summaryrefslogtreecommitdiffstats
path: root/private/nw/vwipxspx/dll
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/nw/vwipxspx/dll
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/nw/vwipxspx/dll')
-rw-r--r--private/nw/vwipxspx/dll/makefile6
-rw-r--r--private/nw/vwipxspx/dll/socket.c2309
-rw-r--r--private/nw/vwipxspx/dll/socket.h318
-rw-r--r--private/nw/vwipxspx/dll/sources64
-rw-r--r--private/nw/vwipxspx/dll/util.c2966
-rw-r--r--private/nw/vwipxspx/dll/util.h233
-rw-r--r--private/nw/vwipxspx/dll/vw.h57
-rw-r--r--private/nw/vwipxspx/dll/vwasync.c167
-rw-r--r--private/nw/vwipxspx/dll/vwasync.h27
-rw-r--r--private/nw/vwipxspx/dll/vwdebug.c825
-rw-r--r--private/nw/vwipxspx/dll/vwdebug.h184
-rw-r--r--private/nw/vwipxspx/dll/vwdll.c502
-rw-r--r--private/nw/vwipxspx/dll/vwdll.h27
-rw-r--r--private/nw/vwipxspx/dll/vwdos.c1502
-rw-r--r--private/nw/vwipxspx/dll/vwinapi.c1185
-rw-r--r--private/nw/vwipxspx/dll/vwinapi.h186
-rw-r--r--private/nw/vwipxspx/dll/vwint.h146
-rw-r--r--private/nw/vwipxspx/dll/vwipx.c839
-rw-r--r--private/nw/vwipxspx/dll/vwipx.h122
-rw-r--r--private/nw/vwipxspx/dll/vwipxspx.def64
-rw-r--r--private/nw/vwipxspx/dll/vwipxspx.h586
-rw-r--r--private/nw/vwipxspx/dll/vwipxspx.rc11
-rw-r--r--private/nw/vwipxspx/dll/vwmisc.c74
-rw-r--r--private/nw/vwipxspx/dll/vwmisc.h27
-rw-r--r--private/nw/vwipxspx/dll/vwspx.c1339
-rw-r--r--private/nw/vwipxspx/dll/vwspx.h62
-rw-r--r--private/nw/vwipxspx/dll/vwvdm.h151
27 files changed, 13979 insertions, 0 deletions
diff --git a/private/nw/vwipxspx/dll/makefile b/private/nw/vwipxspx/dll/makefile
new file mode 100644
index 000000000..f0db8e4a7
--- /dev/null
+++ b/private/nw/vwipxspx/dll/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS LINE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/nw/vwipxspx/dll/socket.c b/private/nw/vwipxspx/dll/socket.c
new file mode 100644
index 000000000..874d4691f
--- /dev/null
+++ b/private/nw/vwipxspx/dll/socket.c
@@ -0,0 +1,2309 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ socket.c
+
+Abstract:
+
+ Contains functions to create, delete and manipulate IPX sockets and SPX
+ connections
+
+ Contents:
+ CreateSocket
+ AllocateTemporarySocket
+ QueueSocket
+ DequeueSocket
+ FindSocket
+ FindActiveSocket
+ ReopenSocket
+ KillSocket
+ KillShortLivedSockets
+ AllocateConnection
+ DeallocateConnection
+ FindConnection
+ QueueConnection
+ DequeueConnection
+ KillConnection
+ AbortOrTerminateConnection
+ CheckPendingSpxRequests
+ (CheckSocketState)
+ (CheckSelectRead)
+ (CheckSelectWrite)
+ (AsyncReadAction)
+ (AsyncWriteAction)
+ (CompleteAccept)
+ (CompleteReceive)
+ (CompleteConnect)
+ (CompleteSend)
+
+Author:
+
+ Richard L Firth (rfirth) 25-Oct-1993
+
+Environment:
+
+ User-mode Win32
+
+Revision History:
+
+ 25-Oct-1993 rfirth
+ Created
+
+--*/
+
+#include "vw.h"
+#pragma hdrstop
+
+//
+// miscellaneous manifests
+//
+
+#define ARBITRARY_CONNECTION_INCREMENT 2
+
+//
+// macros
+//
+
+#define ALLOCATE_CONNECTION_NUMBER() (ConnectionNumber += ARBITRARY_CONNECTION_INCREMENT)
+
+//
+// private data
+//
+
+PRIVATE LPSOCKET_INFO SocketList = NULL;
+PRIVATE LPCONNECTION_INFO ConnectionList = NULL;
+PRIVATE WORD ConnectionNumber = ARBITRARY_CONNECTION_NUMBER;
+
+//
+// private functions
+//
+
+PRIVATE
+BOOL
+CheckSocketState(
+ IN SOCKET Socket,
+ OUT LPBOOL Readable,
+ OUT LPBOOL Writeable,
+ OUT LPBOOL Error
+ );
+
+
+PRIVATE
+VOID
+CheckSelectRead(
+ IN LPSOCKET_INFO pSocketInfo,
+ IN LPCONNECTION_INFO pConnectionInfo,
+ OUT BOOL *CheckRead
+ );
+
+PRIVATE
+VOID
+CheckSelectWrite(
+ IN LPSOCKET_INFO pSocketInfo,
+ IN LPCONNECTION_INFO pConnectionInfo,
+ OUT BOOL *CheckWrite
+ );
+
+PRIVATE
+VOID
+AsyncReadAction(
+ IN LPSOCKET_INFO pSocketInfo,
+ IN LPCONNECTION_INFO pConnectionInfo,
+ OUT BOOL *ReadPerformed
+ );
+
+PRIVATE
+VOID
+AsyncWriteAction(
+ IN LPSOCKET_INFO pSocketInfo,
+ IN LPCONNECTION_INFO pConnectionInfo,
+ OUT BOOL *WritePerformed
+ );
+
+PRIVATE
+VOID
+CompleteAccept(
+ IN LPSOCKET_INFO pSocketInfo,
+ IN LPCONNECTION_INFO pConnectionInfo
+ );
+
+PRIVATE
+VOID
+CompleteReceive(
+ IN LPSOCKET_INFO pSocketInfo,
+ IN LPCONNECTION_INFO pConnectionInfo
+ );
+
+PRIVATE
+VOID
+CompleteConnect(
+ IN LPSOCKET_INFO pSocketInfo,
+ IN LPCONNECTION_INFO pConnectionInfo
+ );
+
+PRIVATE
+VOID
+CompleteSend(
+ IN LPSOCKET_INFO pSocketInfo,
+ IN LPCONNECTION_INFO pConnectionInfo
+ );
+
+#if SPX_HACK
+PRIVATE VOID ModifyFirstReceive(LPBYTE, LPDWORD, WORD, SOCKET);
+#endif
+
+//
+// public functions
+//
+
+
+int
+CreateSocket(
+ IN SOCKET_TYPE SocketType,
+ IN OUT ULPWORD pSocketNumber,
+ OUT SOCKET* pSocket
+ )
+
+/*++
+
+Routine Description:
+
+ Creates a socket for IPX or SPX (a connection). Once the socket is created
+ we have to bind it to the IPX/SPX 'socket' - i.e. port. We also need to
+ change a few things about the standard socket:
+
+ * if this is an SPX request then we must set the REUSEADDR socket option
+ since there may typically be several connect requests over the same
+ WinSock socket: we need to be able to bind multiple connections to the
+ same socket number
+
+ * all sockets opened by this function are put into non-blocking mode
+ * all sockets opened by this function will return the packet header in
+ any received data (IPX_RECVHDR)
+
+ The requested socket number can be 0 in which case we bind to a dynamic
+ socket number. We always return the number of the socket bound to: if not 0
+ on input, this should always be the same value as that requested in
+ pSocketNumber
+
+ If any WinSock call fails (and the socket was created) then we close the
+ socket before returning
+
+Arguments:
+
+ SocketType - SOCKET_TYPE_IPX or SOCKET_TYPE_SPX
+ pSocketNumber - input: socket number to bind (can be 0)
+ output: socket number bound
+ pSocket - pointer to address of socket identifier to return
+
+Return Value:
+
+ int
+ Success - IPX_SUCCESS/SPX_SUCCESS (0)
+
+ Failure - IPX_SOCKET_TABLE_FULL
+ WinSock cannot create the socket
+
+ IPX_SOCKET_ALREADY_OPEN
+ Assume the request was for an IPX socket: we do not allow
+ multiple IPX sockets to be bound to the same socket number,
+ only SPX
+
+
+--*/
+
+{
+ SOCKET s;
+ SOCKADDR_IPX socketAddress;
+ BOOL true = TRUE;
+ int rc;
+ int status = IPX_SOCKET_TABLE_FULL; // default error
+
+ s = socket(AF_IPX,
+ (SocketType == SOCKET_TYPE_SPX) ? SOCK_SEQPACKET : SOCK_DGRAM,
+ (SocketType == SOCKET_TYPE_SPX) ? NSPROTO_SPX : NSPROTO_IPX
+ );
+
+ if (s != INVALID_SOCKET) {
+
+ //
+ // for stream (SPX) sockets, we need multiple sockets bound to the
+ // same socket number if we are to have multiple connections on the
+ // same SPX socket
+ //
+
+ if (SocketType == SOCKET_TYPE_SPX) {
+ rc = setsockopt(s,
+ SOL_SOCKET,
+ SO_REUSEADDR,
+ (char FAR*)&true,
+ sizeof(true)
+ );
+ if (rc == SOCKET_ERROR) {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_ERROR,
+ "CreateSocket: setsockopt(SO_REUSEADDR) returns %d\n",
+ WSAGetLastError()
+ ));
+
+ } else {
+ rc = setsockopt(s,
+ SOL_SOCKET,
+ SO_OOBINLINE,
+ (char FAR*)&true,
+ sizeof(true)
+ );
+
+ if (rc == SOCKET_ERROR) {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_ERROR,
+ "CreateSocket: setsockopt(SO_OOBINLINE) returns %d\n",
+ WSAGetLastError()
+ ));
+
+ }
+ }
+ } else {
+
+ //
+ // allow broadcasts to be transmitted on IPX sockets
+ //
+
+ rc = setsockopt(s,
+ SOL_SOCKET,
+ SO_BROADCAST,
+ (char FAR*)&true,
+ sizeof(true)
+ );
+ }
+ if (!rc) {
+
+ //
+ // bind the socket to the local socket number (port)
+ //
+
+ ZeroMemory(&socketAddress, sizeof(socketAddress));
+ socketAddress.sa_family = AF_IPX;
+ socketAddress.sa_socket = *pSocketNumber;
+ rc = bind(s, (LPSOCKADDR)&socketAddress, sizeof(socketAddress));
+ if (rc != SOCKET_ERROR) {
+
+ int length = sizeof(socketAddress);
+
+ ZeroMemory(&socketAddress, sizeof(socketAddress));
+ socketAddress.sa_family = AF_IPX;
+
+ //
+ // use getsockname() to find the (big-endian) socket value that
+ // was actually assigned: should only be different from
+ // *pSocketNumber if the latter was 0 on input
+ //
+
+ rc = getsockname(s, (LPSOCKADDR)&socketAddress, &length);
+ if (rc != SOCKET_ERROR) {
+
+ u_long arg = !0;
+
+ //
+ // put the socket into non-blocking mode. Neither IPX nor
+ // SPX sockets are blocking: the app starts an I/O request
+ // and if it doesn't complete immediately, will be completed
+ // by AES which periodically polls the outstanding I/O
+ // requests
+ //
+
+ rc = ioctlsocket(s, FIONBIO, &arg);
+ if (rc != SOCKET_ERROR) {
+
+ //
+ // return protocol header on receive frames
+ //
+
+ rc = setsockopt(s,
+ NSPROTO_IPX,
+ IPX_RECVHDR,
+ (char FAR*)&true,
+ sizeof(true)
+ );
+ if (rc != SOCKET_ERROR) {
+ *pSocketNumber = socketAddress.sa_socket;
+ *pSocket = s;
+ status = IPX_SUCCESS;
+ } else {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_ERROR,
+ "CreateSocket: setsockopt(RECVHDR) returns %d\n",
+ WSAGetLastError()
+ ));
+
+ }
+ } else {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_ERROR,
+ "CreateSocket: ioctlsocket(FIONBIO) returns %d\n",
+ WSAGetLastError()
+ ));
+
+ }
+ } else {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_ERROR,
+ "CreateSocket: getsockname() returns %d\n",
+ WSAGetLastError()
+ ));
+
+ }
+ } else {
+
+ //
+ // bind() failed - either an expected error (the requested socket
+ // is already in use), or (horror) an unexpected error, in which
+ // case report table full (?)
+ //
+
+ switch (WSAGetLastError()) {
+ case WSAEADDRINUSE:
+
+ ASSERT(*pSocketNumber != 0);
+ ASSERT(SocketType == SOCKET_TYPE_IPX);
+
+ status = IPX_SOCKET_ALREADY_OPEN;
+ break;
+
+ default:
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_ERROR,
+ "CreateSocket: bind() on socket %#x returns %d\n",
+ s,
+ WSAGetLastError()
+ ));
+
+ }
+ }
+ }
+ } else {
+
+ //
+ // the socket() call failed - treat as table full
+ //
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_ERROR,
+ "CreateSocket: socket() returns %d\n",
+ WSAGetLastError()
+ ));
+
+ }
+ if (status != IPX_SUCCESS) {
+ if (s != INVALID_SOCKET) {
+ closesocket(s);
+ }
+ }
+ return status;
+}
+
+
+LPSOCKET_INFO
+AllocateTemporarySocket(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Allocates a temporary socket. Creates an IPX socket having a dynamically
+ allocated socket number
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ LPSOCKET_INFO
+ Success - pointer to SOCKET_INFO structure
+ Failure - NULL
+
+--*/
+
+{
+ LPSOCKET_INFO pSocketInfo;
+ int rc;
+
+ pSocketInfo = AllocateSocket();
+ if (pSocketInfo) {
+
+ //
+ // assumption: the SOCKET_INFO structure was zeroed by LocalAlloc(LPTR,..
+ // hence the SocketNumber fields is 0. This causes CreateSocket to
+ // generate a dynamic socket number
+ //
+
+ rc = CreateSocket(SOCKET_TYPE_IPX,
+ &pSocketInfo->SocketNumber,
+ &pSocketInfo->Socket
+ );
+ if (rc == IPX_SUCCESS) {
+ pSocketInfo->Flags |= SOCKET_FLAG_TEMPORARY;
+ } else {
+ DeallocateSocket(pSocketInfo);
+ pSocketInfo = NULL;
+ }
+ }
+ return pSocketInfo;
+}
+
+
+VOID
+QueueSocket(
+ IN LPSOCKET_INFO pSocketInfo
+ )
+
+/*++
+
+Routine Description:
+
+ Add a SOCKET_INFO structure to the list (LIFO) of (opened) sockets
+
+Arguments:
+
+ pSocketInfo - pointer to filled-in SOCKET_INFO structure
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ RequestMutex();
+ pSocketInfo->Next = SocketList;
+ SocketList = pSocketInfo;
+ ReleaseMutex();
+}
+
+
+LPSOCKET_INFO
+DequeueSocket(
+ IN LPSOCKET_INFO pSocketInfo
+ )
+
+/*++
+
+Routine Description:
+
+ Remove a SOCKET_INFO structure from the list
+
+Arguments:
+
+ pSocketInfo - pointer to SOCKET_INFO structure to remove
+
+Return Value:
+
+ LPSOCKET_INFO
+ pSocketInfo - should be this value
+ NULL - couldn't find pSocketInfo (should not get this!)
+
+--*/
+
+{
+ LPSOCKET_INFO prev, p;
+
+ ASSERT(SocketList);
+
+ RequestMutex();
+ prev = (LPSOCKET_INFO)&SocketList;
+ p = SocketList;
+ while (p) {
+ if (p == pSocketInfo) {
+ prev->Next = p->Next;
+ p->Next = NULL;
+ break;
+ } else {
+ prev = p;
+ p = p->Next;
+ }
+ }
+
+ if (!p) {
+
+ //
+ // should never reach here
+ //
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_FATAL,
+ "DequeueSocket: can't find socket structure %08x on queue\n",
+ pSocketInfo
+ ));
+
+ }
+
+ ReleaseMutex();
+ return p;
+}
+
+
+LPSOCKET_INFO
+FindSocket(
+ IN WORD SocketNumber
+ )
+
+/*++
+
+Routine Description:
+
+ Locate a SOCKET_INFO structure in the list, by (big-endian) socket number
+
+ Assumes: 1. There is 1 and only 1 SOCKET_INFO structure that contains
+ SocketNumber
+
+Arguments:
+
+ SocketNumber - big-endian socket number to find
+
+Return Value:
+
+ LPSOCKET_INFO
+ NULL - couldn't find requested socket
+ !NULL - pointer to discovered SOCKET_INFO structure
+
+--*/
+
+{
+ LPSOCKET_INFO p;
+
+ RequestMutex();
+ p = SocketList;
+ while (p) {
+ if (p->SocketNumber == SocketNumber) {
+ break;
+ } else {
+ p = p->Next;
+ }
+ }
+ ReleaseMutex();
+ return p;
+}
+
+
+LPSOCKET_INFO
+FindActiveSocket(
+ IN LPSOCKET_INFO pSocketInfo
+ )
+
+/*++
+
+Routine Description:
+
+ Find a SOCKET_INFO structure with pending send or receive. Called as FindFirst,
+ FindNext - first call made with pSocketInfo == NULL: enters critical section
+ if an active socket is found, returns pointer
+
+ Subsequent calls are made with pSocketInfo pointing to last returned
+ SOCKET_INFO. This continues the search. When search exhausted, critical
+ section is released
+
+Arguments:
+
+ pSocketInfo - pointer to SOCKET_INFO structure: first time must be NULL
+
+Return Value:
+
+ LPSOCKET_INFO - next active SOCKET_INFO structure or NULL
+
+--*/
+
+{
+ if (!pSocketInfo) {
+ RequestMutex();
+ pSocketInfo = SocketList;
+ } else {
+ pSocketInfo = pSocketInfo->Next;
+ }
+ for (; pSocketInfo; pSocketInfo = pSocketInfo->Next) {
+ if (pSocketInfo->Flags & (SOCKET_FLAG_SENDING | SOCKET_FLAG_LISTENING)) {
+ return pSocketInfo;
+ }
+ }
+ ReleaseMutex();
+ return NULL;
+}
+
+
+int
+ReopenSocket(
+ LPSOCKET_INFO pSocketInfo
+ )
+
+/*++
+
+Routine Description:
+
+ Called expressly to close an IPX socket and reassign the descriptor to SPX.
+ Note that after this function completes, IPXSendPacket and IPXListenForPacket
+ cannot be made agains the IPX socket
+
+Arguments:
+
+ pSocketInfo - pointer to SOCKET_INFO which currently describes an IPX socket
+
+Return Value:
+
+ int - return code from CreateSocket
+
+--*/
+
+{
+ int rc;
+
+ rc = closesocket(pSocketInfo->Socket);
+ if (rc == SOCKET_ERROR) {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_ERROR,
+ "ReopenSocket: closesocket() returns %d\n",
+ WSAGetLastError()
+ ));
+
+ }
+
+ //
+ // mark this socket as connection-based (SPX) socket
+ //
+
+ pSocketInfo->SpxSocket = TRUE;
+
+ //
+ // BUGBUG: need the DOS/Windows task ID: owner may have changed!
+ //
+
+ //
+ // re-open the socket for SPX use
+ //
+
+ return CreateSocket(SOCKET_TYPE_SPX,
+ &pSocketInfo->SocketNumber,
+ &pSocketInfo->Socket
+ );
+}
+
+
+VOID
+KillSocket(
+ IN LPSOCKET_INFO pSocketInfo
+ )
+
+/*++
+
+Routine Description:
+
+ closes a socket, removes the SOCKET_INFO structure from the list and cancels
+ any pending send, listen or timed events associated with the socket
+
+Arguments:
+
+ pSocketInfo - identifying socket to kill
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ int rc;
+
+ //
+ // remove the SOCKET_INFO structure from the list of sockets. Cancel
+ // any pending ECB requests and any IPX timed events that have the
+ // same socket number
+ //
+
+ DequeueSocket(pSocketInfo);
+ rc = closesocket(pSocketInfo->Socket);
+ if (rc == SOCKET_ERROR) {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_ERROR,
+ "KillSocket: closesocket() returns %d\n",
+ WSAGetLastError()
+ ));
+
+ }
+
+ //
+ // the socket has been removed from SocketList: no need to grab mutex to
+ // perform the following
+ //
+
+ CancelTimedEvents(pSocketInfo->SocketNumber, 0, 0);
+ CancelSocketQueue(&pSocketInfo->ListenQueue);
+ CancelSocketQueue(&pSocketInfo->HeaderQueue);
+ CancelSocketQueue(&pSocketInfo->SendQueue);
+ if (pSocketInfo->SpxSocket) {
+
+ LPCONNECTION_INFO pConnectionInfo;
+
+ while (pConnectionInfo = pSocketInfo->Connections) {
+ DequeueConnection(pSocketInfo, pConnectionInfo);
+ KillConnection(pConnectionInfo);
+ }
+ }
+ DeallocateSocket(pSocketInfo);
+}
+
+
+VOID
+KillShortLivedSockets(
+ IN WORD Owner
+ )
+
+/*++
+
+Routine Description:
+
+ For all those sockets created by a DOS process as SHORT_LIVED, terminate
+ the sockets, cancelling any outstanding ECBs
+
+Arguments:
+
+ Owner - DOS PDB which opened sockets
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LPSOCKET_INFO pSocketInfo;
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_INFO,
+ "KillShortLivedSockets(%04x)\n",
+ Owner
+ ));
+
+ RequestMutex();
+
+ //
+ // kill any non-socket (AES) timed events owned by this DOS process
+ //
+
+ CancelTimedEvents(0, Owner, 0);
+
+ //
+ // kill all sockets owned by this PDB
+ //
+
+ pSocketInfo = SocketList;
+ while (pSocketInfo) {
+
+ LPSOCKET_INFO next;
+
+ next = pSocketInfo->Next;
+ if (!pSocketInfo->LongLived && (pSocketInfo->Owner == Owner)) {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_INFO,
+ "KillShortLivedSockets: Socket %04x owned by %04x\n",
+ B2LW(pSocketInfo->SocketNumber),
+ pSocketInfo->Owner
+ ));
+
+ KillSocket(pSocketInfo);
+ }
+ pSocketInfo = next;
+ }
+ ReleaseMutex();
+}
+
+
+LPCONNECTION_INFO
+AllocateConnection(
+ LPSOCKET_INFO pSocketInfo
+ )
+
+/*++
+
+Routine Description:
+
+ Allocates a CONNECTION_INFO structure. If successful, links it at the head
+ of ConnectionList
+
+Arguments:
+
+ pSocketInfo - pointer to owner SOCKET_INFO
+
+Return Value:
+
+ LPCONNECTION_INFO
+ Success - !NULL
+ Failure - NULL
+
+--*/
+
+{
+ LPCONNECTION_INFO pConnectionInfo;
+
+ pConnectionInfo = (LPCONNECTION_INFO)LocalAlloc(LPTR, sizeof(*pConnectionInfo));
+ if (pConnectionInfo) {
+ RequestMutex();
+ pConnectionInfo->ConnectionId = ALLOCATE_CONNECTION_NUMBER();
+ pConnectionInfo->List = ConnectionList;
+ ConnectionList = pConnectionInfo;
+ ReleaseMutex();
+ }
+
+#if SPX_HACK
+ pConnectionInfo->Flags = CF_1ST_RECEIVE;
+#endif
+
+ return pConnectionInfo;
+}
+
+
+VOID
+DeallocateConnection(
+ IN LPCONNECTION_INFO pConnectionInfo
+ )
+
+/*++
+
+Routine Description:
+
+ Undoes the work of AllocateConnection - removes pConnectionInfo from
+ ConnectionList and deallocates the structure
+
+Arguments:
+
+ pConnectionInfo - pointer to CONNECTION_INFO to deallocate
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LPCONNECTION_INFO p;
+ LPCONNECTION_INFO prev = (LPCONNECTION_INFO)&ConnectionList;
+
+ RequestMutex();
+ for (p = ConnectionList; p != pConnectionInfo; ) {
+ prev = p;
+ p = p->List;
+ }
+
+ //
+ // if p is NULL or differs from pConnectionInfo then there's a problem
+ //
+
+ ASSERT(p);
+
+ //
+ // special case if pConnectionInfo is first on list: can't say
+ // &ConnectionList->List - accesses one pointer beyond ConnectionList
+ // which is WRONG
+ //
+
+ if (prev == (LPCONNECTION_INFO)&ConnectionList) {
+ ConnectionList = p->List;
+ } else {
+ prev->List = p->List;
+ }
+ FREE_OBJECT(pConnectionInfo);
+ ReleaseMutex();
+}
+
+
+LPCONNECTION_INFO
+FindConnection(
+ IN WORD ConnectionId
+ )
+
+/*++
+
+Routine Description:
+
+ Returns a pointer to CONNECTION_INFO given a unique connection ID
+
+Arguments:
+
+ ConnectionId - value to find
+
+Return Value:
+
+ LPCONNECTION_INFO
+ Success - !NULL
+ Failure - NULL
+
+--*/
+
+{
+ LPCONNECTION_INFO pConnectionInfo;
+
+ RequestMutex();
+ for (pConnectionInfo = ConnectionList; pConnectionInfo; ) {
+ if (pConnectionInfo->ConnectionId == ConnectionId) {
+ break;
+ } else {
+ pConnectionInfo = pConnectionInfo->List;
+ }
+ }
+ ReleaseMutex();
+ return pConnectionInfo;
+}
+
+
+VOID
+QueueConnection(
+ IN LPSOCKET_INFO pSocketInfo,
+ IN LPCONNECTION_INFO pConnectionInfo
+ )
+
+/*++
+
+Routine Description:
+
+ Adds a CONNECTION_INFO to the list of connections owned by a SOCKET_INFO.
+ Points the CONNECTION_INFO back to the SOCKET_INFO
+
+Arguments:
+
+ pSocketInfo - owning SOCKET_INFO
+ pConnectionInfo - CONNECTION_INFO to add
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ pConnectionInfo->Next = pSocketInfo->Connections;
+ pSocketInfo->Connections = pConnectionInfo;
+ pConnectionInfo->OwningSocket = pSocketInfo;
+}
+
+
+LPCONNECTION_INFO
+DequeueConnection(
+ IN LPSOCKET_INFO pSocketInfo,
+ IN LPCONNECTION_INFO pConnectionInfo
+ )
+
+/*++
+
+Routine Description:
+
+ Removes a CONNECTION_INFO from the list of connections owned by a SOCKET_INFO
+
+Arguments:
+
+ pSocketInfo - owning SOCKET_INFO
+ pConnectionInfo - CONNECTION_INFO to remove
+
+Return Value:
+
+ LPCONNECTION_INFO
+ Success - pointer to removed CONNECTION_INFO (should be same as
+ pConnectionInfo)
+ Failure - NULL (not expected)
+
+--*/
+
+{
+ LPCONNECTION_INFO prev = (LPCONNECTION_INFO)&pSocketInfo->Connections;
+ LPCONNECTION_INFO p = prev->Next;
+
+ while (p && p != pConnectionInfo) {
+ prev = p;
+ p = p->Next;
+ }
+
+ ASSERT(p == pConnectionInfo);
+
+ prev->Next = p->Next;
+ p->OwningSocket = NULL;
+ return p;
+}
+
+
+VOID
+KillConnection(
+ IN LPCONNECTION_INFO pConnectionInfo
+ )
+
+/*++
+
+Routine Description:
+
+ Closes a socket belonging to a connection and cancels all outstanding
+ requests. The CONNECTION_INFO is deallocated
+
+Arguments:
+
+ pConnectionInfo - pointer to CONNECTION_INFO to kill
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ if (pConnectionInfo->Socket) {
+ closesocket(pConnectionInfo->Socket);
+ }
+ CancelConnectionQueue(&pConnectionInfo->ConnectQueue);
+ CancelConnectionQueue(&pConnectionInfo->AcceptQueue);
+ CancelConnectionQueue(&pConnectionInfo->ListenQueue);
+ CancelConnectionQueue(&pConnectionInfo->SendQueue);
+ DeallocateConnection(pConnectionInfo);
+}
+
+
+VOID
+AbortOrTerminateConnection(
+ IN LPCONNECTION_INFO pConnectionInfo,
+ IN BYTE CompletionCode
+ )
+
+/*++
+
+Routine Description:
+
+ Aborts or terminates a connection: closes the socket, dequeues and completes
+ all outstanding ECBs with relevant code and deallocates the CONNECTION_INFO
+ structure
+
+ The CONNECTION_INFO must NOT be queued on a SOCKET_INFO when this routine
+ is called
+
+Arguments:
+
+ pConnectionInfo - pointer to CONNECTION_INFO to kill
+ CompletionCode - completion code to put in pending ECBs
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ if (pConnectionInfo->Socket) {
+ closesocket(pConnectionInfo->Socket);
+ }
+ AbortQueue(&pConnectionInfo->ConnectQueue, CompletionCode);
+ AbortQueue(&pConnectionInfo->AcceptQueue, CompletionCode);
+ AbortQueue(&pConnectionInfo->ListenQueue, CompletionCode);
+ AbortQueue(&pConnectionInfo->SendQueue, CompletionCode);
+ DeallocateConnection(pConnectionInfo);
+}
+
+
+VOID
+CheckPendingSpxRequests(
+ BOOL *pfOperationPerformed
+ )
+
+/*++
+
+Routine Description:
+
+ Checks the open non-blocking SPX sockets for:
+
+ errors
+ outgoing established connections (connect)
+ incoming established connections (listen/accept)
+ data to receive (recv)
+ send completions (send)
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LPSOCKET_INFO pSocketInfo;
+
+ *pfOperationPerformed = FALSE ;
+
+ RequestMutex();
+ pSocketInfo = SocketList;
+ while (pSocketInfo) {
+ if (pSocketInfo->SpxSocket) {
+
+ LPCONNECTION_INFO pConnectionInfo;
+
+ pConnectionInfo = pSocketInfo->Connections;
+ while (pConnectionInfo) {
+
+ LPCONNECTION_INFO next;
+
+ //
+ // pluck out the Next field now, in case this CONNECTION_INFO
+ // is destroyed as the result of an error
+ //
+
+ next = pConnectionInfo->Next;
+
+ //
+ // if this connection has an active socket or we have issued
+ // SPXListenForConnection against the socket then check the
+ // state
+ //
+
+ if (pConnectionInfo->Socket
+ || (pConnectionInfo->State == CI_WAITING)) {
+
+ SOCKET sock;
+ BOOL readable;
+ BOOL writeable;
+ BOOL sockError;
+
+ CheckSelectRead(pSocketInfo,
+ pConnectionInfo,
+ &readable);
+
+ CheckSelectWrite(pSocketInfo,
+ pConnectionInfo,
+ &writeable);
+
+ sock = pConnectionInfo->Socket
+ ? pConnectionInfo->Socket
+ : pSocketInfo->Socket
+ ;
+
+ if (CheckSocketState(sock, &readable, &writeable, &sockError)) {
+ if (!sockError) {
+
+ if (readable) {
+ AsyncReadAction(pSocketInfo,
+ pConnectionInfo,
+ pfOperationPerformed);
+ }
+ if (writeable) {
+ AsyncWriteAction(pSocketInfo,
+ pConnectionInfo,
+ pfOperationPerformed);
+ }
+ } else {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_ERROR,
+ "CheckPendingSpxRequests: socket %x has error. Connection %08x state %d\n",
+ sock,
+ pConnectionInfo,
+ pConnectionInfo->State
+ ));
+
+ //
+ // irrespective of the error, we just abort any
+ // connection that gets an error
+ //
+
+ DequeueConnection(pConnectionInfo->OwningSocket,
+ pConnectionInfo
+ );
+ AbortOrTerminateConnection(pConnectionInfo,
+ ECB_CC_CONNECTION_ABORTED
+ );
+ }
+ } else {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_ERROR,
+ "CheckPendingSpxRequests: CheckSocketState returns %d\n",
+ WSAGetLastError()
+ ));
+
+ }
+ } else {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_ERROR,
+ "CheckPendingSpxRequests: connection %04x (%08x) in weird state?\n",
+ pConnectionInfo->ConnectionId,
+ pConnectionInfo
+ ));
+
+ }
+ pConnectionInfo = next;
+ }
+ }
+ pSocketInfo = pSocketInfo->Next;
+ }
+ ReleaseMutex();
+}
+
+
+PRIVATE
+BOOL
+CheckSocketState(
+ IN SOCKET Socket,
+ OUT LPBOOL Readable,
+ OUT LPBOOL Writeable,
+ OUT LPBOOL Error
+ )
+
+/*++
+
+Routine Description:
+
+ Given a socket descriptor, checks to see if it is in one of the following
+ states:
+
+ readable - if waiting for a connection, connection has been made
+ else if established, data is ready to be received
+
+ writeable - if waiting to make a connection, connection has been
+ made, else if established, we can send data on this
+ socket
+
+ error - some error has occurred on the socket
+
+Arguments:
+
+ Socket - socket descriptor to check
+ Readable - returned TRUE if readable
+ Writeable - returned TRUE if writeable
+ Error - returned TRUE if error on socket
+
+Return Value:
+
+ BOOL
+ TRUE - contents of Readable, Writeable and Error are valid
+ FALSE - an error occurred performing the select
+
+--*/
+
+{
+ fd_set errors;
+ fd_set reads;
+ fd_set writes;
+ int n;
+ static struct timeval timeout = {0, 0};
+
+ FD_ZERO(&errors);
+ FD_ZERO(&reads);
+ FD_ZERO(&writes);
+
+ if (*Readable)
+ FD_SET(Socket, &reads);
+ if (*Writeable)
+ FD_SET(Socket, &writes);
+ FD_SET(Socket, &errors);
+
+ n = select(0, &reads, &writes, &errors, &timeout);
+
+ if (n != SOCKET_ERROR) {
+ *Readable = (BOOL)(reads.fd_count == 1);
+ *Writeable = (BOOL)(writes.fd_count == 1);
+ *Error = (BOOL)(errors.fd_count == 1);
+ return TRUE;
+ } else if (n) {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_INFO,
+ "CheckSocketState: select returns %d\n",
+ WSAGetLastError()
+ ));
+
+ }
+ return FALSE;
+}
+
+
+PRIVATE
+VOID
+AsyncReadAction(
+ IN LPSOCKET_INFO pSocketInfo,
+ IN LPCONNECTION_INFO pConnectionInfo,
+ OUT BOOL *ReadPerformed
+ )
+
+/*++
+
+Routine Description:
+
+ A connection has some read action to complete - complete a pending
+ SPXListenForConnection or SPXListenForSequencedPacket
+
+Arguments:
+
+ pSocketInfo - pointer to SOCKET_INFO
+ pConnectionInfo - pointer to CONNECTION_INFO
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ *ReadPerformed = FALSE ;
+
+ switch (pConnectionInfo->State) {
+ case CI_STARTING:
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_INFO,
+ "AsyncReadAction: STARTING connection %04x (%08x) readable\n",
+ pConnectionInfo->ConnectionId,
+ pConnectionInfo
+ ));
+
+ break;
+
+ case CI_WAITING:
+ if (pConnectionInfo->AcceptQueue.Head) {
+ CompleteAccept(pSocketInfo, pConnectionInfo);
+ *ReadPerformed = TRUE ;
+ } else {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_ERROR,
+ "AsyncReadAction: connection %04x (%08x): no AcceptQueue\n",
+ pConnectionInfo->ConnectionId,
+ pConnectionInfo
+ ));
+
+ }
+ break;
+
+ case CI_ESTABLISHED:
+ if (pSocketInfo->ListenQueue.Head) {
+ CompleteReceive(pSocketInfo, pConnectionInfo);
+ *ReadPerformed = TRUE ;
+ } else {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_WARNING,
+ "AsyncReadAction: connection %04x (%08x): no ListenQueue\n",
+ pConnectionInfo->ConnectionId,
+ pConnectionInfo
+ ));
+
+ }
+ break;
+
+ case CI_TERMINATING:
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_INFO,
+ "AsyncReadAction: TERMINATING connection %04x (%08x) readable\n",
+ pConnectionInfo->ConnectionId,
+ pConnectionInfo
+ ));
+
+ break;
+ }
+}
+
+
+PRIVATE
+VOID
+AsyncWriteAction(
+ IN LPSOCKET_INFO pSocketInfo,
+ IN LPCONNECTION_INFO pConnectionInfo,
+ OUT BOOL *WritePerformed
+ )
+
+/*++
+
+Routine Description:
+
+ A connection has some write action to complete - complete a pending
+ SPXEstablishConnection or SPXSendSequencedPacket
+
+Arguments:
+
+ pSocketInfo - pointer to SOCKET_INFO
+ pConnectionInfo - pointer to CONNECTION_INFO
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ *WritePerformed = FALSE ;
+
+ switch (pConnectionInfo->State) {
+ case CI_STARTING:
+ if (pConnectionInfo->ConnectQueue.Head) {
+ CompleteConnect(pSocketInfo, pConnectionInfo);
+ *WritePerformed = TRUE ;
+ } else {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_ERROR,
+ "AsyncWriteAction: connection %04x (%08x): no ConnectQueue\n",
+ pConnectionInfo->ConnectionId,
+ pConnectionInfo
+ ));
+
+ }
+ break;
+
+ case CI_WAITING:
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_INFO,
+ "AsyncWriteAction: WAITING connection %04x (%08x) is writeable\n",
+ pConnectionInfo->ConnectionId,
+ pConnectionInfo
+ ));
+
+ break;
+
+ case CI_ESTABLISHED:
+ if (pConnectionInfo->SendQueue.Head) {
+ CompleteSend(pSocketInfo, pConnectionInfo);
+ *WritePerformed = TRUE ;
+ } else {
+/*
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_WARNING,
+ "AsyncWriteAction: connection %04x (%08x): no SendQueue\n",
+ pConnectionInfo->ConnectionId,
+ pConnectionInfo
+ ));
+*/
+ }
+ break;
+
+ case CI_TERMINATING:
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_INFO,
+ "AsyncWriteAction: TERMINATING connection %04x (%08x) writeable\n",
+ pConnectionInfo->ConnectionId,
+ pConnectionInfo
+ ));
+
+ break;
+ }
+}
+
+PRIVATE
+VOID
+CheckSelectRead(
+ IN LPSOCKET_INFO pSocketInfo,
+ IN LPCONNECTION_INFO pConnectionInfo,
+ OUT BOOL *CheckRead
+ )
+
+/*++
+
+Routine Description:
+
+ See if want to check for Read readiness in select statement.
+
+Arguments:
+
+ pSocketInfo - pointer to SOCKET_INFO
+ pConnectionInfo - pointer to CONNECTION_INFO
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ *CheckRead = FALSE ;
+
+ switch (pConnectionInfo->State)
+ {
+ case CI_WAITING:
+
+ if (pConnectionInfo->AcceptQueue.Head)
+ *CheckRead = TRUE ;
+ break;
+
+ case CI_ESTABLISHED:
+
+ if (pSocketInfo->ListenQueue.Head)
+ *CheckRead = TRUE ;
+ break;
+
+ default:
+
+ break;
+ }
+}
+
+
+PRIVATE
+VOID
+CheckSelectWrite(
+ IN LPSOCKET_INFO pSocketInfo,
+ IN LPCONNECTION_INFO pConnectionInfo,
+ OUT BOOL *CheckWrite
+ )
+
+/*++
+
+Routine Description:
+
+ See if want to check for Write readiness in select statement.
+
+Arguments:
+
+ pSocketInfo - pointer to SOCKET_INFO
+ pConnectionInfo - pointer to CONNECTION_INFO
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ *CheckWrite = FALSE ;
+
+ switch (pConnectionInfo->State)
+ {
+
+ case CI_STARTING:
+
+ if (pConnectionInfo->ConnectQueue.Head)
+ *CheckWrite = TRUE ;
+ break;
+
+ case CI_ESTABLISHED:
+
+ if (pConnectionInfo->SendQueue.Head)
+ *CheckWrite = TRUE ;
+ break;
+
+ default:
+
+ break;
+ }
+}
+
+
+
+PRIVATE
+VOID
+CompleteAccept(
+ IN LPSOCKET_INFO pSocketInfo,
+ IN LPCONNECTION_INFO pConnectionInfo
+ )
+
+/*++
+
+Routine Description:
+
+ Complete a SPXListenForConnection
+
+Arguments:
+
+ pSocketInfo - pointer to SOCKET_INFO
+ pConnectionInfo - pointer to CONNECTION_INFO
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ SOCKET conn;
+ SOCKADDR_IPX remoteAddress;
+ int addressLength = sizeof(remoteAddress);
+ LPXECB pXecb = pConnectionInfo->AcceptQueue.Head;
+ BOOL true = TRUE;
+ int rc;
+
+ conn = accept(pSocketInfo->Socket, (LPSOCKADDR)&remoteAddress, &addressLength);
+ if (conn != SOCKET_ERROR) {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_INFO,
+ "CompleteAccept: connection %04x (%08x) socket=%x\n",
+ pConnectionInfo->ConnectionId,
+ pConnectionInfo,
+ conn
+ ));
+
+ //
+ // we want to receive the frame headers from this socket
+ //
+
+ rc = setsockopt(conn,
+ NSPROTO_IPX,
+ IPX_RECVHDR,
+ (char FAR*)&true,
+ sizeof(true)
+ );
+ rc = !SOCKET_ERROR;
+ if (rc != SOCKET_ERROR) {
+
+ //
+ // update the CONNECTION_INFO structure with the actual socket
+ // identifier and set the connection state to established
+ //
+
+ pConnectionInfo->Socket = conn;
+ pConnectionInfo->State = CI_ESTABLISHED;
+
+ //
+ // update the app's ECB with the connection ID
+ //
+
+ SPX_ECB_CONNECTION_ID(pXecb->Ecb) = pConnectionInfo->ConnectionId;
+
+ //
+ // and with the partner address info
+ //
+
+ CopyMemory(&pXecb->Ecb->DriverWorkspace,
+ &remoteAddress.sa_netnum,
+ sizeof(pXecb->Ecb->DriverWorkspace)
+ );
+
+ //
+ // fill in the immediate address field
+ //
+
+ CopyMemory(&pXecb->Ecb->ImmediateAddress,
+ &remoteAddress.sa_nodenum,
+ sizeof(pXecb->Ecb->ImmediateAddress)
+ );
+
+ //
+ // remove the XECB from AcceptQueue and complete the SPXListenForConnection ECB
+ //
+
+ DequeueEcb(pXecb, &pConnectionInfo->AcceptQueue);
+
+ IPXDUMPECB((pXecb->Ecb,
+ HIWORD(pXecb->EcbAddress),
+ LOWORD(pXecb->EcbAddress),
+ ECB_TYPE_SPX,
+ FALSE,
+ FALSE,
+ IS_PROT_MODE(pXecb)
+ ));
+
+ CompleteOrQueueEcb(pXecb, ECB_CC_SUCCESS);
+ } else {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_ERROR,
+ "CompleteAccept: setsockopt(IPX_RECVHDR) returns %d\n",
+ WSAGetLastError()
+ ));
+
+ //
+ // BUGBUG: value?
+ //
+
+ closesocket(conn);
+ DequeueEcb(pXecb, &pConnectionInfo->AcceptQueue);
+ DequeueConnection(pSocketInfo, pConnectionInfo);
+ DeallocateConnection(pConnectionInfo);
+ CompleteOrQueueEcb(pXecb, ECB_CC_CONNECTION_ABORTED);
+ }
+ } else {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_ERROR,
+ "CompleteAccept: accept() returns %d\n",
+ WSAGetLastError()
+ ));
+
+ }
+}
+
+
+PRIVATE
+VOID
+CompleteReceive(
+ IN LPSOCKET_INFO pSocketInfo,
+ IN LPCONNECTION_INFO pConnectionInfo
+ )
+
+/*++
+
+Routine Description:
+
+ Complete a SPXListenForSequencedPacket
+
+Arguments:
+
+ pSocketInfo - pointer to SOCKET_INFO
+ pConnectionInfo - pointer to CONNECTION_INFO
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LPXECB pXecb;
+ int rc;
+ BOOL conn_q;
+ LPXECB_QUEUE pQueue;
+ int len;
+ BOOL completeRequest;
+ BYTE status;
+
+ //
+ // receive packets while there are listen ECBs and data waiting
+ //
+
+ while (1) {
+ if (pConnectionInfo->ListenQueue.Head) {
+ pQueue = &pConnectionInfo->ListenQueue;
+ pXecb = pConnectionInfo->ListenQueue.Head;
+ conn_q = TRUE;
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_INFO,
+ "CompleteReceive: XECB %08x from CONNECTION_INFO %08x\n",
+ pXecb,
+ pConnectionInfo
+ ));
+
+
+ } else if (pSocketInfo->ListenQueue.Head) {
+ pQueue = &pSocketInfo->ListenQueue;
+ pXecb = pSocketInfo->ListenQueue.Head;
+ conn_q = FALSE;
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_INFO,
+ "CompleteReceive: XECB %08x from SOCKET_INFO %08x\n",
+ pXecb,
+ pSocketInfo
+ ));
+
+ } else {
+ break;
+ }
+
+ rc = recv(pConnectionInfo->Socket, pXecb->Data, pXecb->Length, 0);
+
+ if (rc != SOCKET_ERROR) {
+
+ len = rc;
+ status = ECB_CC_SUCCESS;
+ completeRequest = TRUE;
+
+ } else {
+ rc = WSAGetLastError();
+ if (rc == WSAEMSGSIZE) {
+ len = pXecb->Length;
+ status = ECB_CC_PACKET_OVERFLOW;
+ completeRequest = TRUE;
+ } else {
+ completeRequest = FALSE;
+
+ //
+ // if no data to receive, quit the loop (don't go down error path)
+ //
+
+ if (rc == WSAEWOULDBLOCK) {
+ break;
+ }
+ }
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_ERROR,
+ "CompleteReceive: error %d on socket %08x (CID %04x)\n",
+ rc,
+ pConnectionInfo->Socket,
+ pConnectionInfo->ConnectionId
+ ));
+
+ DUMPXECB(pXecb);
+
+ }
+
+ if( rc == WSAEDISCON ) {
+
+ //
+ // handle the disconnect case - we still need to complete the
+ // ECB.
+ //
+
+ LPSPX_PACKET pPacket = (LPSPX_PACKET)pXecb->Buffer;
+
+ status = ECB_CC_SUCCESS;
+
+
+ pPacket->DestinationConnectId = pConnectionInfo->ConnectionId;
+ pPacket->SourceConnectId = pConnectionInfo->RemoteConnectionId;
+ pPacket->DataStreamType = SPX_DS_TERMINATE ;
+ pPacket->Checksum = 0xffff;
+ pPacket->Length = L2BW(SPX_HEADER_LENGTH);
+ pPacket->TransportControl = 0;
+ pPacket->PacketType = 5;
+
+ pXecb->Length = SPX_HEADER_LENGTH ;
+ ScatterData(pXecb);
+
+ DequeueEcb(pXecb, pQueue);
+
+ //
+ // Put the remote node address in the ECB's immediate address
+ // field
+ //
+
+ CopyMemory(pXecb->Ecb->ImmediateAddress,
+ pConnectionInfo->RemoteNode,
+ sizeof(pXecb->Ecb->ImmediateAddress)
+ );
+
+ CompleteOrQueueIo(pXecb, status);
+
+ DequeueConnection(pConnectionInfo->OwningSocket, pConnectionInfo);
+ AbortOrTerminateConnection(pConnectionInfo, ECB_CC_CONNECTION_ABORTED);
+ break ;
+
+ }
+ else if (completeRequest) {
+
+#if SPX_HACK
+ if (pConnectionInfo->Flags & CF_1ST_RECEIVE) {
+ pConnectionInfo->Flags &= ~CF_1ST_RECEIVE;
+ ModifyFirstReceive(pXecb->Data, &len, pSocketInfo->SocketNumber, pConnectionInfo->Socket);
+ }
+#endif
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_INFO,
+ "CompleteReceive: recv() on socket %#x returns %d bytes (Addr=%08x)\n",
+ pConnectionInfo->Socket,
+ len,
+ pXecb->Data
+ ));
+
+ IPXDUMPDATA((pXecb->Data, 0, 0, FALSE, (WORD)len));
+
+ pXecb->Length -= len;
+ pXecb->ActualLength += len;
+ pXecb->Data += len;
+ if (pXecb->ActualLength >= SPX_HEADER_LENGTH) {
+ if (pXecb->Flags & XECB_FLAG_FIRST_RECEIVE) {
+
+ LPSPX_PACKET pPacket = (LPSPX_PACKET)pXecb->Buffer;
+
+ //
+ // record in the SPX header the local connection id we invented
+ //
+
+ pPacket->DestinationConnectId = pConnectionInfo->ConnectionId;
+
+ //
+ // record the actual frame length from the header
+ //
+
+ pXecb->FrameLength = B2LW(((LPSPX_PACKET)pXecb->Buffer)->Length);
+ pXecb->Flags &= ~XECB_FLAG_FIRST_RECEIVE;
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_INFO,
+ "CompleteReceive: FrameLength=%x (%d)\n",
+ pXecb->FrameLength,
+ pXecb->FrameLength
+ ));
+
+ }
+
+ //
+ // if we received all the data in the packet (according to length
+ // field in the SPX header) OR we ran out of buffer space, remove
+ // the ECB from its queue and complete it
+ //
+
+ if (!pXecb->Length || (pXecb->ActualLength == pXecb->FrameLength)) {
+ if (pXecb->Flags & XECB_FLAG_BUFFER_ALLOCATED) {
+
+ //
+ // update the XECB.Length field to reflect the amount of
+ // data received and copy it to the fragmented buffers
+ // in VDM. do not overflow buffer if FrameLength turns
+ // out to be larger than we expect.
+ //
+
+ pXecb->Length = min(pXecb->FrameLength,
+ pXecb->ActualLength);
+ ScatterData(pXecb);
+ }
+ DequeueEcb(pXecb, pQueue);
+
+ // DUMPXECB(pXecb);
+
+
+ IPXDUMPECB((pXecb->Ecb,
+ HIWORD(pXecb->EcbAddress),
+ LOWORD(pXecb->EcbAddress),
+ ECB_TYPE_SPX,
+ TRUE,
+ TRUE,
+ IS_PROT_MODE(pXecb)
+ ));
+
+ //
+ // Put the remote node address in the ECB's immediate address
+ // field
+ //
+
+ CopyMemory(pXecb->Ecb->ImmediateAddress,
+ pConnectionInfo->RemoteNode,
+ sizeof(pXecb->Ecb->ImmediateAddress)
+ );
+ CompleteOrQueueIo(pXecb, status);
+ } else {
+
+ //
+ // partial receive. If the listen ECB came off the socket
+ // queue then put it on the connection queue: this is the
+ // ECB that will be used for this connection until all data
+ // received or we get an error
+ //
+
+ if (!conn_q) {
+ DequeueEcb(pXecb, &pSocketInfo->ListenQueue);
+ QueueEcb(pXecb,
+ &pConnectionInfo->ListenQueue,
+ CONNECTION_LISTEN_QUEUE
+ );
+ }
+
+ //
+ // not enough data to satisfy read: don't continue yet
+ //
+
+ break;
+ }
+ }
+ } else {
+
+ //
+ // error occurred - abort the connection
+ //
+
+ if (!conn_q) {
+ DequeueEcb(pXecb, &pSocketInfo->ListenQueue);
+ QueueEcb(pXecb,
+ &pConnectionInfo->ListenQueue,
+ CONNECTION_LISTEN_QUEUE
+ );
+ }
+ DequeueConnection(pConnectionInfo->OwningSocket, pConnectionInfo);
+ AbortOrTerminateConnection(pConnectionInfo, ECB_CC_CONNECTION_ABORTED);
+
+ //
+ // don't continue in this case
+ //
+
+ break;
+ }
+ }
+}
+
+
+PRIVATE
+VOID
+CompleteConnect(
+ IN LPSOCKET_INFO pSocketInfo,
+ IN LPCONNECTION_INFO pConnectionInfo
+ )
+
+/*++
+
+Routine Description:
+
+ Complete a SPXEstablishConnection
+
+Arguments:
+
+ pSocketInfo - pointer to SOCKET_INFO
+ pConnectionInfo - pointer to CONNECTION_INFO
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LPXECB pXecb = pConnectionInfo->ConnectQueue.Head;
+/*
+ LPSPX_PACKET pPacket;
+
+ //
+ // the connection ID also appears in the first segment of the establish
+ // ECB
+ //
+
+ pPacket = (LPSPX_PACKET)GET_FAR_POINTER(&ECB_FRAGMENT(pXecb->Ecb, 0)->Address,
+ IS_PROT_MODE(pXecb)
+ );
+ pPacket->Checksum = 0xffff;
+ pPacket->Length = L2BW(SPX_HEADER_LENGTH);
+ pPacket->TransportControl = 0;
+ pPacket->PacketType = 5;
+ pPacket->Source.Socket = pSocketInfo->SocketNumber;
+ pPacket->ConnectionControl = 0xc0;
+ pPacket->DataStreamType = 0;
+ pPacket->SourceConnectId = pConnectionInfo->ConnectionId;
+ pPacket->DestinationConnectId = 0xffff;
+ pPacket->SequenceNumber = 0;
+ pPacket->AckNumber = 0;
+ pPacket->AllocationNumber = 0;
+*/
+
+ pConnectionInfo->State = CI_ESTABLISHED;
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_INFO,
+ "CompleteConnect: connection %04x (%08x) completed\n",
+ pConnectionInfo->ConnectionId,
+ pConnectionInfo
+ ));
+
+ DUMPCONN(pConnectionInfo);
+
+ DequeueEcb(pXecb, &pConnectionInfo->ConnectQueue);
+
+ IPXDUMPECB((pXecb->Ecb,
+ HIWORD(pXecb->EcbAddress),
+ LOWORD(pXecb->EcbAddress),
+ ECB_TYPE_SPX,
+ TRUE,
+ TRUE,
+ IS_PROT_MODE(pXecb)
+ ));
+
+ CompleteOrQueueEcb(pXecb, ECB_CC_SUCCESS);
+}
+
+
+PRIVATE
+VOID
+CompleteSend(
+ IN LPSOCKET_INFO pSocketInfo,
+ IN LPCONNECTION_INFO pConnectionInfo
+ )
+
+/*++
+
+Routine Description:
+
+ Complete a SPXSendSequencedPacket
+
+Arguments:
+
+ pSocketInfo - pointer to SOCKET_INFO
+ pConnectionInfo - pointer to CONNECTION_INFO
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LPXECB pXecb = pConnectionInfo->SendQueue.Head;
+ int rc;
+ BYTE status;
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_INFO,
+ "CompleteSend: sending %d (0x%x) bytes from %08x\n",
+ pXecb->Length,
+ pXecb->Length,
+ pXecb->Data
+ ));
+
+ IPXDUMPECB((pXecb->Ecb,
+ HIWORD(pXecb->EcbAddress),
+ LOWORD(pXecb->EcbAddress),
+ ECB_TYPE_SPX,
+ TRUE,
+ TRUE,
+ IS_PROT_MODE(pXecb)
+ ));
+
+ rc = send(pConnectionInfo->Socket, pXecb->Data, pXecb->Length, 0);
+ if (rc == pXecb->Length) {
+
+ //
+ // all data sent
+ //
+
+ status = ECB_CC_SUCCESS;
+ } else if (rc == SOCKET_ERROR) {
+ rc = WSAGetLastError();
+ if (rc == WSAEWOULDBLOCK) {
+
+ //
+ // huh???
+ //
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_ERROR,
+ "CompleteSend: send() returns WSAEWOODBLOCK??\n"
+ ));
+
+ //
+ // leave ECB on queue
+ //
+
+ return;
+ } else {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_ERROR,
+ "CompleteSend: send() returns %d\n",
+ rc
+ ));
+
+ //
+ // BUGBUG: abort connection?
+ //
+
+ status = ECB_CC_CONNECTION_ABORTED;
+ }
+ } else {
+
+ //
+ // partial data sent. Update the buffer pointer and length fields
+ // and leave this ECB at the head of the send queue
+ //
+
+ pXecb->Data += rc;
+ pXecb->Length -= (WORD)rc;
+ return;
+ }
+ DequeueEcb(pXecb, &pConnectionInfo->SendQueue);
+ CompleteOrQueueIo(pXecb, status);
+}
+
+#if SPX_HACK
+
+PRIVATE
+VOID
+ModifyFirstReceive(
+ LPBYTE Buffer,
+ LPDWORD pLength,
+ WORD SocketNumber,
+ SOCKET Socket
+ )
+{
+ WORD len = *(LPWORD)pLength;
+
+ if ((*(ULPWORD)Buffer != 0xffff) && (*(ULPWORD)(Buffer+2) != L2BW(len))) {
+
+ LPSPX_PACKET packet;
+ SOCKADDR_IPX remote;
+ int rc;
+ int remlen;
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_INFO,
+ "ModifyFirstReceive: Modifying: Buffer=%08x Length=%04x SocketNumber=%04x Socket=%08x\n",
+ Buffer,
+ len,
+ B2LW(SocketNumber),
+ Socket
+ ));
+
+ MoveMemory(Buffer+42, Buffer, len);
+ packet = (LPSPX_PACKET)Buffer;
+ packet->Checksum = 0xffff;
+ packet->Length = L2BW(42+len);
+ packet->TransportControl = 0;
+ packet->PacketType = 5;
+ CopyMemory((LPVOID)&packet->Destination,
+ (LPVOID)&MyInternetAddress.sa_netnum,
+ sizeof(INTERNET_ADDRESS)
+ );
+ packet->Destination.Socket = SocketNumber;
+ rc = getpeername(Socket, (LPSOCKADDR)&remote, &remlen);
+ if (rc != SOCKET_ERROR) {
+ CopyMemory((LPVOID)&packet->Source,
+ (LPVOID)&remote.sa_netnum,
+ sizeof(NETWARE_ADDRESS)
+ );
+ } else {
+ ZeroMemory((LPVOID)&packet->Source, sizeof(NETWARE_ADDRESS));
+ }
+ packet->ConnectionControl = 0x40;
+ packet->DataStreamType = 0;
+ packet->SourceConnectId = 0;
+ packet->DestinationConnectId = 0;
+ packet->SequenceNumber = 0;
+ packet->AckNumber = 0;
+ packet->AllocationNumber = 0;
+ *pLength += 42;
+ }
+}
+
+#endif
diff --git a/private/nw/vwipxspx/dll/socket.h b/private/nw/vwipxspx/dll/socket.h
new file mode 100644
index 000000000..facf7c6f7
--- /dev/null
+++ b/private/nw/vwipxspx/dll/socket.h
@@ -0,0 +1,318 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ socket.h
+
+Abstract:
+
+ Contains macros, prototypes and structures for socket.c
+
+Author:
+
+ Richard L Firth (rfirth) 25-Oct-1993
+
+Revision History:
+
+ 25-Oct-1993 rfirth
+ Created
+
+--*/
+
+#define ARBITRARY_CONNECTION_NUMBER 0x6c8e
+
+//
+// forward declarations
+//
+
+typedef struct _FIFO *LPFIFO;
+typedef struct _XECB *LPXECB;
+typedef struct _XECB_QUEUE *LPXECB_QUEUE;
+typedef struct _SOCKET_INFO* LPSOCKET_INFO;
+typedef struct _CONNECTION_INFO *LPCONNECTION_INFO;
+
+//
+// FIFO - standard single-linked FIFO queue structure
+//
+
+typedef struct _FIFO {
+ LPVOID Head;
+ LPVOID Tail;
+} FIFO;
+
+//
+// function type for cancelling XECB/ECB
+//
+
+typedef BYTE (*ECB_CANCEL_ROUTINE)(LPXECB);
+
+//
+// QUEUE_ID - indicator of which queue an ECB is on
+//
+
+typedef enum {
+ NO_QUEUE = 0x10cadd1e,
+ ASYNC_COMPLETION_QUEUE = 0xCC5055C0, // arbitrary numbers make life interesting
+ TIMER_QUEUE,
+ SOCKET_LISTEN_QUEUE,
+ SOCKET_SEND_QUEUE,
+ SOCKET_HEADER_QUEUE, // special queue for small ECBs that cannot hold data
+ CONNECTION_CONNECT_QUEUE,
+ CONNECTION_ACCEPT_QUEUE,
+ CONNECTION_SEND_QUEUE,
+ CONNECTION_LISTEN_QUEUE
+} QUEUE_ID;
+
+//
+// XECB - our copy of the ECB (IPX or AES)
+//
+
+typedef struct _XECB {
+ LPXECB Next;
+ LPECB Ecb; // points to ECB in DOS memory
+ ECB_ADDRESS EcbAddress; // segmented address of ECB in DOS memory
+ ESR_ADDRESS EsrAddress; // Event Service Routine in DOS memory
+ LPBYTE Buffer; // address of 32-bit buffer
+ LPBYTE Data; // moveable data pointer
+ WORD FrameLength; // actual size of frame (from IPX/SPX header)
+ WORD ActualLength; // same as FrameLength. Not decremented
+ WORD Length; // length of 32-bit buffer
+ WORD Ticks; // for AES
+ WORD SocketNumber; // number of owning socket
+ WORD Owner; // owning DOS Task ID
+ DWORD TaskId; // owning Windows Task ID
+ DWORD Flags; // see below
+ QUEUE_ID QueueId; // identifies the queue for quick location
+ LPVOID OwningObject; // which SOCKET_INFO or CONNECTION_INFO the queue is on
+ DWORD RefCount; // the dreaded reference count
+} XECB;
+
+//
+// XECB flags
+//
+
+#define XECB_FLAG_AES 0x00000000
+#define XECB_FLAG_IPX 0x00000001
+#define XECB_FLAG_TEMPORARY_SOCKET 0x00000002
+#define XECB_FLAG_BUFFER_ALLOCATED 0x00000004
+#define XECB_FLAG_LISTEN 0x00000008
+#define XECB_FLAG_SEND 0x00000010
+#define XECB_FLAG_TIMER 0x00000020
+#define XECB_FLAG_ASYNC 0x00000040
+#define XECB_FLAG_FIRST_RECEIVE 0x00000080
+#define XECB_FLAG_SPX 0x00000100
+#define XECB_FLAG_PROTMODE 0x00000200
+
+#define IS_PROT_MODE(p) (((p)->Flags & XECB_FLAG_PROTMODE) ? TRUE : FALSE)
+
+//
+// XECB_QUEUE - queue of XECBs
+//
+
+typedef struct _XECB_QUEUE {
+ LPXECB Head;
+ LPXECB Tail;
+} XECB_QUEUE;
+
+//
+// SOCKET_INFO - maintains info about IPX sockets
+//
+
+typedef struct _SOCKET_INFO {
+ LPSOCKET_INFO Next;
+ WORD SocketNumber; // big-endian socket (bound port)
+ WORD Owner; // DOS PDB
+ DWORD TaskId; // Windows owner
+ SOCKET Socket; // the WinSock socket handle
+ DWORD Flags;
+
+ //
+ // BUGBUG: these next 2 fields can be flags
+ //
+
+ BOOL LongLived; // TRUE if keep-alive when app dies
+ BOOL SpxSocket; // TRUE if socket opened for SPX
+
+ //
+ // BUGBUG: these next 2 fields can we WORD or even BYTE (do we even need
+ // them - only used to tell AES if pending requests - it can look at the
+ // queue heads?
+ //
+
+ DWORD PendingSends; // used by cancel
+ DWORD PendingListens; // used by cancel
+
+ //
+ // ListenQueue is used for IPXListenForPacket and SPXListenForSequencedPacket
+ //
+
+ XECB_QUEUE ListenQueue; // pool of listening ECBs against this socket
+
+ //
+ // SendQueue is used by IPX for IPXSendPacket
+ //
+
+ XECB_QUEUE SendQueue; // queue of pending send ECBs against this socket
+
+ //
+ // HeaderQueue is used to hold small ECBs that can only take header info.
+ // We have this separate queue to make sure that we do not put ECBs that
+ // really cant accept any data into the Listen Queue.
+ //
+
+ XECB_QUEUE HeaderQueue; // pool of header ECBs against this socket
+
+ LPCONNECTION_INFO Connections;
+} SOCKET_INFO;
+
+#define SOCKET_FLAG_LISTENING 0x00000001
+#define SOCKET_FLAG_SENDING 0x00000002
+#define SOCKET_FLAG_TEMPORARY 0x80000000
+
+//
+// CONNECTION_INFO - maintains info about SPX sockets
+//
+
+typedef struct _CONNECTION_INFO {
+ LPCONNECTION_INFO Next; // next CONNECTION_INFO by OwningSocket
+ LPCONNECTION_INFO List; // all CONNECTION_INFO are linked together
+ LPSOCKET_INFO OwningSocket; // back-pointer to SOCKET_INFO
+ SOCKET Socket; // handle to socket
+ DWORD TaskId; // identifies windows task/owner
+ WORD ConnectionId; // analogous to SocketNumber
+ BYTE Flags;
+ BYTE State;
+ XECB_QUEUE ConnectQueue; // outgoing connections being made
+ XECB_QUEUE AcceptQueue; // waiting for incoming connections
+ XECB_QUEUE SendQueue; // packet sends on this connection
+ XECB_QUEUE ListenQueue; // partially complete receive
+ BYTE RemoteNode[6];
+ WORD RemoteConnectionId;
+} CONNECTION_INFO;
+
+//
+// CONNECTION_INFO Flag field values
+//
+
+#define CF_1ST_RECEIVE 0x80 // hack-o-rama till NWLink timing problem fixed
+
+//
+// CONNECTION_INFO State field values
+//
+
+#define CI_WAITING 0x01
+#define CI_STARTING 0x02
+#define CI_ESTABLISHED 0x03
+#define CI_TERMINATING 0x04
+
+//
+// one-line function macros
+//
+
+#define AllocateSocket() (LPSOCKET_INFO)LocalAlloc(LPTR, sizeof(SOCKET_INFO))
+#define DeallocateSocket(p) FREE_OBJECT(p)
+
+//
+// SocketType parameter for CreateSocket
+//
+
+typedef enum {
+ SOCKET_TYPE_IPX,
+ SOCKET_TYPE_SPX
+} SOCKET_TYPE;
+
+//
+// function prototypes
+//
+
+int
+CreateSocket(
+ IN SOCKET_TYPE SocketType,
+ IN OUT ULPWORD pSocketNumber,
+ OUT SOCKET* pSocket
+ );
+
+LPSOCKET_INFO
+AllocateTemporarySocket(
+ VOID
+ );
+
+VOID
+QueueSocket(
+ IN LPSOCKET_INFO pSocketInfo
+ );
+
+LPSOCKET_INFO
+DequeueSocket(
+ IN LPSOCKET_INFO pSocketInfo
+ );
+
+LPSOCKET_INFO
+FindSocket(
+ IN WORD SocketNumber
+ );
+
+LPSOCKET_INFO
+FindActiveSocket(
+ IN LPSOCKET_INFO pSocketInfo
+ );
+
+int
+ReopenSocket(
+ LPSOCKET_INFO pSocketInfo
+ );
+
+VOID
+KillSocket(
+ IN LPSOCKET_INFO pSocketInfo
+ );
+
+VOID
+KillShortLivedSockets(
+ IN WORD Owner
+ );
+
+LPCONNECTION_INFO
+AllocateConnection(
+ LPSOCKET_INFO pSocketInfo
+ );
+
+VOID
+DeallocateConnection(
+ IN LPCONNECTION_INFO pConnectionInfo
+ );
+
+LPCONNECTION_INFO
+FindConnection(
+ IN WORD ConnectionId
+ );
+
+VOID
+QueueConnection(
+ IN LPSOCKET_INFO pSocketInfo,
+ IN LPCONNECTION_INFO pConnectionInfo
+ );
+
+LPCONNECTION_INFO
+DequeueConnection(
+ IN LPSOCKET_INFO pSocketInfo,
+ IN LPCONNECTION_INFO pConnectionInfo
+ );
+
+VOID
+KillConnection(
+ IN LPCONNECTION_INFO pConnectionInfo
+ );
+
+VOID
+AbortOrTerminateConnection(
+ IN LPCONNECTION_INFO pConnectionInfo,
+ IN BYTE CompletionCode
+ );
+
+VOID
+CheckPendingSpxRequests(
+ BOOL *pfOperationPerformed
+ );
diff --git a/private/nw/vwipxspx/dll/sources b/private/nw/vwipxspx/dll/sources
new file mode 100644
index 000000000..2cb76d030
--- /dev/null
+++ b/private/nw/vwipxspx/dll/sources
@@ -0,0 +1,64 @@
+!IF 0
+
+Copyright (c) 1989-1991 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+History:
+
+ Created 12-Sep-1991 by Richard L Firth (rfirth)
+ from template created 12-Apr-1990 by Steve Wood (stevewo)
+
+
+NOTE: Commented description of this file is in \nt\public\oak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=nw
+MINORCOMP=vwipxspx
+
+TARGETNAME=vwipxspx
+TARGETPATH=$(BASEDIR)\public\sdk\lib
+TARGETTYPE=DYNLINK
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\kernel32.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntvdm.lib \
+ $(BASEDIR)\public\sdk\lib\*\wsock32.lib
+
+DLLENTRY=VwDllEntryPoint
+DLLBASE=0x03200000
+
+USE_CRTDLL=1
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+INCLUDES=.;..\..\inc;$(BASEDIR)\private\inc;$(BASEDIR)\private\mvdm\vdd\h
+
+SOURCES=vwdll.c \
+ vwipx.c \
+ vwspx.c \
+ vwasync.c \
+ vwmisc.c \
+ vwdebug.c \
+ socket.c \
+ vwinapi.c \
+ vwdos.c \
+ vwipxspx.rc \
+ util.c
+
+C_DEFINES=-DMAX_OPEN_SOCKETS=150 -DSPX_HACK=1 -DREUSEADDR=1
+
+!ifdef MARS_PCH
+PRECOMPILED_INCLUDE=vw.h
+PRECOMPILED_PCH=vw.pch
+PRECOMPILED_OBJ=vw.obj
+!endif
diff --git a/private/nw/vwipxspx/dll/util.c b/private/nw/vwipxspx/dll/util.c
new file mode 100644
index 000000000..5e4aac78f
--- /dev/null
+++ b/private/nw/vwipxspx/dll/util.c
@@ -0,0 +1,2966 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ util.c
+
+Abstract:
+
+ ntVdm netWare (Vw) IPX/SPX Functions
+
+ Vw: The peoples' network
+
+ Contains various utility routines
+
+ Contents:
+ GetInternetAddress
+ GetMaxPacketSize
+ RetrieveEcb
+ RetrieveXEcb
+ (AllocateXecb)
+ (DeallocateXecb)
+ ScheduleEvent
+ ScanTimerList
+ CancelTimerEvent
+ CancelTimedEvents
+ CancelAsyncEvent
+ CancelSocketEvent
+ CancelConnectionEvent
+ QueueEcb
+ DequeueEcb
+ CancelSocketQueue
+ CancelConnectionQueue
+ AbortQueue
+ AbortConnectionEvent
+ StartIpxSend
+ GetIoBuffer
+ (ReleaseIoBuffer)
+ GatherData
+ ScatterData
+ IpxReceiveFirst
+ IpxReceiveNext
+ (IpxSendFirst)
+ IpxSendNext
+ (QueueReceiveRequest)
+ (DequeueReceiveRequest)
+ (QueueSendRequest)
+ (DequeueSendRequest)
+ CompleteOrQueueIo
+ CompleteIo
+ CompleteOrQueueEcb
+ CompleteEcb
+ (QueueAsyncCompletion)
+ EsrCallback
+ VWinEsrCallback
+ FifoAddHead
+ FifoAdd
+ FifoRemove
+ FifoNext
+
+Author:
+
+ Richard L Firth (rfirth) 30-Sep-1993
+
+Environment:
+
+ User-mode Win32
+
+Revision History:
+
+ 30-Sep-1993 rfirth
+ Created
+
+--*/
+
+#include "vw.h"
+#pragma hdrstop
+
+//
+// private routine prototypes
+//
+
+PRIVATE
+LPXECB
+AllocateXecb(
+ VOID
+ );
+
+PRIVATE
+VOID
+DeallocateXecb(
+ IN LPXECB pXecb
+ );
+
+PRIVATE
+VOID
+ReleaseIoBuffer(
+ IN LPXECB pXecb
+ );
+
+PRIVATE
+VOID
+IpxSendFirst(
+ IN LPXECB pXecb,
+ IN LPSOCKET_INFO pSocketInfo
+ );
+
+PRIVATE
+VOID
+QueueReceiveRequest(
+ IN LPXECB pXecb,
+ IN LPSOCKET_INFO pSocketInfo
+ );
+
+PRIVATE
+LPXECB
+DequeueReceiveRequest(
+ IN LPXECB pXecb,
+ IN LPSOCKET_INFO pSocketInfo
+ );
+
+PRIVATE
+VOID
+QueueSendRequest(
+ IN LPXECB pXecb,
+ IN LPSOCKET_INFO pSocketInfo
+ );
+
+PRIVATE
+LPXECB
+DequeueSendRequest(
+ IN LPXECB pXecb,
+ IN LPSOCKET_INFO pSocketInfo
+ );
+
+PRIVATE
+VOID
+QueueAsyncCompletion(
+ IN LPXECB pXecb,
+ IN BYTE CompletionCode
+ );
+
+//
+// private data
+//
+
+//
+// TimerList - singly-linked list of timed events, in order of duration
+//
+
+PRIVATE LPXECB TimerList = NULL;
+
+//
+// AsyncCompletionQueue - keeps list of completed ECBs awaiting removal via
+// ESR callback
+//
+
+PRIVATE FIFO AsyncCompletionQueue = {NULL, NULL};
+
+//
+// sort-of-private data (matches not-really-global data in other modules)
+//
+
+//
+// SerializationCritSec - grab this when manipulating SOCKET_INFO list
+//
+
+CRITICAL_SECTION SerializationCritSec;
+
+//
+// AsyncCritSec - grab this when manipulating AsyncCompletionQueue
+//
+
+CRITICAL_SECTION AsyncCritSec;
+
+//
+// functions
+//
+
+
+int
+GetInternetAddress(
+ IN OUT LPSOCKADDR_IPX InternetAddress
+ )
+
+/*++
+
+Routine Description:
+
+ Gets the node and net numbers for this station
+
+Arguments:
+
+ InternetAddress - pointer to SOCKADDR_IPX structure to fill with internetwork
+ address for this station
+
+Return Value:
+
+ int
+ Success - 0
+ Failure - SOCKET_ERROR
+
+--*/
+
+{
+ SOCKET s;
+ int rc;
+ int structureLength = sizeof(*InternetAddress);
+
+ s = socket(AF_IPX, SOCK_DGRAM, NSPROTO_IPX);
+ if (s != INVALID_SOCKET) {
+
+ //
+ // make dynamic binding (socket number = 0)
+ //
+
+ ZeroMemory(InternetAddress, structureLength);
+ InternetAddress->sa_family = AF_IPX;
+ rc = bind(s, (LPSOCKADDR)InternetAddress, structureLength);
+ if (rc != SOCKET_ERROR) {
+ rc = getsockname(s, (LPSOCKADDR)InternetAddress, &structureLength);
+ if (rc) {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_ERROR,
+ "GetInternetAddress: getsockname() returns %d\n",
+ WSAGetLastError()
+ ));
+
+ }
+ } else {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_ERROR,
+ "GetInternetAddress: bind() returns %d\n",
+ WSAGetLastError()
+ ));
+
+ }
+ closesocket(s);
+ } else {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_ERROR,
+ "GetInternetAddress: socket() returns %d\n",
+ WSAGetLastError()
+ ));
+
+ rc = SOCKET_ERROR;
+ }
+ return rc;
+}
+
+
+int
+GetMaxPacketSize(
+ OUT LPWORD MaxPacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ Returns the maximum packet allowed by the underlying transport
+
+Arguments:
+
+ MaxPacketSize - pointer to returned maximum packet size
+
+Return Value:
+
+ int
+ Success - 0
+ Failure - SOCKET_ERROR
+
+--*/
+
+{
+ SOCKET s;
+ int maxLen, maxLenSize = sizeof(maxLen);
+ int rc;
+ SOCKADDR_IPX ipxAddr;
+
+ s = socket(AF_IPX, SOCK_DGRAM, NSPROTO_IPX);
+ if (s != SOCKET_ERROR) {
+
+ //
+ // set socket to 0 - causes any applicable address to be bound
+ //
+
+ ZeroMemory(&ipxAddr, sizeof(ipxAddr));
+ ipxAddr.sa_family = AF_IPX;
+ rc = bind(s, (LPSOCKADDR)&ipxAddr, sizeof(ipxAddr));
+ if (rc != SOCKET_ERROR) {
+
+ rc = getsockopt(s,
+ NSPROTO_IPX,
+ IPX_MAXSIZE,
+ (char FAR*)&maxLen,
+ &maxLenSize
+ );
+ if (rc != SOCKET_ERROR) {
+
+ //
+ // IPX_MAXSIZE always returns the amount of data that can be
+ // transmitted in a single frame. 16-bit IPX/SPX requires that
+ // the IPX header length be included in the data size
+ //
+
+ maxLen += IPX_HEADER_LENGTH;
+ } else {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_ERROR,
+ "GetMaxPacketSize: getsockopt() returns %d\n",
+ WSAGetLastError()
+ ));
+
+ }
+ } else {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_ERROR,
+ "GetMaxPacketSize: bind() returns %d\n",
+ WSAGetLastError()
+ ));
+
+ }
+ closesocket(s);
+ } else {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_ERROR,
+ "GetMaxPacketSize: socket() returns %d\n",
+ WSAGetLastError()
+ ));
+
+ rc = SOCKET_ERROR;
+ }
+
+ //
+ // BUGBUG: since IPX and SPX can only deal in packets of max size 576 bytes,
+ // should we just return 576 if the indicated size is larger???
+ //
+
+ *MaxPacketSize = (rc != SOCKET_ERROR) ? maxLen : MAXIMUM_IPX_PACKET_LENGTH;
+
+ return rc;
+}
+
+
+LPXECB
+RetrieveEcb(
+ IN BYTE EcbType
+ )
+
+/*++
+
+Routine Description:
+
+ Returns pointer to 32-bit extended ECB structure which contains flat pointer
+ to IPX or AES ECB in VDM memory
+
+ We allocate the extended ECB for 3 reasons:
+
+ 1. Avoids 16-bit app scribbling over our control fields
+ 2. Don't have to make unaligned references to all fields (still need some)
+ 3. Don't have enough space in AES ECB to remember all the stuff we need
+
+ However, we do update the 16-bit ECB's LinkAddress field. We use this as a
+ pointer to the 32-bit XECB we allocate in this routine. This just saves us
+ having to traverse all the lists looking for the address of the 16-bit ECB
+ (which we could still do as a fall-back)
+
+Arguments:
+
+ EcbType - type of ECB - AES, IPX or SPX
+
+Return Value:
+
+ LPXECB - 32-bit pointer to extended ECB structure
+
+--*/
+
+{
+ WORD segment;
+ WORD offset;
+ LPECB pEcb;
+
+ segment = IPX_GET_ECB_SEGMENT();
+ offset = IPX_GET_ECB_OFFSET();
+ pEcb = (LPIPX_ECB)POINTER_FROM_WORDS(segment, offset, sizeof(IPX_ECB));
+
+ return RetrieveXEcb(EcbType, pEcb, (ECB_ADDRESS)MAKELONG(offset,segment));
+}
+
+
+LPXECB
+RetrieveXEcb(
+ IN BYTE EcbType,
+ LPECB pEcb,
+ ECB_ADDRESS EcbAddress
+ )
+
+/*++
+
+Routine Description:
+
+ worker for RetrieveEcb, callable from windows functions (ex DOS parms)
+
+Arguments:
+
+ EcbType - type of ECB - AES, IPX or SPX
+ pEcb - pointer to the 16-bit ECB
+ EcbAddress - address (seg:off in DWORD) of 16-bit ECB
+
+Return Value:
+
+ LPXECB
+
+--*/
+
+{
+ LPXECB pXecb;
+
+ if (pEcb) {
+
+ //
+ // allocate and fill-in 32-bit extended ECB structure. If can't allocate
+ // then return NULL
+ //
+
+ pXecb = AllocateXecb();
+ if (pXecb) {
+ pXecb->Ecb = pEcb;
+ pXecb->EcbAddress = EcbAddress;
+ pXecb->EsrAddress = pEcb->EsrAddress;
+
+ //
+ // set flags - IPX/AES, SPX, protect-mode
+ //
+
+ pXecb->Flags |= (((EcbType == ECB_TYPE_IPX) || (EcbType == ECB_TYPE_SPX))
+ ? XECB_FLAG_IPX
+ : XECB_FLAG_AES)
+ | ((EcbType == ECB_TYPE_SPX) ? XECB_FLAG_SPX : 0)
+ | ((getMSW() & MSW_PE) ? XECB_FLAG_PROTMODE : 0);
+
+ //
+ // this XECB is not yet on a queue
+ //
+
+ pXecb->QueueId = NO_QUEUE;
+
+ //
+ // mark the 16-bit ECB as being used. We use an undefined value to
+ // make sure it gets set/reset in the right places
+ //
+
+ pEcb->InUse = ECB_IU_TEMPORARY;
+
+ //
+ // use the LinkAddress field in the 16-bit ECB to point to the XECB.
+ // We use this when cancelling the ECB
+ //
+
+ pEcb->LinkAddress = pXecb;
+
+ //
+ // AES and IPX ECBs have different sizes and different layouts
+ //
+
+ if ((EcbType == ECB_TYPE_IPX) || (EcbType == ECB_TYPE_SPX)) {
+ pXecb->SocketNumber = pEcb->SocketNumber;
+ }
+ }
+ } else {
+ pXecb = NULL;
+ }
+ return pXecb;
+}
+
+
+PRIVATE
+LPXECB
+AllocateXecb(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Allocate an XECB; zero it; set the reference count to 1
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ LPXECB
+
+--*/
+
+{
+ LPXECB pXecb;
+
+ pXecb = (LPXECB)LocalAlloc(LPTR, sizeof(*pXecb));
+ if (pXecb) {
+ pXecb->RefCount = 1;
+ }
+ return pXecb;
+}
+
+
+PRIVATE
+VOID
+DeallocateXecb(
+ IN LPXECB pXecb
+ )
+
+/*++
+
+Routine Description:
+
+ decrement the XECB reference count (while holding SerializationCritSec). If
+ goes to 0 then free the structure (else other thread is also holding pointer
+ to XECB)
+
+Arguments:
+
+ pXecb - XECB to deallocate
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ RequestMutex();
+ --pXecb->RefCount;
+ if (!pXecb->RefCount) {
+
+#if DBG
+ FillMemory(pXecb, sizeof(*pXecb), 0xFF);
+#endif
+
+ FREE_OBJECT(pXecb);
+ }
+ ReleaseMutex();
+}
+
+
+VOID
+ScheduleEvent(
+ IN LPXECB pXecb,
+ IN WORD Ticks
+ )
+
+/*++
+
+Routine Description:
+
+ Adds an ECB to the TimerList, ordered by Ticks. The value of Ticks cannot
+ be zero
+
+ Assumes 1. Ticks != 0
+ 2. pXecb->Next is already NULL (as result of LocalAlloc(LPTR,...)
+
+Arguments:
+
+ pXecb - pointer to XECB describing IPX or AES ECB to queue
+ Ticks - number of ticks to elapse before ECB is cooked
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ASSERT(Ticks);
+ ASSERT(pXecb->Next == NULL);
+
+ RequestMutex();
+ if (!TimerList) {
+ TimerList = pXecb;
+ } else {
+ if (TimerList->Ticks > Ticks) {
+ TimerList->Ticks -= Ticks;
+ pXecb->Next = TimerList;
+ TimerList = pXecb;
+ } else {
+
+ LPXECB previous = (LPXECB)TimerList;
+ LPXECB this = previous->Next;
+
+ Ticks -= TimerList->Ticks;
+ while (this && Ticks > this->Ticks) {
+ Ticks -= this->Ticks;
+ previous = this;
+ this = this->Next;
+ }
+ previous->Next = pXecb;
+ pXecb->Next = this;
+ }
+ }
+ pXecb->Ticks = Ticks;
+ pXecb->QueueId = TIMER_QUEUE;
+ ReleaseMutex();
+}
+
+
+VOID
+ScanTimerList(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Called once per tick. Decrements the tick count of the ECB at the head of
+ the list. If it goes to zero, completes the ECB and any subsequent ECBs
+ which whose tick count would go to zero
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LPXECB pXecb;
+
+ RequestMutex();
+ pXecb = TimerList;
+ if (pXecb) {
+
+ //
+ // Decrement if not already zero. Can be zero because the ECB at the
+ // front of the list could have been Cancelled. This makes sure we
+ // do not wrap around to 0xFFFF !!!
+ //
+
+ if (pXecb->Ticks != 0)
+ --pXecb->Ticks;
+
+ if (!pXecb->Ticks) {
+
+ //
+ // complete all ECBs that would go to 0 on this tick
+ //
+
+ while (pXecb->Ticks <= 1) {
+ TimerList = pXecb->Next;
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_INFO,
+ "ScanTimerList: ECB %04x:%04x is done\n",
+ HIWORD(pXecb->EcbAddress),
+ LOWORD(pXecb->EcbAddress)
+ ));
+
+ CompleteOrQueueEcb(pXecb, ECB_CC_SUCCESS);
+ pXecb = TimerList;
+ if (!pXecb) {
+ break;
+ }
+ }
+ }
+ }
+
+ ReleaseMutex();
+}
+
+
+BYTE
+CancelTimerEvent(
+ IN LPXECB pXecb
+ )
+
+/*++
+
+Routine Description:
+
+ Cancels a pending event on the timer list
+
+Arguments:
+
+ pXecb - pointer to XECB to cancel
+
+Return Value:
+
+ BYTE
+ Success - IPX_SUCCESS
+ Failure - IPX_ECB_NOT_IN_USE
+
+--*/
+
+{
+ LPXECB listptr;
+ LPXECB previous = (LPXECB)&TimerList;
+ BYTE status;
+
+ RequestMutex();
+ listptr = TimerList;
+ while (listptr && listptr != pXecb) {
+ previous = listptr;
+ listptr = listptr->Next;
+ }
+ if (listptr) {
+
+ //
+ // take the XECB out of the list and complete the ECB (in VDM memory).
+ // Does not generate a call-back to the ESR. When CompleteEcb returns,
+ // the XECB has been deallocated
+ //
+
+ previous->Next = listptr->Next;
+
+ ASSERT(pXecb->RefCount == 2);
+
+ --pXecb->RefCount;
+ CompleteEcb(pXecb, ECB_CC_CANCELLED);
+ status = IPX_SUCCESS;
+ } else {
+ status = IPX_ECB_NOT_IN_USE;
+ }
+ ReleaseMutex();
+ return status;
+}
+
+
+VOID
+CancelTimedEvents(
+ IN WORD SocketNumber,
+ IN WORD Owner,
+ IN DWORD TaskId
+ )
+
+/*++
+
+Routine Description:
+
+ traverses the TimerList cancelling any IPX or AES events owned by any of
+ SocketNumber, Owner or TaskId
+
+ Assumes valid SocketNumber, Owner or TaskId cannot be 0
+
+Arguments:
+
+ SocketNumber - owning socket of IPX events to cancel
+ Owner - owning DOS PDB
+ TaskID - owning Windows Task ID
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LPXECB pXecb;
+ LPXECB prev = (LPXECB)&TimerList;
+ LPXECB next;
+
+ RequestMutex();
+ pXecb = TimerList;
+ while (pXecb) {
+
+ next = pXecb->Next;
+
+ if ((SocketNumber && (pXecb->SocketNumber == SocketNumber))
+ || (Owner && !(pXecb->Flags & XECB_FLAG_IPX) && (pXecb->Owner == Owner))
+ || (TaskId && (pXecb->TaskId == TaskId))) {
+
+ prev->Next = next;
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_INFO,
+ "CancelTimedEvents: cancelling ECB %08x (%04x:%04x)\n",
+ pXecb,
+ HIWORD(pXecb->EcbAddress),
+ LOWORD(pXecb->EcbAddress)
+ ));
+
+ CompleteEcb(pXecb, ECB_CC_CANCELLED);
+ }
+ else
+ {
+ prev = pXecb ;
+ }
+ pXecb = next;
+ }
+ ReleaseMutex();
+}
+
+
+BYTE
+CancelAsyncEvent(
+ IN LPXECB pXecb
+ )
+
+/*++
+
+Routine Description:
+
+ Called to cancel an event currently on the async completion list. We don't
+ cancel these events - just return 0xF9 (ECB cannot be cancelled). It is a
+ race to see who gets there first - us with the cancel, or the ESR callback.
+ In this case it is fairly immaterial
+
+Arguments:
+
+ pXecb - pointer to XECB to cancel (ignored)
+
+Return Value:
+
+ BYTE - IPX_CANNOT_CANCEL
+
+--*/
+
+{
+ //
+ // we call DeallocateXecb to reduce the reference count. If the other thread
+ // really tried to deallocate it in the short time we've been looking at it
+ // on the cancel path, the call will finish up what the other thread started
+ //
+
+ DeallocateXecb(pXecb);
+ return IPX_CANNOT_CANCEL;
+}
+
+
+BYTE
+CancelSocketEvent(
+ IN LPXECB pXecb
+ )
+
+/*++
+
+Routine Description:
+
+ Called to cancel a pending send or listen from a socket queue. Request can
+ be IPX or SPX. If IPX event, then the ECB is on either the SendQueue or
+ ListenQueue. If SPX, it may be on a CONNECTION_INFO ConnectQueue,
+ AcceptQueue, SendQueue or ListenQueue, or if it is an
+ SPXListenForSequencedPacket request that is still in the pool then it may
+ be on the owning SOCKET_INFO ListenQueue
+
+Arguments:
+
+ pXecb - pointer to XECB describing ECB to cancel
+
+Return Value:
+
+ BYTE - IPX_SUCCESS
+
+--*/
+
+{
+ LPXECB ptr;
+ LPVOID pObject;
+
+ RequestMutex();
+ pObject = pXecb->OwningObject;
+ switch (pXecb->QueueId) {
+ case SOCKET_LISTEN_QUEUE:
+ if (pXecb->Flags & XECB_FLAG_SPX) {
+ ptr = DequeueEcb(pXecb, &((LPSOCKET_INFO)pObject)->ListenQueue);
+ } else {
+ ptr = DequeueReceiveRequest(pXecb, (LPSOCKET_INFO)pObject);
+ }
+ break;
+
+ case SOCKET_SEND_QUEUE:
+ if (pXecb->Flags & XECB_FLAG_SPX) {
+ ptr = DequeueEcb(pXecb, &((LPSOCKET_INFO)pObject)->SendQueue);
+ } else {
+ ptr = DequeueSendRequest(pXecb, (LPSOCKET_INFO)pObject);
+ }
+ break;
+
+ case SOCKET_HEADER_QUEUE: // SPX only
+ if (pXecb->Flags & XECB_FLAG_SPX) {
+ ptr = DequeueEcb(pXecb, &((LPSOCKET_INFO)pObject)->HeaderQueue);
+ } else {
+ ASSERT(FALSE);
+ }
+ break;
+ }
+ ReleaseMutex();
+ if (ptr) {
+ CompleteIo(ptr, ECB_CC_CANCELLED);
+ }
+ return IPX_SUCCESS;
+}
+
+
+BYTE
+CancelConnectionEvent(
+ IN LPXECB pXecb
+ )
+
+/*++
+
+Routine Description:
+
+ Cancels a pending SPXListenForConnection or SPXListenForSequencedPacket, the
+ only cancellable SPX requests
+
+Arguments:
+
+ pXecb - pointer to SPX XECB to cancel
+
+Return Value:
+
+ BYTE - IPX_SUCCESS
+
+--*/
+
+{
+ LPXECB ptr;
+ LPVOID pObject;
+ LPXECB_QUEUE pQueue;
+
+ RequestMutex();
+ pObject = pXecb->OwningObject;
+ switch (pXecb->QueueId) {
+ case CONNECTION_ACCEPT_QUEUE:
+ pQueue = &((LPCONNECTION_INFO)pObject)->AcceptQueue;
+ break;
+
+ case CONNECTION_LISTEN_QUEUE:
+ pQueue = &((LPCONNECTION_INFO)pObject)->ListenQueue;
+ break;
+ }
+ ptr = DequeueEcb(pXecb, pQueue);
+ ReleaseMutex();
+ if (ptr) {
+ CompleteIo(ptr, ECB_CC_CANCELLED);
+ }
+ return IPX_SUCCESS;
+}
+
+
+VOID
+QueueEcb(
+ IN LPXECB pXecb,
+ IN LPXECB_QUEUE Queue,
+ IN QUEUE_ID QueueId
+ )
+
+/*++
+
+Routine Description:
+
+ Adds an XECB to a queue and sets the queue identifier in the XECB.
+
+Arguments:
+
+ pXecb - pointer to XECB to queue
+ Queue - pointer to queue to add XECB to (at tail)
+ QueueId - identifies Queue
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LPVOID owningObject = NULL;
+
+#define CONTAINER_STRUCTURE(p, t, f) (LPVOID)(((LPBYTE)(p)) - (DWORD)(&((t)0)->f))
+
+ pXecb->QueueId = QueueId;
+ switch (QueueId) {
+ case SOCKET_LISTEN_QUEUE:
+ if (Queue->Tail && (Queue->Tail->Length < pXecb->Length)) {
+ FifoAddHead((LPFIFO)Queue, (LPFIFO)pXecb);
+ } else {
+ FifoAdd((LPFIFO)Queue, (LPFIFO)pXecb);
+ }
+ owningObject = CONTAINER_STRUCTURE(Queue, LPSOCKET_INFO, ListenQueue);
+ break;
+
+ case SOCKET_SEND_QUEUE:
+ FifoAdd((LPFIFO)Queue, (LPFIFO)pXecb);
+ owningObject = CONTAINER_STRUCTURE(Queue, LPSOCKET_INFO, SendQueue);
+ break;
+
+ case SOCKET_HEADER_QUEUE:
+ FifoAdd((LPFIFO)Queue, (LPFIFO)pXecb);
+ owningObject = CONTAINER_STRUCTURE(Queue, LPSOCKET_INFO, HeaderQueue);
+ break;
+
+ case CONNECTION_CONNECT_QUEUE:
+ FifoAdd((LPFIFO)Queue, (LPFIFO)pXecb);
+ owningObject = CONTAINER_STRUCTURE(Queue, LPCONNECTION_INFO, ConnectQueue);
+ break;
+
+ case CONNECTION_ACCEPT_QUEUE:
+ FifoAdd((LPFIFO)Queue, (LPFIFO)pXecb);
+ owningObject = CONTAINER_STRUCTURE(Queue, LPCONNECTION_INFO, AcceptQueue);
+ break;
+
+ case CONNECTION_SEND_QUEUE:
+ FifoAdd((LPFIFO)Queue, (LPFIFO)pXecb);
+ owningObject = CONTAINER_STRUCTURE(Queue, LPCONNECTION_INFO, SendQueue);
+ break;
+
+ case CONNECTION_LISTEN_QUEUE:
+ FifoAdd((LPFIFO)Queue, (LPFIFO)pXecb);
+ owningObject = CONTAINER_STRUCTURE(Queue, LPCONNECTION_INFO, ListenQueue);
+ break;
+ }
+ pXecb->OwningObject = owningObject;
+}
+
+
+LPXECB
+DequeueEcb(
+ IN LPXECB pXecb,
+ IN LPXECB_QUEUE Queue
+ )
+
+/*++
+
+Routine Description:
+
+ Removes pXecb from Queue and resets the XECB queue identifier (to NO_QUEUE)
+
+Arguments:
+
+ pXecb - pointer to XECB to remove
+ Queue - queue from which to remove pXecb
+
+Return Value:
+
+ LPXECB
+ pointer to removed XECB
+
+--*/
+
+{
+ LPXECB p;
+
+ p = (LPXECB)FifoRemove((LPFIFO)Queue, (LPFIFO)pXecb);
+ pXecb->QueueId = NO_QUEUE;
+ pXecb->OwningObject = NULL;
+ return pXecb;
+}
+
+
+VOID
+CancelSocketQueue(
+ IN LPXECB_QUEUE pXecbQueue
+ )
+
+/*++
+
+Routine Description:
+
+ Cancels all pending ECBs on a SOCKET_INFO queue
+
+Arguments:
+
+ pXecbQueue - pointer to (socket/connection) queue
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LPXECB ptr;
+
+ while (ptr = pXecbQueue->Head) {
+ CancelSocketEvent(ptr);
+ }
+}
+
+
+VOID
+CancelConnectionQueue(
+ IN LPXECB_QUEUE pXecbQueue
+ )
+
+/*++
+
+Routine Description:
+
+ Cancels all pending ECBs on a CONNECTION_INFO queue
+
+Arguments:
+
+ pXecbQueue - pointer to XECB queue on CONNECTION_INFO
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LPXECB ptr;
+
+ while (ptr = pXecbQueue->Head) {
+ CancelConnectionEvent(ptr);
+ }
+}
+
+
+VOID
+AbortQueue(
+ IN LPXECB_QUEUE pXecbQueue,
+ IN BYTE CompletionCode
+ )
+
+/*++
+
+Routine Description:
+
+ Aborts or terminates an ECB queue from a CONNECTION_INFO structure
+
+Arguments:
+
+ pXecbQueue - pointer to queue
+ CompletionCode - to put in aborted/terminated ECBs
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LPXECB ptr;
+
+ while (ptr = pXecbQueue->Head) {
+ AbortConnectionEvent(ptr, CompletionCode);
+ }
+}
+
+
+VOID
+AbortConnectionEvent(
+ IN LPXECB pXecb,
+ IN BYTE CompletionCode
+ )
+
+/*++
+
+Routine Description:
+
+ Aborts a connection ECB
+
+Arguments:
+
+ pXecb - pointer to SPX XECB to cancel
+ CompletionCode - value to put in ECB
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LPXECB ptr;
+ LPCONNECTION_INFO pConnectionInfo;
+ LPXECB_QUEUE pQueue;
+
+ pConnectionInfo = (LPCONNECTION_INFO)pXecb->OwningObject;
+ switch (pXecb->QueueId) {
+ case CONNECTION_CONNECT_QUEUE:
+ pQueue = &pConnectionInfo->ConnectQueue;
+ break;
+
+ case CONNECTION_ACCEPT_QUEUE:
+ pQueue = &pConnectionInfo->AcceptQueue;
+ break;
+
+ case CONNECTION_SEND_QUEUE:
+ pQueue = &pConnectionInfo->SendQueue;
+ break;
+
+ case CONNECTION_LISTEN_QUEUE:
+ pQueue = &pConnectionInfo->ListenQueue;
+ break;
+ }
+ ptr = DequeueEcb(pXecb, pQueue);
+ if (ptr) {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_INFO,
+ "AbortConnectionEvent: Aborting ECB %04x:%04x\n",
+ HIWORD(pXecb->EcbAddress),
+ LOWORD(pXecb->EcbAddress)
+ ));
+
+ SPX_ECB_CONNECTION_ID(ptr->Ecb) = pConnectionInfo->ConnectionId;
+ CompleteOrQueueIo(ptr, CompletionCode);
+ }
+}
+
+
+VOID
+StartIpxSend(
+ IN LPXECB pXecb,
+ IN LPSOCKET_INFO pSocketInfo
+ )
+
+/*++
+
+Routine Description:
+
+ Starts a send operation for IPXSendPacket(). Allocates a send buffer if
+ the ECB has >1 fragment else uses a pointer to the single fragment buffer
+ in 16-bit address space
+
+ Fills in various fields in the ECB and IPX header
+
+ Assumes: 1. By the time this function is called, we already know we have
+ a valid non-zero fragment count and the first fragment is
+ big enough to hold an IPX packet header
+
+ When this function terminates, the ECB is either completed or queued
+
+Arguments:
+
+ pXecb - pointer to XECB describing ECB to use for sending
+ pSocketInfo - pointer to SOCKET_INFO structure
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ BOOL success;
+ int packetLength = 0;
+ LPFRAGMENT pFragment;
+ int fragmentCount;
+ LPIPX_ECB pEcb = (LPIPX_ECB)pXecb->Ecb;
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_INFO,
+ "StartIpxSend: %d frag(s), 1: address=%x (%04x:%04x), len=%04x\n",
+ READ_WORD(&pEcb->FragmentCount),
+ GET_FAR_POINTER(&(ECB_FRAGMENT(pEcb, 0)->Address), IS_PROT_MODE(pXecb)),
+ GET_SELECTOR(&(ECB_FRAGMENT(pEcb, 0)->Address)),
+ GET_OFFSET(&(ECB_FRAGMENT(pEcb, 0)->Address)),
+ READ_WORD(&(ECB_FRAGMENT(pEcb, 0)->Length))
+ ));
+
+ //
+ // mark the ECB as being used by IPX (for send)
+ //
+
+ pEcb->InUse = ECB_IU_SENDING;
+
+ //
+ // the total send buffer size cannot exceed the maximum packet size
+ //
+
+ fragmentCount = (int)pEcb->FragmentCount;
+
+ ASSERT(fragmentCount);
+
+ pFragment = (LPFRAGMENT)&(ECB_FRAGMENT(pEcb, 0)->Address);
+ while (fragmentCount--) {
+ packetLength += pFragment->Length;
+ ++pFragment;
+ }
+ if (packetLength <= MyMaxPacketSize) {
+ success = GetIoBuffer(pXecb, TRUE, IPX_HEADER_LENGTH);
+ if (success) {
+
+ LPIPX_PACKET pPacket = (LPIPX_PACKET)GET_FAR_POINTER(
+ &(ECB_FRAGMENT(pEcb, 0)->Address),
+ IS_PROT_MODE(pXecb)
+ );
+
+ //
+ // fill in the following fields in the IPX header:
+ //
+ // Checksum
+ // Length
+ // TransportControl
+ // Source (network, node, socket)
+ //
+ // BUGBUG: Does real IPX modify these fields in app memory?
+ // If so, does the app expect modified fields?
+ // If not, we need to always copy then modify memory,
+ // even if only 1 fragment
+ //
+
+ pPacket->Checksum = 0xFFFF;
+ pPacket->Length = L2BW((WORD)packetLength);
+ pPacket->TransportControl = 0;
+ CopyMemory((LPBYTE)&pPacket->Source,
+ &MyInternetAddress.sa_netnum,
+ sizeof(MyInternetAddress.sa_netnum)
+ + sizeof(MyInternetAddress.sa_nodenum)
+ );
+ pPacket->Source.Socket = pSocketInfo->SocketNumber;
+
+ //
+ // if we allocated a buffer then there is >1 fragment. Collect them
+ //
+
+ if (pXecb->Flags & XECB_FLAG_BUFFER_ALLOCATED) {
+ GatherData(pXecb, IPX_HEADER_LENGTH);
+ }
+
+ //
+ // initiate the send. IPX_ECB_BUFFER32(pEcb) points to the data to send,
+ // IPX_ECB_LENGTH32(pEcb) is the size of data to send
+ //
+
+ IpxSendFirst(pXecb, pSocketInfo);
+ } else {
+
+ //
+ // couldn't allocate a buffer? Comes under the heading of
+ // hardware error?
+ //
+
+ CompleteEcb(pXecb, ECB_CC_HARDWARE_ERROR);
+ if (pSocketInfo->Flags & SOCKET_FLAG_TEMPORARY) {
+ KillSocket(pSocketInfo);
+ }
+ }
+ } else {
+
+ //
+ // packet larger than MyMaxPacketSize
+ //
+
+ CompleteOrQueueEcb(pXecb, ECB_CC_BAD_REQUEST);
+ if (pSocketInfo->Flags & SOCKET_FLAG_TEMPORARY) {
+ KillSocket(pSocketInfo);
+ }
+ }
+}
+
+
+BOOL
+GetIoBuffer(
+ IN OUT LPXECB pXecb,
+ IN BOOL Send,
+ IN WORD HeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ Allocate a buffer based on the ECB fragment list. If there is only 1 fragment
+ we use the address of the buffer in the VDM. If >1 fragment, we allocate a
+ 32-bit buffer large enough to hold all the 16-bit fragments
+
+ We trim the buffer requirement for a send buffer: we do not send the IPX/SPX
+ header with the data: it will be provided by the transport
+
+ Assumes: 1. If called for a send buffer, the first fragment has already
+ been verified as >= HeaderLength
+
+Arguments:
+
+ pXecb - pointer to XECB which points to IPX_ECB containing fragment
+ list to allocate buffer for
+ Send - TRUE if this request is to get a send buffer
+ HeaderLength - length of the (untransmitted) header portion
+
+Return Value:
+
+ BOOL
+ TRUE - Buffer allocated, XECB updated with address, length and flags
+ FALSE - either ECB contains bad fragment descriptor list or we
+ couldn't allocate a buffer
+
+--*/
+
+{
+ WORD fragmentCount;
+ WORD bufferLength = 0;
+ LPBYTE bufferPointer = NULL;
+ WORD flags = 0;
+ int i;
+ int fragIndex = 0; // index of fragment address to use if no allocation required
+ LPIPX_ECB pEcb = (LPIPX_ECB)pXecb->Ecb;
+
+ fragmentCount = READ_WORD(&pEcb->FragmentCount);
+
+ for (i = 0; i < (int)fragmentCount; ++i) {
+ bufferLength += ECB_FRAGMENT(pEcb, i)->Length;
+ }
+ if (bufferLength) {
+
+ //
+ // exclude the IPX header from send buffer. If the first send fragment
+ // contains only the IPX header, reduce the fragment count by 1
+ //
+
+ if (Send) {
+ bufferLength -= HeaderLength;
+ if (ECB_FRAGMENT(pEcb, 0)->Length == HeaderLength) {
+ --fragmentCount;
+ fragIndex = 1;
+ }
+ }
+ if (bufferLength) {
+ if (fragmentCount > 1) {
+ bufferPointer = AllocateBuffer(bufferLength);
+ if (bufferPointer) {
+ flags = XECB_FLAG_BUFFER_ALLOCATED;
+ } else {
+
+ //
+ // need a buffer; failed to allocate it
+ //
+
+ return FALSE;
+ }
+ } else {
+
+ //
+ // fragmentCount must be 1 (else bufferLength would be 0)
+ //
+
+ bufferPointer = GET_FAR_POINTER(
+ &ECB_FRAGMENT(pEcb, fragIndex)->Address,
+ IS_PROT_MODE(pXecb)
+ );
+ if (Send && !fragIndex) {
+
+ //
+ // if we are allocating a send buffer AND there is only 1
+ // fragment AND it is the first fragment then the one and
+ // only fragment must contain the IPX header and the data.
+ // Advance the data pointer past the IPX header
+ //
+
+ bufferPointer += HeaderLength;
+ }
+ }
+ } else {
+
+ //
+ // sending 0 bytes!!!
+ //
+
+ }
+ } else {
+
+ //
+ // fragments but no buffer length? Sounds like a malformed packet
+ //
+
+ return FALSE;
+ }
+
+ //
+ // bufferPointer is either the address of a buffer in 32-bit memory which
+ // must be gather/scattered when the I/O operation completes, or it is the
+ // address of a single fragment buffer in 16-bit memory. In the former case
+ // flags is ECB_ALLOCATE_32 and the latter 0
+ //
+
+ pXecb->Buffer = pXecb->Data = bufferPointer;
+ pXecb->Length = bufferLength;
+ pXecb->Flags |= flags;
+ return TRUE;
+}
+
+
+PRIVATE
+VOID
+ReleaseIoBuffer(
+ IN LPXECB pXecb
+ )
+
+/*++
+
+Routine Description:
+
+ Deallocates I/O buffer attached to XECB and zaps associated XECB fields
+
+Arguments:
+
+ pXecb - pointer to XECB owning buffer to be released
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ if (pXecb->Flags & XECB_FLAG_BUFFER_ALLOCATED) {
+ DeallocateBuffer(pXecb->Buffer);
+ pXecb->Buffer = pXecb->Data = NULL;
+ pXecb->Flags &= ~XECB_FLAG_BUFFER_ALLOCATED;
+ }
+}
+
+
+VOID
+GatherData(
+ IN LPXECB pXecb,
+ IN WORD HeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ Copies data from fragmented 16-bit memory into single 32-bit memory buffer.
+ Used to send data. We exclude the IPX header: this information is supplied
+ by the transport
+
+ Assumes: 1. The fragment descriptor list has been verified: we know that
+ the first fragment contains at least the IPX header
+
+Arguments:
+
+ pXecb - pointer to XECB structure. The following IPX_ECB and XECB
+ fields must contain coherent values:
+
+ IPX_ECB.FragmentCount
+ XECB.Buffer
+
+ HeaderLength - length of the (untransmitted) header portion
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ int fragmentCount;
+ WORD length;
+ ULPBYTE pData16;
+ ULPBYTE pData32;
+ LPFRAGMENT pFragment;
+ LPIPX_ECB pEcb = (LPIPX_ECB)pXecb->Ecb;
+
+ fragmentCount = (int)pEcb->FragmentCount;
+ pFragment = (LPFRAGMENT)&(ECB_FRAGMENT(pEcb, 0)->Address);
+ pData32 = pXecb->Buffer;
+
+ //
+ // if the 1st fragment contains more than the IPX/SPX header, copy the data
+ // after the header
+ //
+
+ if (pFragment->Length > HeaderLength) {
+
+ LPBYTE fragAddr = GET_FAR_POINTER(&pFragment->Address,
+ IS_PROT_MODE(pXecb)
+ );
+
+ length = pFragment->Length - HeaderLength;
+ CopyMemory((LPVOID)pData32,
+ fragAddr + HeaderLength,
+ length
+ );
+ pData32 += length;
+ }
+
+ //
+ // copy subsequent fragments
+ //
+
+ ++pFragment;
+ while (--fragmentCount) {
+ pData16 = GET_FAR_POINTER(&pFragment->Address, IS_PROT_MODE(pXecb));
+ length = pFragment->Length;
+ CopyMemory((PVOID)pData32, (CONST VOID*)pData16, (ULONG)length);
+ pData32 += length;
+ ++pFragment;
+ }
+}
+
+
+VOID
+ScatterData(
+ IN LPXECB pXecb
+ )
+
+/*++
+
+Routine Description:
+
+ Copies data from 32-bit memory to 16-bit. The data must be fragmented if
+ this function has been called (i.e. we determined there were >1 fragments
+ and allocated a single 32-bit buffer to cover them)
+
+Arguments:
+
+ pXecb - pointer to XECB containing 32-bit buffer info
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ int fragmentCount;
+ int length;
+ WORD length16;
+ WORD length32;
+ ULPBYTE pData16;
+ ULPBYTE pData32;
+ LPFRAGMENT pFragment;
+ LPIPX_ECB pEcb = (LPIPX_ECB)pXecb->Ecb;
+
+ fragmentCount = (int)pEcb->FragmentCount;
+ pFragment = (LPFRAGMENT)&(ECB_FRAGMENT(pEcb, 0)->Address);
+ pData32 = pXecb->Buffer;
+ length32 = pXecb->Length;
+ while (length32) {
+ pData16 = GET_FAR_POINTER(&pFragment->Address, IS_PROT_MODE(pXecb));
+ length16 = pFragment->Length;
+ length = min(length16, length32);
+ CopyMemory((PVOID)pData16, (CONST VOID*)pData32, (ULONG)length);
+ pData32 += length;
+ length32 -= length;
+ ++pFragment;
+ --fragmentCount;
+
+ ASSERT(fragmentCount >= 0);
+
+ }
+}
+
+
+VOID
+IpxReceiveFirst(
+ IN LPXECB pXecb,
+ IN LPSOCKET_INFO pSocketInfo
+ )
+
+/*++
+
+Routine Description:
+
+ Performs a receive against a non-blocking socket. This is the first
+ receive call for this ECB. If the receive completes immediately with data
+ or an error that isn't WSAEWOULDBLOCK then the ECB is completed. If the
+ receives completes with a WSAEWOULDBLOCK error then the request is queued
+ for deferred processing by the AES thread
+
+ Unlike send, receives are not serialized. If there are already receives
+ pending against the socket there could be a clash between this function
+ and IpxReceiveNext(), called from the AES thread. In this case, we expect
+ Winsock to do the right thing and serialize the callers
+
+Arguments:
+
+ pXecb - pointer to XECB describing receive ECB
+ pSocketInfo - pointer to socket structure
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ SOCKADDR_IPX from;
+ int fromLen = sizeof(from);
+ int rc;
+ BYTE status;
+ BOOL error;
+
+ rc = recvfrom(pSocketInfo->Socket,
+ (char FAR*)pXecb->Buffer,
+ (int)pXecb->Length,
+ 0, // flags
+ (LPSOCKADDR)&from,
+ &fromLen
+ );
+ if (rc != SOCKET_ERROR) {
+ error = FALSE;
+ status = ECB_CC_SUCCESS;
+ } else {
+ error = TRUE;
+ rc = WSAGetLastError();
+ if (rc == WSAEWOULDBLOCK) {
+ RequestMutex();
+ QueueReceiveRequest(pXecb, pSocketInfo);
+ ReleaseMutex();
+ } else if (rc == WSAEMSGSIZE) {
+ error = FALSE;
+ status = ECB_CC_BAD_REQUEST;
+ rc = pXecb->Length;
+ } else {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_ERROR,
+ "IpxReceiveFirst: recvfrom() returns %d (buflen=%d)\n",
+ rc,
+ pXecb->Length
+ ));
+
+ //
+ // BUGBUG: map error
+ //
+
+ CompleteOrQueueIo(pXecb, ECB_CC_BAD_REQUEST);
+ }
+ }
+ if (!error) {
+
+ //
+ // rc = bytes received, or 0 = connection terminated (even for DGRAM?)
+ //
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_INFO,
+ "IpxReceiveFirst: bytes received = %d (%x)\n",
+ rc,
+ rc
+ ));
+/*
+ VwDumpEcb(pXecb->Ecb,
+ HIWORD(pXecb->EcbAddress),
+ LOWORD(pXecb->EcbAddress),
+ FALSE,
+ TRUE,
+ TRUE,
+ IS_PROT_MODE(pXecb)
+ );
+*/
+
+ IPXDUMPDATA((pXecb->Buffer, 0, 0, FALSE, (WORD)rc));
+
+ //
+ // if the receive buffers are fragmented, copy the data to 16-bit memory
+ // (else single buffer: its already there (dude))
+ //
+
+ if (pXecb->Flags & XECB_FLAG_BUFFER_ALLOCATED) {
+
+ //
+ // update the ECB_LENGTH32 field to reflect the amount of data received
+ //
+
+ pXecb->Length = (WORD)rc;
+ ScatterData(pXecb);
+
+ //
+ // we have finished with the 32-bit buffer: deallocate it
+ //
+
+ ReleaseIoBuffer(pXecb);
+ }
+
+ //
+ // update the ImmediateAddress field in the ECB with the node address
+ // of the sender
+ //
+
+ CopyMemory(pXecb->Ecb->ImmediateAddress, from.sa_nodenum, sizeof(from.sa_nodenum));
+
+ //
+ // if this ECB has a non-NULL ESR then queue for asynchronous completion
+ // else complete immediately (app must poll InUse field)
+ //
+
+ CompleteOrQueueEcb(pXecb, status);
+ }
+}
+
+
+VOID
+IpxReceiveNext(
+ IN LPSOCKET_INFO pSocketInfo
+ )
+
+/*++
+
+Routine Description:
+
+ Attempts to complete an IPXListenForPacket request that has been deferred due
+ to the fact the socket was blocked.
+
+ The ECB containing all the receive information is at the head of the
+ ListenQueue on pSocketInfo
+
+ We can use any queued listen ECB, but it just so happens we use the one at
+ the head of the FIFO
+
+ Note: SerializationCritSec is held when this function is called.
+
+Arguments:
+
+ pSocketInfo - pointer to SOCKET_INFO structure with pending IPX send request
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LPXECB pXecb;
+ SOCKADDR_IPX from;
+ int fromLen = sizeof(from);
+ int rc;
+ BYTE status;
+ BOOL error;
+
+ ASSERT(pSocketInfo);
+
+ pXecb = (LPXECB)pSocketInfo->ListenQueue.Head;
+
+ ASSERT(pXecb);
+
+ rc = recvfrom(pSocketInfo->Socket,
+ (char FAR*)pXecb->Buffer,
+ (int)pXecb->Length,
+ 0, // flags
+ (LPSOCKADDR)&from,
+ &fromLen
+ );
+ if (rc != SOCKET_ERROR) {
+ error = FALSE;
+ status = ECB_CC_SUCCESS;
+ } else {
+ error = TRUE;
+ rc = WSAGetLastError();
+ if (rc == WSAEMSGSIZE) {
+ error = FALSE;
+ status = ECB_CC_BAD_REQUEST;
+ rc = pXecb->Length;
+ } else if (rc != WSAEWOULDBLOCK) {
+ DequeueReceiveRequest(pXecb, pSocketInfo);
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_ERROR,
+ "IpxReceiveNext: recvfrom() returns %d\n",
+ rc
+ ));
+
+ //
+ // BUGBUG: completion code?
+ //
+
+ CompleteOrQueueIo(pXecb, ECB_CC_CANCELLED);
+ }
+ }
+ if (!error) {
+/*
+ VwDumpEcb(pXecb->Ecb,
+ HIWORD(pXecb->EcbAddress),
+ LOWORD(pXecb->EcbAddress),
+ FALSE,
+ TRUE,
+ TRUE,
+ IS_PROT_MODE(pXecb)
+ );
+*/
+ //
+ // data received. Remove ECB from queue
+ //
+
+ DequeueReceiveRequest(pXecb, pSocketInfo);
+
+ //
+ // rc = bytes received, or 0 = connection terminated (even for DGRAM?)
+ //
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_INFO,
+ "IpxReceiveNext: ECB %04x:%04x bytes received = %d (%x)\n",
+ HIWORD(pXecb->EcbAddress),
+ LOWORD(pXecb->EcbAddress),
+ rc,
+ rc
+ ));
+
+ IPXDUMPDATA((pXecb->Buffer, 0, 0, FALSE, (WORD)rc));
+
+ //
+ // if the receive buffers are fragmented, copy the data to 16-bit memory
+ // (else single buffer: its already there (dude))
+ //
+
+ if (pXecb->Flags & XECB_FLAG_BUFFER_ALLOCATED) {
+
+ //
+ // update the IPX_ECB_LENGTH32 field to reflect the amount of data received
+ //
+
+ pXecb->Length = (WORD)rc;
+ ScatterData(pXecb);
+ ReleaseIoBuffer(pXecb);
+ }
+
+ //
+ // update the ImmediateAddress field in the ECB with the node address
+ // of the sender
+ //
+
+ CopyMemory(pXecb->Ecb->ImmediateAddress,
+ from.sa_nodenum,
+ sizeof(from.sa_nodenum)
+ );
+
+ //
+ // if this ECB has a non-NULL ESR then queue for asynchronous completion
+ // else complete immediately (app must poll InUse field)
+ //
+
+ CompleteOrQueueEcb(pXecb, ECB_CC_SUCCESS);
+ }
+}
+
+
+PRIVATE
+VOID
+IpxSendFirst(
+ IN LPXECB pXecb,
+ IN LPSOCKET_INFO pSocketInfo
+ )
+
+/*++
+
+Routine Description:
+
+ Tries to send an IPX packet. This is the first attempt to send the packet
+ described in the ECB. If the send succeeds or fails with an error other
+ than WSAEWOULDBLOCK we complete the ECB. If the send attempt fails because
+ the transport can't accept the request at this time, we queue it for later
+ when the AES thread will attempt to send it.
+
+ If there is already a send being attempted then we just queue this request
+ and let AES handle it in IpxSendNext()
+
+Arguments:
+
+ pXecb - pointer to XECB
+ pSocketInfo - pointer to SOCKET_INFO structure
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ RequestMutex();
+ if (pSocketInfo->Flags & SOCKET_FLAG_SENDING) {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_INFO,
+ "IpxSendFirst: queueing ECB %04x:%04x\n",
+ HIWORD(pXecb->EcbAddress),
+ LOWORD(pXecb->EcbAddress)
+ ));
+
+ QueueSendRequest(pXecb, pSocketInfo);
+ } else {
+
+ SOCKADDR_IPX to;
+ LPIPX_PACKET pPacket;
+ int length;
+ int rc;
+ LPIPX_ECB pEcb = (LPIPX_ECB)pXecb->Ecb;
+ int type;
+/*
+ VwDumpEcb(pXecb->Ecb,
+ HIWORD(pXecb->EcbAddress),
+ LOWORD(pXecb->EcbAddress),
+ FALSE,
+ TRUE,
+ TRUE,
+ IS_PROT_MODE(pXecb)
+ );
+*/
+ length = (int)pXecb->Length;
+
+ //
+ // the first fragment holds the destination address info
+ //
+
+ pPacket = (LPIPX_PACKET)GET_FAR_POINTER(&ECB_FRAGMENT(pEcb, 0)->Address,
+ IS_PROT_MODE(pXecb)
+ );
+ to.sa_family = AF_IPX;
+
+ //
+ // copy the destination net number as a DWORD (4 bytes) from the
+ // destination network address structure in the IPX packet header
+ //
+
+ *(ULPDWORD)&to.sa_netnum[0] = *(ULPDWORD)&pPacket->Destination.Net[0];
+ //
+ // copy the immediate (destination) node number as a DWORD (4 bytes) and
+ // a WORD (2 bytes) from the Destination network address structure in
+ // the IPX packet header. pPacket is an unaligned pointer, so we are
+ // safe
+ //
+
+ *(ULPDWORD)&to.sa_nodenum[0] = *(ULPDWORD)&pPacket->Destination.Node[0];
+
+ *(LPWORD)&to.sa_nodenum[4] = *(ULPWORD)&pPacket->Destination.Node[4];
+
+ //
+ // copy the destination socket number from the IPX packet header as a
+ // WORD (2 bytes). Again, the aligned pointer will save us
+ //
+
+ to.sa_socket = pPacket->Destination.Socket;
+
+ type = (int)pPacket->PacketType;
+ rc = setsockopt(pSocketInfo->Socket,
+ NSPROTO_IPX,
+ IPX_PTYPE,
+ (char FAR*)&type,
+ sizeof(type)
+ );
+ if (rc) {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_ERROR,
+ "IpxSendFirst: setsockopt(IPX_PTYPE) returns %d\n",
+ WSAGetLastError()
+ ));
+
+ }
+ rc = sendto(pSocketInfo->Socket,
+ (char FAR*)pXecb->Buffer,
+ length,
+ 0, // flags
+ (LPSOCKADDR)&to,
+ sizeof(to)
+ );
+ if (rc == length) {
+
+ //
+ // all data sent
+ //
+
+ IPXDUMPDATA((pXecb->Buffer, 0, 0, FALSE, (WORD)rc));
+
+ CompleteOrQueueIo(pXecb, ECB_CC_SUCCESS);
+ if (pSocketInfo->Flags & SOCKET_FLAG_TEMPORARY) {
+ KillSocket(pSocketInfo);
+ }
+ } else if (rc == SOCKET_ERROR) {
+ rc = WSAGetLastError();
+ if (rc == WSAEWOULDBLOCK) {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_INFO,
+ "IpxSendFirst: queueing ECB %04x:%04x (after sendto)\n",
+ HIWORD(pXecb->EcbAddress),
+ LOWORD(pXecb->EcbAddress)
+ ));
+
+ QueueSendRequest(pXecb, pSocketInfo);
+ } else {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_ERROR,
+ "IpxSendFirst: sendto() returns %d\n",
+ rc
+ ));
+
+ //
+ // BUGBUG: couple of possible completion codes here
+ //
+
+ CompleteIo(pXecb, ECB_CC_UNDELIVERABLE);
+ if (pSocketInfo->Flags & SOCKET_FLAG_TEMPORARY) {
+ KillSocket(pSocketInfo);
+ }
+ }
+ } else {
+
+ //
+ // BUGBUG: Is 0 a valid value for rc?
+ //
+
+ //
+ // send should send all the data or return an error
+ //
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_FATAL,
+ "IpxSendFirst: sendto() returns unexpected %d (length = %d)\n",
+ rc,
+ length
+ ));
+ }
+ }
+ ReleaseMutex();
+}
+
+
+VOID
+IpxSendNext(
+ IN LPSOCKET_INFO pSocketInfo
+ )
+
+/*++
+
+Routine Description:
+
+ Attempts to complete an IPXSendPacket request that has been deferred due
+ to the fact the socket was blocked.
+
+ The ECB containing all the send information is at the head of the SendQueue
+ on pSocketInfo
+
+ The SendQueue is serialized in FIFO order
+
+ Note: SerializationCritSec is held when this function is called.
+
+Arguments:
+
+ pSocketInfo - pointer to SOCKET_INFO structure with pending IPX send request
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ SOCKADDR_IPX to;
+ LPIPX_PACKET pPacket;
+ int length;
+ int rc;
+ LPXECB pXecb;
+ LPIPX_ECB pEcb;
+ int type;
+
+ pXecb = (LPXECB)pSocketInfo->SendQueue.Head;
+ pEcb = (LPIPX_ECB)pXecb->Ecb;
+
+ ASSERT(pXecb);
+ ASSERT(pEcb);
+/*
+ VwDumpEcb(pXecb->Ecb,
+ HIWORD(pXecb->EcbAddress),
+ LOWORD(pXecb->EcbAddress),
+ FALSE,
+ TRUE,
+ TRUE,
+ IS_PROT_MODE(pXecb)
+ );
+*/
+ length = (int)pXecb->Length;
+
+ //
+ // even though we have a 32-bit pointer to the IPX packet buffer which
+ // may be in 16- or 32-bit memory, we still need unaligned access
+ //
+
+ pPacket = (LPIPX_PACKET)pXecb->Buffer;
+ to.sa_family = AF_IPX;
+
+ //
+ // copy the destination net number as a DWORD (4 bytes) from the
+ // destination network address structure in the IPX packet header
+ //
+
+ *(ULPDWORD)&to.sa_netnum[0] = *(ULPDWORD)&pPacket->Destination.Net[0];
+ //
+ // copy the immediate (destination) node number as a DWORD (4 bytes) and
+ // a WORD (2 bytes) from the Destination network address structure in
+ // the IPX packet header. pPacket is an unaligned pointer, so we are
+ // safe
+ //
+
+ *(ULPDWORD)&to.sa_nodenum[0] = *(ULPDWORD)&pPacket->Destination.Node[0];
+ *(LPWORD)&to.sa_nodenum[4] = *(ULPWORD)&pPacket->Destination.Node[4];
+
+ //
+ // copy the destination socket number from the IPX packet header as a
+ // WORD (2 bytes). Again, the aligned pointer will save us
+ //
+
+ to.sa_socket = pPacket->Destination.Socket;
+
+ type = (int)pPacket->PacketType;
+ rc = setsockopt(pSocketInfo->Socket,
+ NSPROTO_IPX,
+ IPX_PTYPE,
+ (char FAR*)&type,
+ sizeof(type)
+ );
+ if (rc) {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_ERROR,
+ "IpxSendNext: setsockopt(IPX_PTYPE) returns %d\n",
+ WSAGetLastError()
+ ));
+
+ }
+ rc = sendto(pSocketInfo->Socket,
+ (char FAR*)pPacket,
+ length,
+ 0, // flags
+ (LPSOCKADDR)&to,
+ sizeof(to)
+ );
+ if (rc == length) {
+
+ //
+ // all data sent - dequeue it
+ //
+
+
+ IPXDUMPDATA((pXecb->Buffer, 0, 0, FALSE, (WORD)rc));
+
+ DequeueEcb(pXecb, &pSocketInfo->SendQueue);
+ if (pXecb->EsrAddress) {
+ if (pXecb->Flags & XECB_FLAG_BUFFER_ALLOCATED) {
+ ReleaseIoBuffer(pXecb);
+ }
+ QueueAsyncCompletion(pXecb, ECB_CC_SUCCESS);
+ } else {
+ CompleteIo(pXecb, ECB_CC_SUCCESS);
+ }
+ if (pSocketInfo->Flags & SOCKET_FLAG_TEMPORARY) {
+ KillSocket(pSocketInfo);
+ }
+ } else if (rc == SOCKET_ERROR) {
+
+ //
+ // if the socket is still blocked, there's nothing to do - just leave
+ // the request hanging around till next time
+ //
+
+ rc = WSAGetLastError();
+ if (rc != WSAEWOULDBLOCK) {
+ DequeueSendRequest(pXecb, pSocketInfo);
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_ERROR,
+ "IpxSendNext: sendto() returns %d\n",
+ rc
+ ));
+
+ //
+ // BUGBUG: couple of possible completion codes here
+ //
+
+ CompleteIo(pXecb, ECB_CC_UNDELIVERABLE);
+ if (pSocketInfo->Flags & SOCKET_FLAG_TEMPORARY) {
+ KillSocket(pSocketInfo);
+ }
+ }
+ } else {
+
+ //
+ // BUGBUG: Is 0 a valid value for rc?
+ //
+
+ //
+ // send should send all the data or return an error
+ //
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_FATAL,
+ "IpxSendNext: sendto() returns unexpected %d (length = %d)\n",
+ rc,
+ length
+ ));
+ }
+}
+
+
+PRIVATE
+VOID
+QueueReceiveRequest(
+ IN LPXECB pXecb,
+ IN LPSOCKET_INFO pSocketInfo
+ )
+
+/*++
+
+Routine Description:
+
+ Add a listen XECB to queue of listen XECBs on a SOCKET_INFO structure
+
+Arguments:
+
+ pXecb - pointer to listen XECB to queue
+ pSocketInfo - pointer to SOCKET_INFO structure
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ QueueEcb(pXecb, &pSocketInfo->ListenQueue, SOCKET_LISTEN_QUEUE);
+ ++pSocketInfo->PendingListens;
+ pSocketInfo->Flags |= SOCKET_FLAG_LISTENING;
+}
+
+
+PRIVATE
+LPXECB
+DequeueReceiveRequest(
+ IN LPXECB pXecb,
+ IN LPSOCKET_INFO pSocketInfo
+ )
+
+/*++
+
+Routine Description:
+
+ Remove a listen XECB from queue of listen XECBs on a SOCKET_INFO structure
+
+Arguments:
+
+ pXecb - pointer to listen XECB to dequeue
+ pSocketInfo - pointer to SOCKET_INFO structure
+
+Return Value:
+
+ LPXECB
+
+--*/
+
+{
+ LPXECB ptr;
+
+ ptr = (LPXECB)DequeueEcb(pXecb, &pSocketInfo->ListenQueue);
+ if (ptr) {
+
+ ASSERT(ptr == pXecb);
+
+ --pSocketInfo->PendingListens;
+ if (!pSocketInfo->PendingListens) {
+ pSocketInfo->Flags &= ~SOCKET_FLAG_LISTENING;
+ }
+
+ //
+ // BUGBUG: Is this correct value?
+ //
+
+ pXecb->Ecb->InUse = ECB_IU_AWAITING_PROCESSING;
+ }
+ return ptr;
+}
+
+
+PRIVATE
+VOID
+QueueSendRequest(
+ IN LPXECB pXecb,
+ IN LPSOCKET_INFO pSocketInfo
+ )
+
+/*++
+
+Routine Description:
+
+ Add a send XECB to queue of send XECBs on a SOCKET_INFO structure
+
+Arguments:
+
+ pXecb - pointer to send XECB to queue
+ pSocketInfo - pointer to SOCKET_INFO structure
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ QueueEcb(pXecb, &pSocketInfo->SendQueue, SOCKET_SEND_QUEUE);
+ ++pSocketInfo->PendingSends;
+ pSocketInfo->Flags |= SOCKET_FLAG_SENDING;
+ pXecb->Ecb->InUse = ECB_IU_SEND_QUEUED;
+}
+
+
+PRIVATE
+LPXECB
+DequeueSendRequest(
+ IN LPXECB pXecb,
+ IN LPSOCKET_INFO pSocketInfo
+ )
+
+/*++
+
+Routine Description:
+
+ Remove a send XECB from queue of send XECBs on a SOCKET_INFO structure
+
+Arguments:
+
+ pXecb - pointer to send XECB to dequeue
+ pSocketInfo - pointer to SOCKET_INFO structure
+
+Return Value:
+
+ LPXECB
+
+--*/
+
+{
+ LPXECB ptr;
+
+ ptr = (LPXECB)DequeueEcb(pXecb, &pSocketInfo->SendQueue);
+ if (ptr) {
+
+ ASSERT(ptr == pXecb);
+
+ --pSocketInfo->PendingSends;
+ if (!pSocketInfo->PendingSends) {
+ pSocketInfo->Flags &= ~SOCKET_FLAG_SENDING;
+ }
+ pXecb->Ecb->InUse = ECB_IU_AWAITING_PROCESSING;
+ }
+ return ptr;
+}
+
+
+VOID
+CompleteOrQueueIo(
+ IN LPXECB pXecb,
+ IN BYTE CompletionCode
+ )
+
+/*++
+
+Routine Description:
+
+ Returns any allocated buffer resource then completes or queues the ECB
+
+Arguments:
+
+ pXecb - pointer to XECB structure
+ CompletionCode - value to put in CompletionCode field
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // if we allocated a buffer, free it
+ //
+
+ if (pXecb->Flags & XECB_FLAG_BUFFER_ALLOCATED) {
+ ReleaseIoBuffer(pXecb);
+ }
+ CompleteOrQueueEcb(pXecb, CompletionCode);
+}
+
+
+VOID
+CompleteIo(
+ IN LPXECB pXecb,
+ IN BYTE CompletionCode
+ )
+
+/*++
+
+Routine Description:
+
+ Completes a send/receive request by returning any allocated buffer resource
+ and setting the ECB InUse and CompletionCode fields
+
+Arguments:
+
+ pXecb - pointer to XECB structure
+ CompletionCode - value to put in CompletionCode field
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // if we allocated a buffer, free it
+ //
+
+ if (pXecb->Flags & XECB_FLAG_BUFFER_ALLOCATED) {
+ ReleaseIoBuffer(pXecb);
+ }
+ CompleteEcb(pXecb, CompletionCode);
+}
+
+
+VOID
+CompleteOrQueueEcb(
+ IN LPXECB pXecb,
+ IN BYTE CompletionCode
+ )
+
+/*++
+
+Routine Description:
+
+ Queues an XECB for completion by ESR or completes it now
+
+Arguments:
+
+ pXecb - pointer to XECB describing ECB to complete
+ CompletionCode - value to put in ECB CompletionCode field
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ if (pXecb->EsrAddress) {
+ QueueAsyncCompletion(pXecb, CompletionCode);
+ } else {
+ CompleteIo(pXecb, CompletionCode);
+ }
+}
+
+
+VOID
+CompleteEcb(
+ IN LPXECB pXecb,
+ IN BYTE CompletionCode
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the CompletionCode field in the ECB and sets the InUse field to 0.
+ Deallocates the XECB structure
+
+Arguments:
+
+ pXecb - pointer to XECB describing ECB in 16-bit memory to update
+ CompletionCode - value to put in CompletionCode field
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LPIPX_ECB pEcb = (LPIPX_ECB)pXecb->Ecb;
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_INFO,
+ "CompleteEcb: completing ECB @%04x:%04x w/ %02x\n",
+ HIWORD(pXecb->EcbAddress),
+ LOWORD(pXecb->EcbAddress),
+ CompletionCode
+ ));
+
+ //
+ // if this is really an AES ECB then CompletionCode is actually the first
+ // byte of the AES workspace. It shouldn't matter that we write into this
+ // field - we are supposed to own it
+ //
+
+ pEcb->CompletionCode = CompletionCode;
+ pEcb->InUse = ECB_IU_NOT_IN_USE;
+
+ //
+ // reset the LinkAddress field. This means we have completed the ECB
+ //
+
+ pEcb->LinkAddress = NULL;
+
+ //
+ // finally, deallocate the XECB. This mustn't have any allocated resources
+ // (like a buffer)
+ //
+
+ DeallocateXecb(pXecb);
+}
+
+
+PRIVATE
+VOID
+QueueAsyncCompletion(
+ IN LPXECB pXecb,
+ IN BYTE CompletionCode
+ )
+
+/*++
+
+Routine Description:
+
+ Add an XECB to the (serialized) async completion queue and raise a simulated
+ hardware interrupt in the VDM.
+
+ The interrupt will cause the VDM to start executing at the ISR in the TSR
+ which will call-back to find the address for the ESR, then execute it
+
+Arguments:
+
+ pXecb - pointer to XECB describing IPX or AES ECB to add to async
+ completion list
+ CompletionCode - the ECB in VDM memory will be updated with this completion
+ code
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_INFO,
+ "QueueAsyncCompletion: completing ECB @%04x:%04x w/ %02x\n",
+ HIWORD(pXecb->EcbAddress),
+ LOWORD(pXecb->EcbAddress),
+ CompletionCode
+ ));
+
+ pXecb->Ecb->CompletionCode = CompletionCode;
+ pXecb->QueueId = ASYNC_COMPLETION_QUEUE;
+ EnterCriticalSection(&AsyncCritSec);
+ FifoAdd(&AsyncCompletionQueue, (LPFIFO)pXecb);
+ LeaveCriticalSection(&AsyncCritSec);
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_INFO,
+ "QueueAsyncCompletion: ECB @ %04x:%04x ESR @ %04x:%04x\n",
+ HIWORD(pXecb->EcbAddress),
+ LOWORD(pXecb->EcbAddress),
+ HIWORD(pXecb->EsrAddress),
+ LOWORD(pXecb->EsrAddress)
+ ));
+
+ VDDSimulateInterrupt(Ica, IcaLine, 1);
+}
+
+
+VOID
+EsrCallback(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Callback function from within 16-bit TSR ESR function. Returns the address
+ of the next completed ECB in ES:SI
+
+ Any allocated resources (e.g. 32-bit buffer) must have been freed by the
+ time the ESR callback happens
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ WORD segment = 0;
+ WORD offset = 0;
+ BYTE flags;
+
+ VWinEsrCallback( &segment, &offset, &flags );
+
+ setES(segment);
+ setSI(offset);
+ setAL(flags);
+}
+
+
+VOID
+VWinEsrCallback(
+ WORD *pSegment,
+ WORD *pOffset,
+ BYTE *pFlags
+ )
+
+/*++
+
+Routine Description:
+
+ Callback function from within 16-bit function. Returns the address
+ of the next completed ECB
+
+ Any allocated resources (e.g. 32-bit buffer) must have been freed by the
+ time the ESR callback happens
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LPXECB pXecb;
+
+ EnterCriticalSection(&AsyncCritSec);
+ pXecb = AsyncCompletionQueue.Head;
+ if (pXecb) {
+
+ WORD msw = getMSW();
+
+ if ((msw & MSW_PE) ^ IS_PROT_MODE(pXecb)) {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_INFO,
+ "EsrCallback: ECB @ %04x:%04x NOT for this proc mode (%d)\n",
+ HIWORD(pXecb->EcbAddress),
+ LOWORD(pXecb->EcbAddress),
+ msw & MSW_PE
+ ));
+
+ pXecb = NULL;
+ } else {
+ pXecb = (LPXECB)FifoNext(&AsyncCompletionQueue);
+ }
+ } else {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_FATAL,
+ "EsrCallback: no ECBs on AsyncCompletionQueue!\n"
+ ));
+
+ }
+ LeaveCriticalSection(&AsyncCritSec);
+
+ if (pXecb) {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_INFO,
+ "EsrCallback: ECB @ %04x:%04x ESR @ %04x:%04x\n",
+ HIWORD(pXecb->EcbAddress),
+ LOWORD(pXecb->EcbAddress),
+ HIWORD(pXecb->EsrAddress),
+ LOWORD(pXecb->EsrAddress)
+ ));
+
+ *pSegment = HIWORD(pXecb->EcbAddress);
+ *pOffset = LOWORD(pXecb->EcbAddress);
+ pXecb->Ecb->LinkAddress = NULL;
+ pXecb->Ecb->InUse = ECB_IU_NOT_IN_USE;
+ *pFlags = (BYTE)((pXecb->Flags & XECB_FLAG_IPX) ? ECB_TYPE_IPX : ECB_TYPE_AES);
+ DeallocateXecb(pXecb);
+ setCF(0);
+ } else {
+ setCF(1);
+ }
+}
+
+
+VOID
+FifoAddHead(
+ IN LPFIFO pFifo,
+ IN LPFIFO pElement
+ )
+
+/*++
+
+Routine Description:
+
+ Adds an element to the head of a (single-linked) FIFO list
+
+Arguments:
+
+ pFifo - pointer to FIFO structure
+ pElement - pointer to (FIFO) element to add to list
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ if (!pFifo->Head) {
+ pFifo->Head = pFifo->Tail = pElement;
+ pElement->Head = NULL;
+ } else {
+ pElement->Head = pFifo->Head;
+ pFifo->Head = pElement;
+ }
+}
+
+VOID
+FifoAdd(
+ IN LPFIFO pFifo,
+ IN LPFIFO pElement
+ )
+
+/*++
+
+Routine Description:
+
+ Adds an element to the tail of a (single-linked) FIFO list
+
+Arguments:
+
+ pFifo - pointer to FIFO structure
+ pElement - pointer to (FIFO) element to add to list
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ if (!pFifo->Head) {
+ pFifo->Head = pFifo->Tail = pElement;
+ } else {
+ ((LPFIFO)pFifo->Tail)->Head = pElement;
+ }
+ pFifo->Tail = pElement;
+ pElement->Head = NULL;
+}
+
+
+LPFIFO
+FifoRemove(
+ IN LPFIFO pFifo,
+ IN LPFIFO pElement
+ )
+
+/*++
+
+Routine Description:
+
+ Removes an element from a (single-linked) FIFO list
+
+Arguments:
+
+ pFifo - pointer to FIFO structure
+ pElement - pointer to (FIFO) element to remove (single-linked)
+
+Return Value:
+
+ PFIFO
+ NULL - pElement not on list
+ !NULL - pElement removed from list
+
+--*/
+
+{
+ LPFIFO p;
+ LPFIFO prev = (LPFIFO)pFifo;
+
+ p = (LPFIFO)pFifo->Head;
+ while (p && (p != pElement)) {
+ prev = p;
+ p = p->Head;
+ }
+ if (p) {
+ prev->Head = p->Head;
+ if (pFifo->Head == NULL) {
+ pFifo->Tail = NULL;
+ } else if (pFifo->Tail == p) {
+ pFifo->Tail = prev;
+ }
+ }
+ return p;
+}
+
+
+LPFIFO
+FifoNext(
+ IN LPFIFO pFifo
+ )
+
+/*++
+
+Routine Description:
+
+ Remove element at head of FIFO queue
+
+Arguments:
+
+ pFifo - pointer to FIFO
+
+Return Value:
+
+ LPFIFO
+ NULL - nothing on queue
+ !NULL - removed element
+
+--*/
+
+{
+ LPFIFO p;
+ LPFIFO prev = (LPFIFO)pFifo;
+
+ p = (LPFIFO)pFifo->Head;
+ if (p) {
+ pFifo->Head = p->Head;
+ if (!pFifo->Head) {
+ pFifo->Tail = NULL;
+ }
+ }
+ return p;
+}
diff --git a/private/nw/vwipxspx/dll/util.h b/private/nw/vwipxspx/dll/util.h
new file mode 100644
index 000000000..d75781952
--- /dev/null
+++ b/private/nw/vwipxspx/dll/util.h
@@ -0,0 +1,233 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ util.h
+
+Abstract:
+
+ Contains macros, prototypes and structures for util.c
+
+Author:
+
+ Richard L Firth (rfirth) 25-Oct-1993
+
+Revision History:
+
+ 25-Oct-1993 rfirth
+ Created
+
+--*/
+
+//
+// external data
+//
+
+extern CRITICAL_SECTION SerializationCritSec;
+
+//
+// one-line function macros
+//
+
+#define RequestMutex() EnterCriticalSection(&SerializationCritSec)
+#define ReleaseMutex() LeaveCriticalSection(&SerializationCritSec)
+
+//
+// function prototypes
+//
+
+int
+GetInternetAddress(
+ IN OUT LPSOCKADDR_IPX InternetAddress
+ );
+
+int
+GetMaxPacketSize(
+ OUT LPWORD MaxPacketSize
+ );
+
+LPXECB
+RetrieveEcb(
+ IN BYTE Type
+ );
+
+LPXECB
+RetrieveXEcb(
+ IN BYTE Type,
+ IN LPECB pEcb,
+ IN ECB_ADDRESS EcbAddress
+ );
+
+VOID
+ScheduleEvent(
+ IN LPXECB pXecb,
+ IN WORD Ticks
+ );
+
+VOID
+ScanTimerList(
+ VOID
+ );
+
+BYTE
+CancelTimerEvent(
+ IN LPXECB pXecb
+ );
+
+VOID
+CancelTimedEvents(
+ IN WORD SocketNumber,
+ IN WORD Owner,
+ IN DWORD TaskId
+ );
+
+BYTE
+CancelAsyncEvent(
+ IN LPXECB pXecb
+ );
+
+BYTE
+CancelSocketEvent(
+ IN LPXECB pXecb
+ );
+
+BYTE
+CancelConnectionEvent(
+ IN LPXECB pXecb
+ );
+
+VOID
+QueueEcb(
+ IN LPXECB pXecb,
+ IN LPXECB_QUEUE Queue,
+ IN QUEUE_ID QueueId
+ );
+
+LPXECB
+DequeueEcb(
+ IN LPXECB pXecb,
+ IN LPXECB_QUEUE Queue
+ );
+
+VOID
+CancelSocketQueue(
+ IN LPXECB_QUEUE pXecbQueue
+ );
+
+VOID
+CancelConnectionQueue(
+ IN LPXECB_QUEUE pXecbQueue
+ );
+
+VOID
+AbortQueue(
+ IN LPXECB_QUEUE pXecbQueue,
+ IN BYTE CompletionCode
+ );
+
+VOID
+AbortConnectionEvent(
+ IN LPXECB pXecb,
+ IN BYTE CompletionCode
+ );
+
+VOID
+StartIpxSend(
+ IN LPXECB pEcb,
+ IN LPSOCKET_INFO pSocketInfo
+ );
+
+BOOL
+GetIoBuffer(
+ IN OUT LPXECB pXecb,
+ IN BOOL Send,
+ IN WORD HeaderLength
+ );
+
+VOID
+GatherData(
+ IN LPXECB pXecb,
+ IN WORD HeaderLength
+ );
+
+VOID
+ScatterData(
+ IN LPXECB pXecb
+ );
+
+VOID
+IpxReceiveFirst(
+ IN LPXECB pXecb,
+ IN LPSOCKET_INFO pSocketInfo
+ );
+
+VOID
+IpxReceiveNext(
+ IN LPSOCKET_INFO pSocketInfo
+ );
+
+VOID
+IpxSendNext(
+ IN LPSOCKET_INFO pSocketInfo
+ );
+
+VOID
+CompleteOrQueueIo(
+ IN LPXECB pXecb,
+ IN BYTE CompletionCode
+ );
+
+VOID
+CompleteIo(
+ IN LPXECB pXecb,
+ IN BYTE CompletionCode
+ );
+
+VOID
+CompleteOrQueueEcb(
+ IN LPXECB pXecb,
+ IN BYTE CompletionCode
+ );
+
+VOID
+CompleteEcb(
+ IN LPXECB pEcb,
+ IN BYTE CompletionCode
+ );
+
+VOID
+EsrCallback(
+ VOID
+ );
+
+VOID
+VWinEsrCallback(
+ WORD *pSegment,
+ WORD *pOffset,
+ BYTE *pFlags
+ );
+
+VOID
+FifoAddHead(
+ IN LPFIFO pFifo,
+ IN LPFIFO pElement
+ );
+
+VOID
+FifoAdd(
+ IN LPFIFO pFifo,
+ IN LPFIFO pElement
+ );
+
+LPFIFO
+FifoRemove(
+ IN LPFIFO pFifo,
+ IN LPFIFO pElement
+ );
+
+LPFIFO
+FifoNext(
+ IN LPFIFO pFifo
+ );
diff --git a/private/nw/vwipxspx/dll/vw.h b/private/nw/vwipxspx/dll/vw.h
new file mode 100644
index 000000000..e14ec83e0
--- /dev/null
+++ b/private/nw/vwipxspx/dll/vw.h
@@ -0,0 +1,57 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ vw.h
+
+Abstract:
+
+ Top-level include file for VWIPXSPX DLL. Pulls in all other required header
+ files
+
+Author:
+
+ Richard L Firth (rfirth) 25-Oct-1993
+
+Revision History:
+
+ 25-Oct-1993 rfirth
+ Created
+
+--*/
+
+//
+// all include files required by VWIPXSPX.DLL
+//
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#include <windows.h>
+#define FD_SETSIZE MAX_OPEN_SOCKETS
+#include <winsock.h>
+#include <wsipx.h>
+#include <wsnwlink.h>
+#include <vddsvc.h> // GetVDMAddress, GetVDMPointer
+#undef getMSW // BUGBUG: there's no c_getMSW in the lib!!!
+
+extern WORD getMSW(VOID);
+
+#include "vwvdm.h"
+#include "vwdll.h"
+#include "vwipxspx.h"
+#include "vwasync.h"
+#include "vwmisc.h"
+#include "vwipx.h"
+#include "vwspx.h"
+#include "socket.h"
+#include "util.h"
+#include "vwdebug.h"
+#include "vwinapi.h"
+#include "vwint.h"
diff --git a/private/nw/vwipxspx/dll/vwasync.c b/private/nw/vwipxspx/dll/vwasync.c
new file mode 100644
index 000000000..686d05816
--- /dev/null
+++ b/private/nw/vwipxspx/dll/vwasync.c
@@ -0,0 +1,167 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ vwasync.c
+
+Abstract:
+
+ ntVdm netWare (Vw) IPX/SPX Functions
+
+ Vw: The peoples' network
+
+ Contains Asyncrhonous Event Scheduler (thread)
+
+ Contents:
+ VwAesThread
+ (CheckPendingIpxRequests)
+
+Author:
+
+ Richard L Firth (rfirth) 30-Sep-1993
+
+Environment:
+
+ User-mode Win32
+
+Revision History:
+
+ 30-Sep-1993 rfirth
+ Created
+
+--*/
+
+#include "vw.h"
+#pragma hdrstop
+
+//
+// private routine prototypes
+//
+
+PRIVATE
+VOID
+CheckPendingIpxRequests(
+ VOID
+ );
+
+//
+// global data
+//
+
+WORD AesTickCount;
+
+//
+// functions
+//
+
+
+DWORD
+VwAesThread(
+ IN LPVOID Parameters
+ )
+
+/*++
+
+Routine Description:
+
+ Provides the functionality of the Asynchronous Event Scheduler (AES) in the
+ Netware world:
+
+ - updates the tick count
+ - completes any matured timer events
+ - checks any pending requests and schedules the next action
+
+ This thread wakes up every PC tick (1/18 second)
+
+Arguments:
+
+ Parameters - unused
+
+Return Value:
+
+ DWORD
+ 0
+
+--*/
+
+{
+ BOOL fOperationPerformed = FALSE ;
+ static int n = 1 ;
+
+ UNREFERENCED_PARAMETER(Parameters);
+
+ while (TRUE)
+ {
+ //
+ // we will always yield in this loop to be friendly to others,
+ // but occasionally we will forcefully do a non zero sleep for
+ // lower priority threads to run.
+ //
+ if ((n % 100) == 0)
+ {
+ Sleep(ONE_TICK) ;
+ n = 1 ;
+ }
+ if (!fOperationPerformed && ((n % 4) == 0))
+ {
+ Sleep(10) ;
+ n++ ;
+ }
+ else
+ {
+ Sleep(0) ;
+ n++ ;
+ }
+
+ ++AesTickCount;
+ ScanTimerList();
+ CheckPendingIpxRequests();
+ CheckPendingSpxRequests(&fOperationPerformed);
+ }
+
+ return 0; // compiler-pacifier
+}
+
+
+PRIVATE
+VOID
+CheckPendingIpxRequests(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Polls the opened, active non-blocking IPX sockets to see if there is anything
+ to do (data to receive, availability to send, timeouts)
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LPSOCKET_INFO pActiveSocket = NULL;
+
+ //
+ // search SOCKET_INFO structures for something to do. Could do select()
+ // but we have most of the info anyway. We use the BFI filter mechanism
+ //
+
+ while (pActiveSocket = FindActiveSocket(pActiveSocket)) {
+ if (pActiveSocket->Flags & SOCKET_FLAG_SENDING) {
+ IpxSendNext(pActiveSocket);
+ }
+ if (pActiveSocket->Flags & SOCKET_FLAG_LISTENING) {
+ IpxReceiveNext(pActiveSocket);
+ }
+ }
+}
diff --git a/private/nw/vwipxspx/dll/vwasync.h b/private/nw/vwipxspx/dll/vwasync.h
new file mode 100644
index 000000000..4c4bd4779
--- /dev/null
+++ b/private/nw/vwipxspx/dll/vwasync.h
@@ -0,0 +1,27 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ vwipx.h
+
+Abstract:
+
+ Contains function prototypes for VWASYNC.C
+
+Author:
+
+ Richard L Firth (rfirth) 25-Oct-1993
+
+Revision History:
+
+ 25-Oct-1993 rfirth
+ Created
+
+--*/
+
+DWORD
+VwAesThread(
+ IN LPVOID Parameters
+ );
diff --git a/private/nw/vwipxspx/dll/vwdebug.c b/private/nw/vwipxspx/dll/vwdebug.c
new file mode 100644
index 000000000..5aa94c933
--- /dev/null
+++ b/private/nw/vwipxspx/dll/vwdebug.c
@@ -0,0 +1,825 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ vwdebug.c
+
+Abstract:
+
+ Contains debug routines for VWIPXSPX.DLL
+
+ Contents:
+ VwDebugStart
+ VwDebugEnd
+ VwDebugPrint
+ VwDumpData
+ VwDumpEcb
+ VwDumpFragment
+ VwDumpPacketHeader
+ VwDumpXecb
+ VwDumpSocketInfo
+ VwDumpConnectionInfo
+ VwDumpConnectionStats
+ VwLog
+ CheckInterrupts
+
+Author:
+
+ Richard L Firth (rfirth) 5-Oct-1993
+
+Environment:
+
+ User-mode Win32
+
+Revision History:
+
+ 5-Oct-1993 rfirth
+ Created
+
+--*/
+
+#include "vw.h"
+#pragma hdrstop
+
+#if DBG
+
+//
+// private prototypes
+//
+
+int PokeLevelString(LPSTR, DWORD, DWORD, LPSTR);
+LPSTR StripNameFromPath(LPSTR);
+
+//
+// private data
+//
+
+DWORD VwDebugFlags = 0;
+DWORD VwDebugFunctions = 0;
+DWORD VwShow = SHOW_ECBS | SHOW_HEADERS;
+DWORD VwDebugLevel = IPXDBG_MIN_LEVEL;
+DWORD VwDebugDump = 0;
+BOOL VwDebugInitialized = FALSE;
+FILE* hVwDebugLog = NULL;
+DWORD DebugFlagsEx = 0 ;
+
+//
+// functions
+//
+
+VOID VwDebugStart() {
+
+ //
+ // a little run-time diagnostication, madam?
+ //
+
+ LPSTR ptr;
+
+ if (VwDebugInitialized) {
+ return;
+ }
+
+ //
+ // override VwDebugFlags from VWFLAGS environment variable
+ //
+
+ if (ptr = getenv("VWFLAGS")) {
+ VwDebugFlags = (DWORD)strtoul(ptr, NULL, 0);
+ }
+ if (ptr = getenv("VWFUNCS")) {
+ VwDebugFunctions = (DWORD)strtoul(ptr, NULL, 0);
+ }
+ if (ptr = getenv("VWSHOW")) {
+ VwShow = (DWORD)strtoul(ptr, NULL, 0);
+ }
+ if (ptr = getenv("VWLEVEL")) {
+ VwDebugLevel = strtoul(ptr, NULL, 0);
+ if (VwDebugLevel > IPXDBG_MAX_LEVEL) {
+ VwDebugLevel = IPXDBG_MAX_LEVEL;
+ }
+ }
+ if (ptr = getenv("VWDUMP")) {
+ VwDebugDump = strtoul(ptr, NULL, 0);
+ }
+ IF_DEBUG(TO_FILE) {
+ if ((hVwDebugLog = fopen(VWDEBUG_FILE, "w+")) == NULL) {
+ VwDebugFlags &= ~DEBUG_TO_FILE;
+ } else {
+
+#if 0
+
+ char currentDirectory[256];
+ int n;
+
+ currentDirectory[0] = 0;
+ if (n = GetCurrentDirectory(sizeof(currentDirectory), currentDirectory)) {
+ if (currentDirectory[n-1] == '\\') {
+ currentDirectory[n-1] = 0;
+ }
+ }
+
+ DbgPrint("VWIPXSPX: Writing debug output to %s\\" VWDEBUG_FILE "\n", currentDirectory);
+#endif
+
+ }
+ }
+ VwDebugInitialized = TRUE;
+}
+
+VOID VwDebugEnd() {
+ IF_DEBUG(TO_FILE) {
+ fflush(hVwDebugLog);
+ fclose(hVwDebugLog);
+ }
+}
+
+VOID VwDebugPrint(LPSTR Module, DWORD Line, DWORD Function, DWORD Level, LPSTR Format, ...) {
+
+ char buf[1024];
+ va_list p;
+
+ IF_DEBUG(NOTHING) {
+ return;
+ }
+
+ //
+ // only log something if we are tracking this Function and Level is above
+ // (or equal to) the filter cut-off or Level >= minimum alert level (error)
+ //
+
+ if (((Function & VwDebugFunctions) && (Level >= VwDebugLevel)) || (Level >= IPXDBG_LEVEL_ERROR)) {
+ va_start(p, Format);
+ vsprintf(buf+PokeLevelString(Module, Line, Level, buf), Format, p);
+ VwLog(buf);
+ va_end(p);
+ }
+}
+
+int PokeLevelString(LPSTR Module, DWORD Line, DWORD Level, LPSTR Buffer) {
+
+ int length;
+ static char levelString[4] = " : ";
+ char level;
+
+ switch (Level) {
+ case IPXDBG_LEVEL_INFO:
+ level = 'I';
+ break;
+
+ case IPXDBG_LEVEL_WARNING:
+ level = 'W';
+ break;
+
+ case IPXDBG_LEVEL_ERROR:
+ level = 'E';
+ break;
+
+ case IPXDBG_LEVEL_FATAL:
+ level = 'F';
+ break;
+ }
+
+ levelString[0] = level;
+ strcpy(Buffer, levelString);
+ length = strlen(levelString);
+
+ if (Level >= IPXDBG_LEVEL_ERROR) {
+ length += sprintf(Buffer + length, "%s [% 5d]: ", StripNameFromPath(Module), Line);
+ }
+
+ return length;
+}
+
+LPSTR StripNameFromPath(LPSTR Path) {
+
+ LPSTR p;
+
+ p = strrchr(Path, '\\');
+ return p ? p+1 : Path;
+}
+
+VOID VwDumpData(ULPBYTE Address, WORD Seg, WORD Off, BOOL InVdm, WORD Size) {
+
+ char buf[128];
+ int i, len;
+
+ IF_NOT_DEBUG(DATA) {
+ return;
+ }
+
+ while (Size) {
+ len = min(Size, 16);
+ if (InVdm) {
+ sprintf(buf, "%04x:%04x ", Seg, Off);
+ } else {
+ sprintf(buf, "%08x ", Address);
+ }
+ for (i = 0; i < len; ++i) {
+ sprintf(&buf[10+i*3], "%02.2x ", Address[i] & 0xff);
+ }
+ for (i = len; i < 17; ++i) {
+ strcat(buf, " ");
+ }
+ for (i = 0; i < len; ++i) {
+
+ char ch;
+
+ ch = Address[i];
+ buf[61+i] = ((ch < 32) || (ch > 127)) ? '.' : ch;
+ }
+ buf[61+i++] = '\n';
+ buf[61+i] = 0;
+ VwLog(buf);
+ Address += len;
+ Size -= len;
+ Off += len;
+ }
+ VwLog("\n");
+}
+
+VOID VwDumpEcb(LPECB pEcb, WORD Seg, WORD Off, BYTE Type, BOOL Frags, BOOL Data, BOOL Mode) {
+
+ char buf[512];
+ int n;
+ char* bufptr;
+
+ IF_NOT_DEBUG(ECB) {
+ return;
+ }
+
+ IF_NOT_SHOW(ECBS) {
+ VwDumpData((ULPBYTE)pEcb,
+ Seg,
+ Off,
+ TRUE,
+ (WORD)((Type == ECB_TYPE_AES)
+ ? sizeof(AES_ECB)
+ : (sizeof(IPX_ECB) + sizeof(FRAGMENT) * (pEcb->FragmentCount - 1)))
+ );
+ return;
+ }
+
+ n = sprintf(buf,
+ "\n"
+ "%s ECB @ %04x:%04x:\n"
+ "LinkAddress %04x:%04x\n"
+ "EsrAddress %04x:%04x\n"
+ "InUse %02x\n",
+ (Type == ECB_TYPE_AES)
+ ? "AES"
+ : (Type == ECB_TYPE_IPX)
+ ? "IPX"
+ : "SPX",
+ Seg,
+ Off,
+ GET_SEGMENT(&pEcb->LinkAddress),
+ GET_OFFSET(&pEcb->LinkAddress),
+ GET_SEGMENT(&pEcb->EsrAddress),
+ GET_OFFSET(&pEcb->EsrAddress),
+ pEcb->InUse
+ );
+ bufptr = buf + n;
+ if (Type == ECB_TYPE_AES) {
+ sprintf(bufptr,
+ "AesWorkspace %02x-%02x-%02x-%02x-%02x\n",
+ ((LPAES_ECB)pEcb)->AesWorkspace[0] & 0xff,
+ ((LPAES_ECB)pEcb)->AesWorkspace[1] & 0xff,
+ ((LPAES_ECB)pEcb)->AesWorkspace[2] & 0xff,
+ ((LPAES_ECB)pEcb)->AesWorkspace[3] & 0xff,
+ ((LPAES_ECB)pEcb)->AesWorkspace[4] & 0xff
+ );
+ } else {
+ sprintf(bufptr,
+ "CompletionCode %02x\n"
+ "SocketNumber %04x\n"
+ "IpxWorkspace %08x\n"
+ "DriverWorkspace %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n"
+ "ImmediateAddress %02x-%02x-%02x-%02x-%02x-%02x\n"
+ "FragmentCount %04x\n",
+ pEcb->CompletionCode,
+ B2LW(pEcb->SocketNumber),
+ pEcb->IpxWorkspace,
+ pEcb->DriverWorkspace[0] & 0xff,
+ pEcb->DriverWorkspace[1] & 0xff,
+ pEcb->DriverWorkspace[2] & 0xff,
+ pEcb->DriverWorkspace[3] & 0xff,
+ pEcb->DriverWorkspace[4] & 0xff,
+ pEcb->DriverWorkspace[5] & 0xff,
+ pEcb->DriverWorkspace[6] & 0xff,
+ pEcb->DriverWorkspace[7] & 0xff,
+ pEcb->DriverWorkspace[8] & 0xff,
+ pEcb->DriverWorkspace[9] & 0xff,
+ pEcb->DriverWorkspace[10] & 0xff,
+ pEcb->DriverWorkspace[11] & 0xff,
+ pEcb->ImmediateAddress[0] & 0xff,
+ pEcb->ImmediateAddress[1] & 0xff,
+ pEcb->ImmediateAddress[2] & 0xff,
+ pEcb->ImmediateAddress[3] & 0xff,
+ pEcb->ImmediateAddress[4] & 0xff,
+ pEcb->ImmediateAddress[5] & 0xff,
+ pEcb->FragmentCount
+ );
+ }
+
+ VwLog(buf);
+
+ if ((Type != ECB_TYPE_AES) && Frags) {
+
+ ASSERT(pEcb->FragmentCount < 10);
+
+ VwDumpFragment(pEcb->FragmentCount,
+ (LPFRAGMENT)(pEcb + 1),
+ Type,
+ Data,
+ Mode
+ );
+ }
+}
+
+VOID VwDumpFragment(WORD Count, LPFRAGMENT pFrag, BYTE Type, BOOL Data, BOOL Mode) {
+
+ char buf[256];
+ int i;
+
+ IF_NOT_DEBUG(FRAGMENTS) {
+ return;
+ }
+
+ for (i = 0; i < Count; ++i) {
+ sprintf(buf,
+ "Fragment %d:\n"
+ " Address %04x:%04x\n"
+ " Length %04x\n",
+ i + 1,
+ GET_SEGMENT(&pFrag->Address),
+ GET_OFFSET(&pFrag->Address),
+ pFrag->Length
+ );
+ VwLog(buf);
+ if (Data) {
+
+ ULPBYTE ptr;
+ WORD size;
+ WORD offset;
+
+ ptr = GET_FAR_POINTER(&pFrag->Address, Mode);
+ size = pFrag->Length;
+ offset = GET_OFFSET(&pFrag->Address);
+
+ //
+ // this allows us to show headers vs. raw data
+ //
+
+ IF_SHOW(HEADERS) {
+ if (i == 0) {
+ VwDumpPacketHeader(ptr, Type);
+
+ if (Type == ECB_TYPE_IPX) {
+ ptr += IPX_HEADER_LENGTH;
+ size -= IPX_HEADER_LENGTH;
+ offset += IPX_HEADER_LENGTH;
+ } else {
+ ptr += SPX_HEADER_LENGTH;
+ size -= SPX_HEADER_LENGTH;
+ offset += SPX_HEADER_LENGTH;
+ }
+ }
+ }
+
+ VwDumpData(ptr,
+ GET_SEGMENT(&pFrag->Address),
+ offset,
+ TRUE,
+ size
+ );
+ }
+ ++pFrag;
+ }
+}
+
+VOID VwDumpPacketHeader(ULPBYTE pPacket, BYTE Type) {
+
+ char buf[512];
+
+ IF_NOT_DEBUG(HEADERS) {
+ return;
+ }
+
+ sprintf(buf,
+ "Checksum %04x\n"
+ "Length %04x\n"
+ "TransportControl %02x\n"
+ "PacketType %02x\n"
+ "Destination %02x-%02x-%02x-%02x : %02x-%02x-%02x-%02x-%02x-%02x : %04x\n"
+ "Source %02x-%02x-%02x-%02x : %02x-%02x-%02x-%02x-%02x-%02x : %04x\n",
+ ((LPIPX_PACKET)pPacket)->Checksum,
+ B2LW(((LPIPX_PACKET)pPacket)->Length),
+ ((LPIPX_PACKET)pPacket)->TransportControl,
+ ((LPIPX_PACKET)pPacket)->PacketType,
+ ((LPIPX_PACKET)pPacket)->Destination.Net[0] & 0xff,
+ ((LPIPX_PACKET)pPacket)->Destination.Net[1] & 0xff,
+ ((LPIPX_PACKET)pPacket)->Destination.Net[2] & 0xff,
+ ((LPIPX_PACKET)pPacket)->Destination.Net[3] & 0xff,
+ ((LPIPX_PACKET)pPacket)->Destination.Node[0] & 0xff,
+ ((LPIPX_PACKET)pPacket)->Destination.Node[1] & 0xff,
+ ((LPIPX_PACKET)pPacket)->Destination.Node[2] & 0xff,
+ ((LPIPX_PACKET)pPacket)->Destination.Node[3] & 0xff,
+ ((LPIPX_PACKET)pPacket)->Destination.Node[4] & 0xff,
+ ((LPIPX_PACKET)pPacket)->Destination.Node[5] & 0xff,
+ B2LW(((LPIPX_PACKET)pPacket)->Destination.Socket),
+ ((LPIPX_PACKET)pPacket)->Source.Net[0] & 0xff,
+ ((LPIPX_PACKET)pPacket)->Source.Net[1] & 0xff,
+ ((LPIPX_PACKET)pPacket)->Source.Net[2] & 0xff,
+ ((LPIPX_PACKET)pPacket)->Source.Net[3] & 0xff,
+ ((LPIPX_PACKET)pPacket)->Source.Node[0] & 0xff,
+ ((LPIPX_PACKET)pPacket)->Source.Node[1] & 0xff,
+ ((LPIPX_PACKET)pPacket)->Source.Node[2] & 0xff,
+ ((LPIPX_PACKET)pPacket)->Source.Node[3] & 0xff,
+ ((LPIPX_PACKET)pPacket)->Source.Node[4] & 0xff,
+ ((LPIPX_PACKET)pPacket)->Source.Node[5] & 0xff,
+ B2LW(((LPIPX_PACKET)pPacket)->Source.Socket)
+ );
+ VwLog(buf);
+ if (Type == ECB_TYPE_SPX) {
+ sprintf(buf,
+ "ConnectControl %02x\n"
+ "DataStreamType %02x\n"
+ "SourceConnectId %04x\n"
+ "DestConnectId %04x\n"
+ "SequenceNumber %04x\n"
+ "AckNumber %04x\n"
+ "AllocationNumber %04x\n",
+ ((LPSPX_PACKET)pPacket)->ConnectionControl,
+ ((LPSPX_PACKET)pPacket)->DataStreamType,
+ B2LW(((LPSPX_PACKET)pPacket)->SourceConnectId),
+ B2LW(((LPSPX_PACKET)pPacket)->DestinationConnectId),
+ B2LW(((LPSPX_PACKET)pPacket)->SequenceNumber),
+ B2LW(((LPSPX_PACKET)pPacket)->AckNumber),
+ B2LW(((LPSPX_PACKET)pPacket)->AllocationNumber)
+ );
+ VwLog(buf);
+ }
+ VwLog("\n");
+}
+
+VOID VwDumpXecb(LPXECB pXecb) {
+
+ char buf[512];
+
+ IF_NOT_DEBUG(XECB) {
+ return;
+ }
+
+ sprintf(buf,
+ "XECB @ %08x:\n"
+ "Next %08x\n"
+ "Ecb %08x\n"
+ "EcbAddress %08x\n"
+ "EsrAddress %08x\n"
+ "Buffer %08x\n"
+ "Data %08x\n"
+ "FrameLength %04x\n"
+ "ActualLength %04x\n"
+ "Length %04x\n"
+ "Ticks %04x\n"
+ "SocketNumber %04x\n"
+ "Owner %04x\n"
+ "TaskId %08x\n"
+ "Flags %08x\n"
+ "QueueId %08x\n"
+ "OwningObject %08x\n"
+ "RefCount %08x\n",
+ pXecb,
+ pXecb->Next,
+ pXecb->Ecb,
+ pXecb->EcbAddress,
+ pXecb->EsrAddress,
+ pXecb->Buffer,
+ pXecb->Data,
+ pXecb->FrameLength,
+ pXecb->ActualLength,
+ pXecb->Length,
+ pXecb->Ticks,
+ B2LW(pXecb->SocketNumber),
+ pXecb->Owner,
+ pXecb->TaskId,
+ pXecb->Flags,
+ pXecb->QueueId,
+ pXecb->OwningObject,
+ pXecb->RefCount
+ );
+ VwLog(buf);
+}
+
+VOID VwDumpSocketInfo(LPSOCKET_INFO pSocketInfo) {
+
+ char buf[512];
+
+ IF_NOT_DEBUG(SOCKINFO) {
+ return;
+ }
+
+ sprintf(buf,
+ "SOCKET_INFO @ %08x:\n"
+ "Next %08x\n"
+ "SocketNumber %04x\n"
+ "Owner %04x\n"
+ "TaskId %08x\n"
+ "Socket %08x\n"
+ "Flags %08x\n"
+ "LongLived %d\n"
+ "SpxSocket %d\n"
+ "PendingSends %08x\n"
+ "PendingListens %08x\n"
+ "ListenQueue %08x, %08x\n"
+ "SendQueue %08x, %08x\n"
+ "HeaderQueue %08x, %08x\n"
+ "Connections %08x\n",
+ pSocketInfo,
+ pSocketInfo->Next,
+ B2LW(pSocketInfo->SocketNumber),
+ pSocketInfo->Owner,
+ pSocketInfo->TaskId,
+ pSocketInfo->Socket,
+ pSocketInfo->Flags,
+ pSocketInfo->LongLived,
+ pSocketInfo->SpxSocket,
+ pSocketInfo->PendingSends,
+ pSocketInfo->PendingListens,
+ pSocketInfo->ListenQueue.Head,
+ pSocketInfo->ListenQueue.Tail,
+ pSocketInfo->SendQueue.Head,
+ pSocketInfo->SendQueue.Tail,
+ pSocketInfo->HeaderQueue.Head,
+ pSocketInfo->HeaderQueue.Tail,
+ pSocketInfo->Connections
+ );
+ VwLog(buf);
+}
+
+VOID VwDumpConnectionInfo(LPCONNECTION_INFO pConnectionInfo) {
+
+ char buf[512];
+
+ IF_NOT_DEBUG(CONNINFO) {
+ return;
+ }
+
+ sprintf(buf,
+ "CONNECTION_INFO @ %08x:\n"
+ "Next %08x\n"
+ "List %08x\n"
+ "OwningSocket %08x\n"
+ "Socket %08x\n"
+ "TaskId %08x\n"
+ "ConnectionId %04x\n"
+ "Flags %02x\n"
+ "State %02x\n"
+ "ConnectQueue %08x, %08x\n"
+ "AcceptQueue %08x, %08x\n"
+ "SendQueue %08x, %08x\n"
+ "ListenQueue %08x, %08x\n",
+ pConnectionInfo,
+ pConnectionInfo->Next,
+ pConnectionInfo->List,
+ pConnectionInfo->OwningSocket,
+ pConnectionInfo->Socket,
+ pConnectionInfo->TaskId,
+ pConnectionInfo->ConnectionId,
+ pConnectionInfo->Flags,
+ pConnectionInfo->State,
+ pConnectionInfo->ConnectQueue.Head,
+ pConnectionInfo->ConnectQueue.Tail,
+ pConnectionInfo->AcceptQueue.Head,
+ pConnectionInfo->AcceptQueue.Tail,
+ pConnectionInfo->SendQueue.Head,
+ pConnectionInfo->SendQueue.Tail,
+ pConnectionInfo->ListenQueue.Head,
+ pConnectionInfo->ListenQueue.Tail
+ );
+ VwLog(buf);
+}
+
+VOID VwDumpConnectionStats(LPSPX_CONNECTION_STATS pStats) {
+
+ char buf[1024];
+
+ IF_NOT_DEBUG(STATS) {
+ return;
+ }
+
+ sprintf(buf,
+ "State %02x\n"
+ "WatchDog %02x\n"
+ "LocalConnectionId %04x\n"
+ "RemoteConnectionId %04x\n"
+ "LocalSequenceNumber %04x\n"
+ "LocalAckNumber %04x\n"
+ "LocalAllocNumber %04x\n"
+ "RemoteAckNumber %04x\n"
+ "RemoteAllocNumber %04x\n"
+ "LocalSocket %04x\n"
+ "ImmediateAddress %02x-%02x-%02x-%02x-%02x-%02x\n"
+ "RemoteNetwork %02x-%02x-%02x-%02x\n"
+ "RemoteNode %02x-%02x-%02x-%02x-%02x-%02x\n"
+ "RemoteSocket %04x\n"
+ "RetransmissionCount %04x\n"
+ "EstimatedRoundTripDelay %04x\n"
+ "RetransmittedPackets %04x\n",
+ pStats->State,
+ pStats->WatchDog,
+ B2LW(pStats->LocalConnectionId),
+ B2LW(pStats->RemoteConnectionId),
+ B2LW(pStats->LocalSequenceNumber),
+ B2LW(pStats->LocalAckNumber),
+ B2LW(pStats->LocalAllocNumber),
+ B2LW(pStats->RemoteAckNumber),
+ B2LW(pStats->RemoteAllocNumber),
+ B2LW(pStats->LocalSocket),
+ pStats->ImmediateAddress[0] & 0xff,
+ pStats->ImmediateAddress[1] & 0xff,
+ pStats->ImmediateAddress[2] & 0xff,
+ pStats->ImmediateAddress[3] & 0xff,
+ pStats->ImmediateAddress[4] & 0xff,
+ pStats->ImmediateAddress[5] & 0xff,
+ pStats->RemoteNetwork[0] & 0xff,
+ pStats->RemoteNetwork[1] & 0xff,
+ pStats->RemoteNetwork[2] & 0xff,
+ pStats->RemoteNetwork[3] & 0xff,
+ pStats->RemoteNode[0] & 0xff,
+ pStats->RemoteNode[1] & 0xff,
+ pStats->RemoteNode[2] & 0xff,
+ pStats->RemoteNode[3] & 0xff,
+ pStats->RemoteNode[4] & 0xff,
+ pStats->RemoteNode[5] & 0xff,
+ B2LW(pStats->RemoteSocket),
+ B2LW(pStats->RetransmissionCount),
+ B2LW(pStats->EstimatedRoundTripDelay),
+ B2LW(pStats->RetransmittedPackets)
+ );
+
+ VwLog(buf);
+}
+
+VOID VwLog(LPSTR buf) {
+
+ IF_DEBUG(NOTHING) {
+ return;
+ }
+
+ IF_DEBUG(TO_FILE) {
+ fputs(buf, hVwDebugLog);
+ IF_DEBUG(FLUSH) {
+ fflush(hVwDebugLog);
+ }
+ } else IF_DEBUG(TO_DBG) {
+ OutputDebugString(buf);
+ }
+}
+
+VOID CheckInterrupts(LPSTR name) {
+
+ IF_DEBUG(CHECK_INT) {
+
+ LPWORD pDosIntFlag = (LPWORD)GET_POINTER(0x40, 0x314, 2, FALSE);
+
+ if ((getIF() == 0) || !(*pDosIntFlag & 0x200)) {
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_ERROR,
+ "*** CheckInterrupts: ints off in %s (IF=%d, 40:314=%04x)\n",
+ name,
+ getIF(),
+ *pDosIntFlag
+ ));
+ }
+ }
+}
+
+extern LPCONNECTION_INFO ConnectionList ;
+extern LPSOCKET_INFO SocketList ;
+
+VOID VwDumpAll(VOID)
+{
+ char buf[512];
+ LPCONNECTION_INFO pConnectionInfo;
+ LPSOCKET_INFO pSocketInfo;
+
+ if (DebugFlagsEx == 0)
+ return ;
+
+ DebugFlagsEx = 0 ;
+
+ RequestMutex();
+
+
+ pSocketInfo = SocketList;
+ while (pSocketInfo) {
+
+ LPXECB pXecb ;
+
+ if (!(pSocketInfo->SpxSocket)) {
+ pSocketInfo = pSocketInfo->Next;
+ continue ;
+ }
+
+ sprintf(buf,
+ "%sSOCKET_INFO @ %08x:\n"
+ " SocketNumber %04x\n"
+ " Owner %04x\n"
+ " TaskId %08x\n"
+ " Socket %08x\n"
+ " Flags %08x\n"
+ " LongLived %d\n"
+ " PendingSends %08x\n"
+ " PendingListens %08x\n"
+ " ListenQueue %08x, %08x\n"
+ " SendQueue %08x, %08x\n"
+ " HeaderQueue %08x, %08x\n"
+ " Connections %08x\n\n",
+ (pSocketInfo->SpxSocket)?"SPX ":"",
+ pSocketInfo,
+ B2LW(pSocketInfo->SocketNumber),
+ pSocketInfo->Owner,
+ pSocketInfo->TaskId,
+ pSocketInfo->Socket,
+ pSocketInfo->Flags,
+ pSocketInfo->LongLived,
+ pSocketInfo->PendingSends,
+ pSocketInfo->PendingListens,
+ pSocketInfo->ListenQueue.Head,
+ pSocketInfo->ListenQueue.Tail,
+ pSocketInfo->SendQueue.Head,
+ pSocketInfo->SendQueue.Tail,
+ pSocketInfo->HeaderQueue.Head,
+ pSocketInfo->HeaderQueue.Tail,
+ pSocketInfo->Connections
+ );
+ OutputDebugString(buf);
+
+ pConnectionInfo = pSocketInfo->Connections ;
+
+ while(pConnectionInfo) {
+ sprintf(buf,
+ "CONNECTION_INFO @ %08x:\n"
+ " List %08x\n"
+ " OwningSocket %08x\n"
+ " Socket %08x\n"
+ " TaskId %08x\n"
+ " ConnectionId %04x\n"
+ " Flags %02x\n"
+ " State %02x\n"
+ " ConnectQueue %08x, %08x\n"
+ " AcceptQueue %08x, %08x\n"
+ " SendQueue %08x, %08x\n"
+ " ListenQueue %08x, %08x\n\n",
+ pConnectionInfo,
+ pConnectionInfo->List,
+ pConnectionInfo->OwningSocket,
+ pConnectionInfo->Socket,
+ pConnectionInfo->TaskId,
+ pConnectionInfo->ConnectionId,
+ pConnectionInfo->Flags,
+ pConnectionInfo->State,
+ pConnectionInfo->ConnectQueue.Head,
+ pConnectionInfo->ConnectQueue.Tail,
+ pConnectionInfo->AcceptQueue.Head,
+ pConnectionInfo->AcceptQueue.Tail,
+ pConnectionInfo->SendQueue.Head,
+ pConnectionInfo->SendQueue.Tail,
+ pConnectionInfo->ListenQueue.Head,
+ pConnectionInfo->ListenQueue.Tail
+ );
+ OutputDebugString(buf);
+ pConnectionInfo = pConnectionInfo->Next ;
+ }
+
+ pXecb = pSocketInfo->ListenQueue.Head ;
+ while(pXecb) {
+ sprintf(buf,
+ " XECB @ %08x: (Ecb %08x)\n"
+ " EcbAddress/EsrAddress %08x %08x\n"
+ " Flags/RefCount %08x %08x\n"
+ " Buffer/QueueId %08x %08x\n"
+ " OwningObject %08x\n",
+ pXecb,
+ pXecb->Ecb,
+ pXecb->EcbAddress,
+ pXecb->EsrAddress,
+ pXecb->Flags,
+ pXecb->RefCount,
+ pXecb->Buffer,
+ pXecb->QueueId,
+ pXecb->OwningObject
+ );
+ OutputDebugString(buf);
+ pXecb = pXecb->Next ;
+ }
+ pSocketInfo = pSocketInfo->Next;
+ }
+ ReleaseMutex();
+}
+
+#endif // DBG
diff --git a/private/nw/vwipxspx/dll/vwdebug.h b/private/nw/vwipxspx/dll/vwdebug.h
new file mode 100644
index 000000000..142c7e22a
--- /dev/null
+++ b/private/nw/vwipxspx/dll/vwdebug.h
@@ -0,0 +1,184 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ vwdebug.h
+
+Abstract:
+
+ Prototypes, structures, manifests, macros for VWIPXSPX debug routines
+
+Author:
+
+ Richard L Firth (rfirth) 5-Oct-1993
+
+Revision History:
+
+ 5-Oct-1993 rfirth
+ Created
+
+--*/
+
+#ifndef _VWDEBUG_H_
+#define _VWDEBUG_H_
+
+//
+// debug flags
+//
+
+#define DEBUG_ANY 0xFFFFFFFF // any debug flags set
+#define DEBUG_NOTHING 0x00000001 // no debug output
+#define DEBUG_CHECK_INT 0x00080000 // check interrupts (DOS)
+#define DEBUG_STATS 0x00100000 // dump connection stats
+#define DEBUG_DATA 0x00200000 // dump data (send)
+#define DEBUG_FRAGMENTS 0x00400000 // dump fragments
+#define DEBUG_HEADERS 0x00800000 // dump IPX/SPX headers
+#define DEBUG_ECB 0x01000000 // dump 16-bit ECBs
+#define DEBUG_XECB 0x02000000 // dump 32-bit XECBs
+#define DEBUG_SOCKINFO 0x04000000 // dump SOCKET_INFO structs
+#define DEBUG_CONNINFO 0x08000000 // dump CONNECTION_INFO structs
+#define DEBUG_DLL 0x10000000 // include DLL attach/detach info
+#define DEBUG_FLUSH 0x20000000 // flush every write
+#define DEBUG_TO_FILE 0x40000000 // write debug stuff to file
+#define DEBUG_TO_DBG 0x80000000 // debug stuff to debugger
+
+#define VWDEBUG_FILE "VWDEBUG.LOG"
+
+//
+// function designators
+//
+
+#define FUNCTION_ANY 0xFFFFFFFF
+#define FUNCTION_IPXOpenSocket 0x00000001 // 0x00
+#define FUNCTION_IPXCloseSocket 0x00000002 // 0x01
+#define FUNCTION_IPXGetLocalTarget 0x00000004 // 0x02
+#define FUNCTION_IPXSendPacket 0x00000008 // 0x03
+#define FUNCTION_IPXListenForPacket 0x00000010 // 0x04
+#define FUNCTION_IPXScheduleIPXEvent 0x00000020 // 0x05
+#define FUNCTION_IPXCancelEvent 0x00000040 // 0x06
+#define FUNCTION_IPXScheduleAESEvent 0x00000080 // 0x07
+#define FUNCTION_IPXGetIntervalMarker 0x00000100 // 0x08
+#define FUNCTION_IPXGetInternetworkAddress 0x00000200 // 0x09
+#define FUNCTION_IPXRelinquishControl 0x00000400 // 0x0A
+#define FUNCTION_IPXDisconnectFromTarget 0x00000800 // 0x0B
+#define FUNCTION_InvalidFunction_0C 0x00001000 // 0x0C
+#define FUNCTION_InvalidFunction_0D 0x00002000 // 0x0D
+#define FUNCTION_InvalidFunction_0E 0x00004000 // 0x0E
+#define FUNCTION_InvalidFunction_0F 0x00008000 // 0x0F
+#define FUNCTION_SPXInitialize 0x00010000 // 0x10
+#define FUNCTION_SPXEstablishConnection 0x00020000 // 0x11
+#define FUNCTION_SPXListenForConnection 0x00040000 // 0x12
+#define FUNCTION_SPXTerminateConnection 0x00080000 // 0x13
+#define FUNCTION_SPXAbortConnection 0x00100000 // 0x14
+#define FUNCTION_SPXGetConnectionStatus 0x00200000 // 0x15
+#define FUNCTION_SPXSendSequencedPacket 0x00400000 // 0x16
+#define FUNCTION_SPXListenForSequencedPacket 0x00800000 // 0x17
+#define FUNCTION_InvalidFunction_18 0x01000000 // 0x18
+#define FUNCTION_InvalidFunction_19 0x02000000 // 0x19
+#define FUNCTION_IPXGetMaxPacketSize 0x04000000 // 0x1A
+#define FUNCTION_InvalidFunction_1B 0x08000000 // 0x1B
+#define FUNCTION_InvalidFunction_1C 0x10000000 // 0x1C
+#define FUNCTION_InvalidFunction_1D 0x20000000 // 0x1D
+#define FUNCTION_InvalidFunction_1E 0x40000000 // 0x1E
+#define FUNCTION_IPXGetInformation 0x80000000 // 0x1F
+#define FUNCTION_IPXSendWithChecksum 0xFFFFFFFF // 0x20
+#define FUNCTION_IPXGenerateChecksum 0xFFFFFFFF // 0x21
+#define FUNCTION_IPXVerifyChecksum 0xFFFFFFFF // 0x22
+
+//
+// debug levels
+//
+
+#define IPXDBG_LEVEL_ALL 0
+#define IPXDBG_LEVEL_INFO 1
+#define IPXDBG_LEVEL_WARNING 2
+#define IPXDBG_LEVEL_ERROR 3
+#define IPXDBG_LEVEL_FATAL 4
+
+#define IPXDBG_MIN_LEVEL IPXDBG_LEVEL_ALL
+#define IPXDBG_MAX_LEVEL IPXDBG_LEVEL_FATAL
+
+//
+// info dump flags (VWDUMP)
+//
+
+#define DUMP_ECB_IN 0x00000001
+#define DUMP_ECB_OUT 0x00000002
+#define DUMP_SEND_DATA 0x00000004
+#define DUMP_RECEIVE_DATA 0x00000008
+
+//
+// show flags
+//
+
+#define SHOW_ECBS 0x00000001 // show ECBs vs. raw data
+#define SHOW_HEADERS 0x00000002 // show IPX/SPX headers vs. raw data
+
+#if DBG
+
+extern DWORD VwDebugFlags;
+extern DWORD VwDebugFunctions;
+extern DWORD VwShow;
+extern DWORD DebugFlagsEx;
+
+
+#define IF_DEBUG(f) if (VwDebugFlags & DEBUG_ ## f)
+#define IF_NOT_DEBUG(f) if (!(VwDebugFlags & DEBUG_ ## f))
+#define IF_SHOW(f) if (VwShow & SHOW_ ## f)
+#define IF_NOT_SHOW(f) if (!(VwShow & SHOW_ ## f))
+#define PRIVATE
+#define IPXDBGPRINT(x) VwDebugPrint x
+#define IPXDBGSTART() VwDebugStart()
+#define IPXDBGEND() VwDebugEnd
+#define VWASSERT(a, b) ASSERT((a) == (b))
+#define IPXDUMPDATA(x) VwDumpData x
+#define IPXDUMPECB(x) VwDumpEcb x
+#define DUMPXECB(x) VwDumpXecb(x)
+#define DUMPCONN(x) VwDumpConnectionInfo(x)
+#define DUMPSTATS(x) VwDumpConnectionStats(x)
+#define CHECK_INTERRUPTS(s) CheckInterrupts(s)
+#define DUMPALL() VwDumpAll()
+
+#else
+
+#define IF_DEBUG(f) if (0)
+#define IF_NOT_DEBUG(f) if (0)
+#define IF_SHOW(f) if (0)
+#define IF_NOT_SHOW(f) if (0)
+#define PRIVATE static
+#define IPXDBGPRINT(x)
+#define IPXDBGSTART()
+#define IPXDBGEND()
+#define VWASSERT(a, b) a
+#define IPXDUMPDATA(x)
+#define IPXDUMPECB(x)
+#define DUMPXECB(x)
+#define DUMPCONN(x)
+#define DUMPSTATS(x)
+#define CHECK_INTERRUPTS(s)
+#define DUMPALL()
+
+#endif
+
+//
+// debug function prototypes
+//
+
+extern VOID VwDebugStart(VOID);
+extern VOID VwDebugEnd(VOID);
+extern VOID VwDebugPrint(LPSTR, DWORD, DWORD, DWORD, LPSTR, ...);
+extern VOID VwDumpData(ULPBYTE, WORD, WORD, BOOL, WORD);
+extern VOID VwDumpEcb(LPECB, WORD, WORD, BYTE, BOOL, BOOL, BOOL);
+extern VOID VwDumpFragment(WORD, LPFRAGMENT, BYTE, BOOL, BOOL);
+extern VOID VwDumpPacketHeader(ULPBYTE, BYTE);
+extern VOID VwDumpXecb(LPXECB);
+extern VOID VwDumpSocketInfo(LPSOCKET_INFO);
+extern VOID VwDumpConnectionInfo(LPCONNECTION_INFO);
+extern VOID VwDumpConnectionStats(LPSPX_CONNECTION_STATS);
+extern VOID VwLog(LPSTR);
+extern VOID CheckInterrupts(LPSTR);
+extern VOID VwDumpAll(VOID);
+
+#endif // _VWDEBUG_H_
diff --git a/private/nw/vwipxspx/dll/vwdll.c b/private/nw/vwipxspx/dll/vwdll.c
new file mode 100644
index 000000000..0b7b9fcd7
--- /dev/null
+++ b/private/nw/vwipxspx/dll/vwdll.c
@@ -0,0 +1,502 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ vwdll.c
+
+Abstract:
+
+ ntVdm netWare (Vw) IPX/SPX Functions
+
+ Vw: The peoples' network
+
+ VDD functions for DOS/WOW IPX/SPX support
+
+ Contents:
+ VwDllEntryPoint
+ VwInitialize
+ VWinInitialize
+ VwDispatcher
+ VwInvalidFunction
+
+Author:
+
+ Richard L Firth (rfirth) 30-Sep-1993
+
+Environment:
+
+ User-mode Win32
+
+Revision History:
+
+ 30-Sep-1993 rfirth
+ Created
+
+--*/
+
+#include "vw.h"
+#pragma hdrstop
+
+//
+// private prototypes
+//
+
+PRIVATE
+VOID
+VwInvalidFunction(
+ VOID
+ );
+
+//
+// private data
+//
+
+PRIVATE
+VOID
+(*VwDispatchTable[])(VOID) = {
+ VwIPXOpenSocket, // 0x00
+ VwIPXCloseSocket, // 0x01
+ VwIPXGetLocalTarget, // 0x02
+ VwIPXSendPacket, // 0x03
+ VwIPXListenForPacket, // 0x04
+ VwIPXScheduleIPXEvent, // 0x05
+ VwIPXCancelEvent, // 0x06
+ VwIPXScheduleAESEvent, // 0x07
+ VwIPXGetIntervalMarker, // 0x08
+ VwIPXGetInternetworkAddress, // 0x09
+ VwIPXRelinquishControl, // 0x0A
+ VwIPXDisconnectFromTarget, // 0x0B
+ VwInvalidFunction, // 0x0C
+ VwInvalidFunction, // 0x0D old-style GetMaxPacketSize
+ VwInvalidFunction, // 0x0E
+ VwInvalidFunction, // 0x0F internal send packet function
+ VwSPXInitialize, // 0x10
+ VwSPXEstablishConnection, // 0x11
+ VwSPXListenForConnection, // 0x12
+ VwSPXTerminateConnection, // 0x13
+ VwSPXAbortConnection, // 0x14
+ VwSPXGetConnectionStatus, // 0x15
+ VwSPXSendSequencedPacket, // 0x16
+ VwSPXListenForSequencedPacket, // 0x17
+ VwInvalidFunction, // 0x18
+ VwInvalidFunction, // 0x19
+ VwIPXGetMaxPacketSize, // 0x1A
+ VwInvalidFunction, // 0x1B
+ VwInvalidFunction, // 0x1C
+ VwInvalidFunction, // 0x1D
+ VwInvalidFunction, // 0x1E
+ VwIPXGetInformation, // 0x1F
+ VwIPXSendWithChecksum, // 0x20
+ VwIPXGenerateChecksum, // 0x21
+ VwIPXVerifyChecksum // 0x22
+};
+
+#define MAX_IPXSPX_FUNCTION LAST_ELEMENT(VwDispatchTable)
+
+WSADATA WsaData = {0};
+HANDLE hAesThread = NULL;
+
+//
+// global data
+//
+
+SOCKADDR_IPX MyInternetAddress;
+WORD MyMaxPacketSize;
+int Ica;
+BYTE IcaLine;
+
+//
+// not-really-global data
+//
+
+extern CRITICAL_SECTION SerializationCritSec;
+extern CRITICAL_SECTION AsyncCritSec;
+
+//
+// functions
+//
+
+
+BOOL
+WINAPI
+VwDllEntryPoint(
+ IN PVOID DllHandle,
+ IN ULONG Reason,
+ IN PCONTEXT Context OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ Called when the process attaches (LoadLibrary/init) and detaches (FreeLibrary/
+ process termination) from this DLL
+
+ Attach:
+ initialize Winsock DLL
+ get internet address for this station
+ get maximum packet size supported by transport (IPX)
+ create AES thread
+
+ Detach:
+ terminate Winsock DLL
+
+Arguments:
+
+ DllHandle - unused
+ Reason - checked for process attach/detach
+ Context - unused
+
+Return Value:
+
+ BOOLEAN
+
+--*/
+
+{
+ DWORD aesThreadId; // unused outside of this function
+
+ static BOOL CriticalSectionsAreInitialized = FALSE;
+
+ UNREFERENCED_PARAMETER(DllHandle);
+ UNREFERENCED_PARAMETER(Context);
+
+ IPXDBGSTART();
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_INFO,
+ "VwDllEntryPoint: %s\n",
+ Reason == DLL_PROCESS_ATTACH ? "DLL_PROCESS_ATTACH"
+ : Reason == DLL_PROCESS_DETACH ? "DLL_PROCESS_DETACH"
+ : Reason == DLL_THREAD_ATTACH ? "DLL_THREAD_ATTACH"
+ : Reason == DLL_THREAD_DETACH ? "DLL_THREAD_DETACH"
+ : "?"
+ ));
+
+ if (Reason == DLL_PROCESS_ATTACH) {
+
+ int err;
+
+ //
+ // BUGBUG: get ICA values from new VDD service. Right now we grab
+ // line 4 on the slave (base = 0x70, modifier = 0x03)
+ //
+
+ Ica = ICA_SLAVE;
+ IcaLine = 3;
+
+ err = WSAStartup(MAKEWORD(1, 1), &WsaData);
+ if (err) {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_FATAL,
+ "VwDllEntryPoint: WSAStartup() returns %d\n",
+ err
+ ));
+
+ return FALSE;
+ } else {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_INFO,
+ "VwDllEntryPoint: WsaData:\n"
+ "\twVersion : 0x%04x\n"
+ "\twHighVersion : 0x%04x\n"
+ "\tszDescription : \"%s\"\n"
+ "\tszSystemStatus : \"%s\"\n"
+ "\tiMaxSockets : %d\n"
+ "\tiMaxUdpDg : %d\n"
+ "\tlpVendorInfo : 0x%08x\n",
+ WsaData.wVersion,
+ WsaData.wHighVersion,
+ WsaData.szDescription,
+ WsaData.szSystemStatus,
+ WsaData.iMaxSockets,
+ WsaData.iMaxUdpDg,
+ WsaData.lpVendorInfo
+ ));
+
+ }
+
+ //
+ // retrieve the internet address for this station. Used in
+ // IPXGetInternetworkAddress() and IPXSendPacket()
+ //
+
+ err = GetInternetAddress(&MyInternetAddress);
+ if (err) {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_FATAL,
+ "VwDllEntryPoint: GetInternetAddress() returns %d\n",
+ WSAGetLastError()
+ ));
+
+ goto attach_error_exit;
+ } else {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_INFO,
+ "VwDllEntryPoint: MyInternetAddress:\n"
+ "\tNet : %02.2x-%02.2x-%02.2x-%02.2x\n"
+ "\tNode : %02.2x-%02.2x-%02.2x-%02.2x-%02.2x-%02.2x\n",
+ MyInternetAddress.sa_netnum[0] & 0xff,
+ MyInternetAddress.sa_netnum[1] & 0xff,
+ MyInternetAddress.sa_netnum[2] & 0xff,
+ MyInternetAddress.sa_netnum[3] & 0xff,
+ MyInternetAddress.sa_nodenum[0] & 0xff,
+ MyInternetAddress.sa_nodenum[1] & 0xff,
+ MyInternetAddress.sa_nodenum[2] & 0xff,
+ MyInternetAddress.sa_nodenum[3] & 0xff,
+ MyInternetAddress.sa_nodenum[4] & 0xff,
+ MyInternetAddress.sa_nodenum[5] & 0xff
+ ));
+
+ }
+
+ //
+ // get the maximum packet size supported by IPX. Used in
+ // IPXGetMaxPacketSize()
+ //
+
+ err = GetMaxPacketSize(&MyMaxPacketSize);
+ if (err) {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_FATAL,
+ "VwDllEntryPoint: GetMaxPacketSize() returns %d\n",
+ WSAGetLastError()
+ ));
+
+ goto attach_error_exit;
+ } else {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_INFO,
+ "VwDllEntryPoint: GetMaxPacketSize: %04x (%d)\n",
+ MyMaxPacketSize,
+ MyMaxPacketSize
+ ));
+
+ }
+
+ hAesThread = CreateThread(NULL,
+ 0,
+ (LPTHREAD_START_ROUTINE)VwAesThread,
+ NULL,
+ 0,
+ &aesThreadId
+ );
+ if (hAesThread == NULL) {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_FATAL,
+ "VwDllEntryPoint: CreateThread() returns %d\n",
+ GetLastError()
+ ));
+
+ goto attach_error_exit;
+ }
+
+ //
+ // finally initialize any critical sections
+ //
+
+ InitializeCriticalSection(&SerializationCritSec);
+ InitializeCriticalSection(&AsyncCritSec);
+ CriticalSectionsAreInitialized = TRUE;
+ } else if (Reason == DLL_PROCESS_DETACH) {
+ if (hAesThread != NULL) {
+ WaitForSingleObject(hAesThread, ONE_TICK * 2);
+ CloseHandle(hAesThread);
+ }
+
+ WSACleanup();
+
+ if (CriticalSectionsAreInitialized) {
+ DeleteCriticalSection(&SerializationCritSec);
+ DeleteCriticalSection(&AsyncCritSec);
+ }
+
+ IPXDBGEND();
+ }
+ return TRUE;
+
+attach_error_exit:
+
+ //
+ // here if any fatal errors on process attach after successfully performing
+ // WSAStartup
+ //
+
+ WSACleanup();
+ return FALSE;
+}
+
+BYTE
+VWinInitialize(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Called by interface when nwipxspx.dll is loaded. We
+ return the IRQ value.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The IRQ value.
+
+--*/
+
+{
+ return 0x73;
+}
+
+
+
+VOID
+VwInitialize(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Called by VDD interface when DLL loaded via call to RegisterModule. We
+ get the IRQ value and return it as an interrupt vector in BX
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_INFO,
+ "VwInitialize\n"
+ ));
+
+ //
+ // only lines on slave PIC are available. Currently, lines 3, 4 and 7 are
+ // not used. We'll grab line 3 here, but in the future we expect a function
+ // to return the available IRQ line
+ //
+
+ setBX( VWinInitialize() );
+}
+
+
+VOID
+VwDispatcher(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Branches to relevant IPX/SPX handler for DOS calls, based on contents of
+ VDM BX register.
+
+ Control transfered here from 16-bit entry point, either as result of call
+ to far address returned from INT 2Fh/AH=7A or INT 7Ah
+
+ Special: we use BX = 0xFFFF to indicate that the app is terminating. The
+ TSR hooks INT 0x2F/AX=0x1122 (IFSResetEnvironment)
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ DWORD dispatchIndex;
+
+ dispatchIndex = (DWORD)getBX() & 0x7fff;
+
+ if (dispatchIndex <= MAX_IPXSPX_FUNCTION) {
+ VwDispatchTable[dispatchIndex]();
+ } else if (dispatchIndex == 0x7FFE) {
+ EsrCallback();
+ } else if (dispatchIndex == 0x7FFF) {
+ VwTerminateProgram();
+ } else {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_ERROR,
+ "ERROR: VwDispatcher: dispatchIndex = %x\n",
+ dispatchIndex
+ ));
+
+ //
+ // BUGBUG - what's the correct error code to return in this situation?
+ // (will it ever arise?)
+ //
+
+ setAX(ERROR_INVALID_FUNCTION);
+ setCF(1);
+ }
+}
+
+
+PRIVATE
+VOID
+VwInvalidFunction(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Just alerts us to the fact that an invalid function request was made.
+ Useful if any app makes a bad call, or we miss out a required function
+ during design/implementation
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_INFO,
+ "VwInvalidFunction: BX=%04x\n",
+ getBX()
+ ));
+}
diff --git a/private/nw/vwipxspx/dll/vwdll.h b/private/nw/vwipxspx/dll/vwdll.h
new file mode 100644
index 000000000..aa87daddb
--- /dev/null
+++ b/private/nw/vwipxspx/dll/vwdll.h
@@ -0,0 +1,27 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ vwdll.h
+
+Abstract:
+
+ Contains external data declarations for VWDLL.C
+
+Author:
+
+ Richard L Firth (rfirth) 25-Oct-1993
+
+Revision History:
+
+ 25-Oct-1993 rfirth
+ Created
+
+--*/
+
+extern SOCKADDR_IPX MyInternetAddress;
+extern WORD MyMaxPacketSize;
+extern int Ica;
+extern BYTE IcaLine;
diff --git a/private/nw/vwipxspx/dll/vwdos.c b/private/nw/vwipxspx/dll/vwdos.c
new file mode 100644
index 000000000..31a8ee5ba
--- /dev/null
+++ b/private/nw/vwipxspx/dll/vwdos.c
@@ -0,0 +1,1502 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ vwdos.c
+
+Abstract:
+
+ ntVdm netWare (Vw) IPX/SPX Functions
+
+ Vw: The peoples' network
+
+ Contains handlers for DOS IPX/SPX calls (netware functions). The IPX APIs
+ use WinSock to perform the actual operations
+
+ Contents:
+ VwIPXCancelEvent
+ VwIPXCloseSocket
+ VwIPXDisconnectFromTarget
+ VwIPXGenerateChecksum
+ VwIPXGetInformation
+ VwIPXGetInternetworkAddress
+ VwIPXGetIntervalMarker
+ VwIPXGetLocalTarget
+ VwIPXGetLocalTargetAsync
+ VwIPXGetMaxPacketSize
+ VwIPXInitialize
+ VwIPXListenForPacket
+ VwIPXOpenSocket
+ VwIPXRelinquishControl
+ VwIPXScheduleAESEvent
+ VwIPXScheduleIPXEvent
+ VwIPXSendPacket
+ VwIPXSendWithChecksum
+ VwIPXSPXDeinit
+ VwIPXVerifyChecksum
+
+ VwSPXAbortConnection
+ VwSPXEstablishConnection
+ VwSPXGetConnectionStatus
+ VwSPXInitialize
+ VwSPXListenForConnection
+ VwSPXListenForSequencedPacket
+ VwSPXSendSequencedPacket
+ VwSPXTerminateConnection
+
+Author:
+
+ Richard L Firth (rfirth) 30-Sep-1993
+
+Environment:
+
+ User-mode Win32
+
+Revision History:
+
+ 30-Sep-1993 rfirth
+ Created
+
+--*/
+
+#include "vw.h"
+#pragma hdrstop
+
+//
+// functions
+//
+
+
+VOID
+VwIPXCancelEvent(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Cancels event described by an ECB
+
+ This call is Synchronous
+
+Arguments:
+
+ Inputs
+ BX 06h
+ ES:SI ECB
+
+ Outputs
+ AL Completion code:
+ 00h Success
+ F9h Can't cancel ECB
+ FFh ECB not in use
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LPECB pEcb;
+ WORD status;
+
+ CHECK_INTERRUPTS("VwIPXCancelEvent");
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_IPXCancelEvent,
+ IPXDBG_LEVEL_INFO,
+ "VwIPXCancelEvent(%04x:%04x)\n",
+ getES(),
+ getSI()
+ ));
+
+ IPX_GET_IPX_ECB(pEcb);
+
+ status = _VwIPXCancelEvent( pEcb );
+
+ IPX_SET_STATUS(status);
+}
+
+
+VOID
+VwIPXCloseSocket(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Closes a socket and cancels any outstanding events on the socket.
+ Closing an unopened socket does not return an error
+ ESRs in cancelled ECBs are not called
+
+ This call is Synchronous
+
+Arguments:
+
+ Inputs
+ BX 01h
+ DX Socket Number
+
+ Outputs
+ Nothing
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ WORD socketNumber;
+
+ CHECK_INTERRUPTS("VwIPXCloseSocket");
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_IPXCloseSocket,
+ IPXDBG_LEVEL_INFO,
+ "VwIPXCloseSocket(%#x)\n",
+ B2LW(IPX_SOCKET_PARM())
+ ));
+
+ IPX_GET_SOCKET(socketNumber);
+
+ _VwIPXCloseSocket( socketNumber );
+
+}
+
+
+VOID
+VwIPXDisconnectFromTarget(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Performs no action for NTVDM IPX
+
+ This call is Synchronous
+
+Arguments:
+
+ Inputs
+ BX 0Bh
+ ES:SI Request buffer:
+ Destination Network DB 4 DUP (?)
+ Destination Node DB 6 DUP (?)
+ Destination Socket DB 2 DUP (?)
+
+ Outputs
+ Nothing
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ CHECK_INTERRUPTS("VwIPXDisconnectFromTarget");
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_IPXDisconnectFromTarget,
+ IPXDBG_LEVEL_INFO,
+ "VwIPXDisconnectFromTarget\n"
+ ));
+}
+
+
+VOID
+VwIPXGenerateChecksum(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Generates checksum for a transmit ECB
+
+ This call is Synchronous
+
+Arguments:
+
+ Inputs
+ BX 21h
+ ES:SI ECB address
+
+ Outputs
+ No registers
+ ECB checksum field is updated
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ CHECK_INTERRUPTS("VwIPXGenerateChecksum");
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_IPXGenerateChecksum,
+ IPXDBG_LEVEL_INFO,
+ "VwIPXGenerateChecksum\n"
+ ));
+}
+
+
+VOID
+VwIPXGetInformation(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Returns a bit-map of supported functions
+
+ This call is Synchronous
+
+Arguments:
+
+ Inputs
+ BX 1Fh
+ DX 0000h
+
+ Outputs
+ DX Bit map:
+ 0001h Set if IPX is IPXODI.COM, not dedicated IPX
+ 0002h Set if checksum functions (20h, 21h, 22h) supported
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ CHECK_INTERRUPTS("VwIPXGetInformation");
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_IPXGetInformation,
+ IPXDBG_LEVEL_INFO,
+ "VwIPXGetInformation\n"
+ ));
+
+ IPX_SET_INFORMATION(IPX_ODI);
+}
+
+
+VOID
+VwIPXGetInternetworkAddress(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Returns a buffer containing the net number and node number for this
+ station.
+
+ This function cannot return an error (!)
+
+ Assumes: 1. GetInternetAddress has been successfully called in the
+ DLL initialization phase
+
+ This call is Synchronous
+
+Arguments:
+
+ Inputs
+ BX 09h
+
+ Outputs
+ ES:SI Buffer
+ Network Address DB 4 DUP (?)
+ Node Address DB 6 DUP (?)
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LPINTERNET_ADDRESS pAddr;
+
+ CHECK_INTERRUPTS("VwIPXGetInternetworkAddress");
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_IPXGetInternetworkAddress,
+ IPXDBG_LEVEL_INFO,
+ "VwIPXGetInternetworkAddress(%04x:%04x)\n",
+ getES(),
+ getSI()
+ ));
+
+ pAddr = (LPINTERNET_ADDRESS)IPX_BUFFER_PARM(sizeof(*pAddr));
+
+ _VwIPXGetInternetworkAddress( pAddr );
+}
+
+
+VOID
+VwIPXGetIntervalMarker(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Just returns the tick count maintained by Asynchronous Event Scheduler
+
+ This call is Synchronous
+
+Arguments:
+
+ Inputs
+ BX 08h
+
+ Outputs
+ AX Interval marker
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ CHECK_INTERRUPTS("VwIPXGetIntervalMarker");
+
+ setAX( _VwIPXGetIntervalMarker() );
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_IPXGetIntervalMarker,
+ IPXDBG_LEVEL_INFO,
+ "VwIPXGetIntervalMarker: Returning %04x\n",
+ getAX()
+ ));
+}
+
+
+VOID
+VwIPXGetLocalTarget(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Given a target address of the form (network address {4}, node address {6}),
+ returns the node address of the target if on the same network, or the node
+ address of the router which knows how to get to the next hop in reaching the
+ eventual target
+
+ This call is Synchronous
+
+Arguments:
+
+ Inputs
+ BX 02h
+ ES:SI Request buffer
+ Destination Network DB 4 DUP (?)
+ Destination Node DB 6 DUP (?)
+ Destination Socket DB 2 DUP (?)
+ ES:DI Response buffer
+ Local Target DB 6 DUP (?)
+
+ Outputs
+ AL Completion code
+ 00h Success
+ FAh No path to destination node found
+ AH Number of hops to destination
+ CX Transport time
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LPBYTE pImmediateAddress;
+ LPBYTE pNetworkAddress;
+ WORD transportTime;
+ WORD status;
+
+ CHECK_INTERRUPTS("VwIPXGetLocalTarget");
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_IPXGetLocalTarget,
+ IPXDBG_LEVEL_INFO,
+ "VwIPXGetLocalTarget(target buf @ %04x:%04x, local buf @ %04x:%04x)\n",
+ getES(),
+ getSI(),
+ getES(),
+ getDI()
+ ));
+
+
+ pImmediateAddress = POINTER_FROM_WORDS(getES(), getDI(), 6);
+ pNetworkAddress = POINTER_FROM_WORDS(getES(), getSI(), 12);
+
+ status = _VwIPXGetLocalTarget( pNetworkAddress,
+ pImmediateAddress,
+ &transportTime );
+
+
+ setCX( transportTime );
+ setAH(1);
+
+ IPX_SET_STATUS(status);
+}
+
+
+VOID
+VwIPXGetLocalTargetAsync(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ description-of-function.
+
+ This call is Asynchronous
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ CHECK_INTERRUPTS("VwIPXGetLocalTargetAsync");
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_INFO,
+ "VwIPXGetLocalTargetAsync\n"
+ ));
+}
+
+
+VOID
+VwIPXGetMaxPacketSize(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Returns the maximum packet size the underlying network can handle
+
+ Assumes: 1. A successfull call to GetMaxPacketSize has been made during
+ DLL initialization
+ 2. Maximum packet size is constant
+
+ This call is Synchronous
+
+Arguments:
+
+ Inputs
+ BX 1Ah
+
+ Outputs
+ AX Maximum packet size
+ CX IPX retry count
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ WORD maxPacketSize;
+ WORD retryCount;
+
+ CHECK_INTERRUPTS("VwIPXGetMaxPacketSize");
+
+ maxPacketSize = _VwIPXGetMaxPacketSize( &retryCount );
+
+ setAX(maxPacketSize);
+
+ //
+ // BUGBUG: The DOS Assembly and C manuals differ slightly here: DOS says
+ // we return the IPX retry count in CX. There is no corresponding parameter
+ // in the C interface?
+ //
+
+ setCX(retryCount);
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_IPXGetMaxPacketSize,
+ IPXDBG_LEVEL_INFO,
+ "VwIPXGetMaxPacketSize: PacketSize=%d, RetryCount=%d\n",
+ getAX(),
+ getCX()
+ ));
+}
+
+
+VOID
+VwIPXInitialize(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ description-of-function.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ CHECK_INTERRUPTS("VwIPXInitialize");
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_INFO,
+ "VwIPXInitialize\n"
+ ));
+}
+
+
+VOID
+VwIPXListenForPacket(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Queue a listen request against a socket. All listen requests will be
+ completed asynchronously, unless cancelled by app
+
+ This call is Asynchronous
+
+Arguments:
+
+ Inputs
+ BX 04h
+ ES:SI ECB address
+
+ Outputs
+ AL Completion code
+ FFh Socket doesn't exist
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LPECB pEcb;
+ WORD status;
+
+ CHECK_INTERRUPTS("VwIPXListenForPacket");
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_IPXListenForPacket,
+ IPXDBG_LEVEL_INFO,
+ "VwIPXListenForPacket(%04x:%04x)\n",
+ getES(),
+ getSI()
+ ));
+
+ IPX_GET_IPX_ECB(pEcb);
+
+ status = _VwIPXListenForPacket( pEcb, ECB_PARM_ADDRESS() );
+
+ IPX_SET_STATUS(status);
+}
+
+
+VOID
+VwIPXOpenSocket(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Opens a socket for use by IPX or SPX. Puts the socket into non-blocking mode.
+ The socket will be bound to IPX
+
+ This call is Synchronous
+
+Arguments:
+
+ Inputs
+ AL Socket Longevity flag
+ This parameter is actually in BP - AX has been sequestered
+ by the VDD dispatcher
+ BX 00h
+ DX Requested Socket Number
+
+ CX DOS PDB. This parameter is not part of the IPX API.
+ Added because we need to remember which DOS executable created
+ the socket: we need to clean-up short-lived sockets when the
+ executable terminates
+
+ Outputs
+ AL Completion code:
+ 00h Success
+ FFh Socket already open
+ FEh Socket table full
+ DX Assigned socket number
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ BYTE socketLife;
+ WORD socketNumber;
+ WORD status;
+
+ CHECK_INTERRUPTS("VwIPXOpenSocket");
+
+ IPX_GET_SOCKET_LIFE(socketLife);
+ IPX_GET_SOCKET(socketNumber);
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_IPXOpenSocket,
+ IPXDBG_LEVEL_INFO,
+ "VwIPXOpenSocket(Life=%02x, Socket=%04x, Owner=%04x)\n",
+ socketLife,
+ B2LW(socketNumber),
+ IPX_SOCKET_OWNER_PARM()
+ ));
+
+
+ status = _VwIPXOpenSocket( &socketNumber,
+ socketLife,
+ IPX_SOCKET_OWNER_PARM() );
+
+ if ( status == IPX_SUCCESS )
+ IPX_SET_SOCKET(socketNumber);
+
+ IPX_SET_STATUS(status);
+}
+
+
+VOID
+VwIPXRelinquishControl(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Just sleep for a nominal amount. Netware seems to be dependent on the
+ default setting of the PC clock, so one timer tick (1/18 second) would
+ seem to be a good value
+
+ This call is Synchronous
+
+Arguments:
+
+ Inputs
+ BX 0Ah
+
+ Outputs
+ Nothing
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ CHECK_INTERRUPTS("VwIPXRelinquishControl");
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_IPXRelinquishControl,
+ IPXDBG_LEVEL_INFO,
+ "VwIPXRelinquishControl\n"
+ ));
+
+ _VwIPXRelinquishControl();
+
+}
+
+
+VOID
+VwIPXScheduleAESEvent(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Schedules a an event to occur in some number of ticks. When the tick count
+ reaches 0, the ECB InUse field is cleared and any ESR called
+
+ This call is Asynchronous
+
+Arguments:
+
+ Inputs
+ BX 07h
+ AX Delay time - number of 1/18 second ticks
+ ES:SI ECB address
+
+ Outputs
+ Nothing
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LPXECB pXecb = AES_ECB_PARM();
+ WORD ticks = IPX_TICKS_PARM();
+
+ CHECK_INTERRUPTS("VwIPXScheduleAESEvent");
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_IPXScheduleAESEvent,
+ IPXDBG_LEVEL_INFO,
+ "VwIPXScheduleAESEvent(%04x:%04x, %04x)\n",
+ getES(),
+ getSI(),
+ ticks
+ ));
+
+ ScheduleEvent(pXecb, ticks);
+}
+
+
+VOID
+VwIPXScheduleIPXEvent(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Schedules a an event to occur in some number of ticks. When the tick count
+ reaches 0, the ECB InUse field is cleared and any ESR called
+
+ This call is Asynchronous
+
+Arguments:
+
+ Inputs
+ BX 05h
+ AX Delay time - number of 1/18 second ticks
+ ES:SI ECB address
+
+ Outputs
+ Nothing
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LPECB pEcb;
+ WORD ticks = IPX_TICKS_PARM();
+
+ CHECK_INTERRUPTS("VwIPXScheduleIPXEvent");
+
+ IPX_GET_IPX_ECB(pEcb);
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_IPXScheduleIPXEvent,
+ IPXDBG_LEVEL_INFO,
+ "VwIPXScheduleIPXEvent(%04x:%04x, %04x)\n",
+ getES(),
+ getSI(),
+ ticks
+ ));
+
+ _VwIPXScheduleIPXEvent( ticks, pEcb, ECB_PARM_ADDRESS() );
+
+}
+
+
+VOID
+VwIPXSendPacket(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Sends a packet to the target machine/router. This call can be made on a
+ socket that is not open
+
+ The app must have filled in the following IPX_ECB fields:
+
+ EsrAddress
+ Socket
+ ImmediateAddress
+ FragmentCount
+ fragment descriptor fields
+
+ and the following IPX_PACKET fields:
+
+ PacketType
+ Destination.Net
+ Destination.Node
+ Destination.Socket
+
+ This call is Asynchronous
+
+Arguments:
+
+ Inputs
+ BX 03h
+ CX DOS PDB. This parameter is not part of the IPX API.
+ Added because we need to remember which DOS executable owns the
+ socket IF WE MUST CREATE A TEMPORTARY SOCKET: we need to clean-up
+ short-lived sockets when the executable terminates
+ ES:SI ECB Address
+
+ Outputs
+ Nothing
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LPECB pEcb;
+ WORD owner;
+
+ CHECK_INTERRUPTS("VwIPXSendPacket");
+
+ IPX_GET_IPX_ECB(pEcb);
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_IPXSendPacket,
+ IPXDBG_LEVEL_INFO,
+ "VwIPXSendPacket(%04x:%04x), owner = %04x\n",
+ getES(),
+ getSI(),
+ IPX_SOCKET_OWNER_PARM()
+ ));
+
+ _VwIPXSendPacket(pEcb,
+ ECB_PARM_ADDRESS(),
+ IPX_SOCKET_OWNER_PARM()
+ );
+}
+
+
+VOID
+VwIPXSendWithChecksum(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ description-of-function.
+
+ This call is Asynchronous
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ CHECK_INTERRUPTS("VwIPXSendWithChecksum");
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_IPXSendWithChecksum,
+ IPXDBG_LEVEL_INFO,
+ "VwIPXSendWithChecksum\n"
+ ));
+}
+
+
+VOID
+VwIPXSPXDeinit(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ description-of-function.
+
+ This call is Synchronous
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ CHECK_INTERRUPTS("VwIPXSPXDeinit");
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_INFO,
+ "VwIPXSPXDeinit\n"
+ ));
+}
+
+
+VOID
+VwIPXVerifyChecksum(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ description-of-function.
+
+ This call is Synchronous
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ CHECK_INTERRUPTS("VwIPXVerifyChecksum");
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_IPXVerifyChecksum,
+ IPXDBG_LEVEL_INFO,
+ "VwIPXVerifyChecksum\n"
+ ));
+}
+
+
+VOID
+VwSPXAbortConnection(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Aborts this end of a connection
+
+ This call is Asynchronous
+
+Arguments:
+
+ Inputs
+ BX 14h
+ DX Connection ID
+
+ Outputs
+ Nothing
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ WORD connectionId = SPX_CONNECTION_PARM();
+
+ CHECK_INTERRUPTS("VwSPXAbortConnection");
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_SPXAbortConnection,
+ IPXDBG_LEVEL_INFO,
+ "VwSPXAbortConnection(%04x)\n",
+ connectionId
+ ));
+
+ _VwSPXAbortConnection(connectionId);
+}
+
+
+VOID
+VwSPXEstablishConnection(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Creates a connection with a remote SPX socket. The remote end can be on
+ this machine (i.e. same app in DOS world)
+
+ This call is Asynchronous
+
+Arguments:
+
+ Inputs
+ BX 11h
+ AL Retry count
+ AH WatchDog flag
+ ES:SI ECB Address
+
+ Outputs
+ AL Completion code:
+ 00h Attempting to talk to remote
+ EFh Local connection table full
+ FDh Fragment count not 1; buffer size not 42
+ FFh Send socket not open
+ DX Connection ID
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ WORD status;
+ BYTE retryCount = SPX_RETRY_COUNT_PARM();
+ BYTE watchDogFlag = SPX_WATCHDOG_FLAG_PARM();
+ WORD connectionId;
+ LPECB pEcb;
+
+ CHECK_INTERRUPTS("VwSPXEstablishConnection");
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_SPXEstablishConnection,
+ IPXDBG_LEVEL_INFO,
+ "VwSPXEstablishConnection(%02x, %02x, %04x:%04x)\n",
+ retryCount,
+ watchDogFlag,
+ ECB_PARM_SEGMENT(),
+ ECB_PARM_OFFSET()
+ ));
+
+ IPX_GET_IPX_ECB( pEcb );
+
+ IPXDUMPECB((pEcb, getES(), getSI(), ECB_TYPE_SPX, TRUE, TRUE, FALSE));
+
+ status = _VwSPXEstablishConnection( retryCount,
+ watchDogFlag,
+ &connectionId,
+ pEcb,
+ ECB_PARM_ADDRESS() );
+
+
+ SPX_SET_CONNECTION_ID( connectionId );
+ SPX_SET_STATUS( status );
+}
+
+
+VOID
+VwSPXGetConnectionStatus(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Returns buffer crammed full of useful statistics or something (hu hu huh)
+
+ This call is Synchronous
+
+Arguments:
+
+ Inputs
+ BX 15h
+ DX Connection ID
+ ES:SI Buffer address
+
+ Outputs
+ AL Completion code:
+ 00h Connection is active
+ EEh No such connection
+
+ on output, buffer in ES:SI contains:
+
+ BYTE ConnectionStatus
+ BYTE WatchDogActive
+ WORD LocalConnectionID
+ WORD RemoteConnectionID
+ WORD SequenceNumber
+ WORD LocalAckNumber
+ WORD LocalAllocationNumber
+ WORD RemoteAckNumber
+ WORD RemoteAllocationNumber
+ WORD LocalSocket
+ BYTE ImmediateAddress[6]
+ BYTE RemoteNetwork[4]
+ WORD RetransmissionCount
+ WORD RetransmittedPackets
+ WORD SuppressedPackets
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ WORD status;
+ WORD connectionId = SPX_CONNECTION_PARM();
+ LPSPX_CONNECTION_STATS pStats = (LPSPX_CONNECTION_STATS)SPX_BUFFER_PARM(sizeof(*pStats));
+
+ CHECK_INTERRUPTS("VwSPXGetConnectionStatus");
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_SPXGetConnectionStatus,
+ IPXDBG_LEVEL_INFO,
+ "VwSPXGetConnectionStatus: connectionId=%04x\n",
+ connectionId
+ ));
+
+ status = _VwSPXGetConnectionStatus( connectionId,
+ pStats );
+
+
+ SPX_SET_STATUS(status);
+}
+
+
+VOID
+VwSPXInitialize(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Informs the app that SPX is present on this station
+
+ This call is Synchronous
+
+Arguments:
+
+ Inputs
+ BX 10h
+ AL 00h
+
+ Outputs
+ AL Installation flag:
+ 00h Not installed
+ FFh Installed
+ BH SPX Major revision number
+ BL SPX Minor revision number
+ CX Maximum SPX connections supported
+ normally from SHELL.CFG
+ DX Available SPX connections
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ WORD status;
+ BYTE majorRevisionNumber;
+ BYTE minorRevisionNumber;
+ WORD maxConnections;
+ WORD availableConnections;
+
+ CHECK_INTERRUPTS("VwSPXInitialize");
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_SPXInitialize,
+ IPXDBG_LEVEL_INFO,
+ "VwSPXInitialize\n"
+ ));
+
+
+ status = _VwSPXInitialize( &majorRevisionNumber,
+ &minorRevisionNumber,
+ &maxConnections,
+ &availableConnections );
+
+
+ setBH( majorRevisionNumber );
+ setBL( minorRevisionNumber );
+ setCX( maxConnections );
+ setDX( availableConnections );
+ SPX_SET_STATUS(status);
+}
+
+
+VOID
+VwSPXListenForConnection(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Listens for an incoming connection request
+
+ This call is Asynchronous
+
+Arguments:
+
+ Inputs
+ BX 12h
+ AL Retry count
+ AH SPX WatchDog flag
+ ES:SI ECB Address
+
+ Outputs
+ Nothing
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ BYTE retryCount = SPX_RETRY_COUNT_PARM();
+ BYTE watchDogFlag = SPX_WATCHDOG_FLAG_PARM();
+ LPECB pEcb;
+
+ CHECK_INTERRUPTS("VwSPXListenForConnection");
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_SPXListenForConnection,
+ IPXDBG_LEVEL_INFO,
+ "VwSPXListenForConnection(%02x, %02x, %04x:%04x)\n",
+ retryCount,
+ watchDogFlag,
+ ECB_PARM_SEGMENT(),
+ ECB_PARM_OFFSET()
+ ));
+
+ IPX_GET_IPX_ECB( pEcb );
+
+ IPXDUMPECB((pEcb, getES(), getSI(), ECB_TYPE_SPX, TRUE, FALSE, FALSE));
+
+ _VwSPXListenForConnection( retryCount,
+ watchDogFlag,
+ pEcb,
+ ECB_PARM_ADDRESS() );
+}
+
+
+VOID
+VwSPXListenForSequencedPacket(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Attempts to receive an SPX packet. This call is made against the top-level
+ socket (the socket in SPX-speak, not the connection). We can receive a
+ packet from any connection assigned to this socket. In this function, we
+ just queue the ECB (since there is no return status, we expect that the
+ app has supplied an ESR) and let AES handle it
+
+ This call is Asynchronous
+
+Arguments:
+
+ Inputs
+ BX 17h
+ ES:SI ECB Address
+
+ Outputs
+ Nothing
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LPECB pEcb;
+
+ CHECK_INTERRUPTS("VwSPXListenForSequencedPacket");
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_SPXListenForSequencedPacket,
+ IPXDBG_LEVEL_INFO,
+ "VwSPXListenForSequencedPacket(%04x:%04x)\n",
+ ECB_PARM_SEGMENT(),
+ ECB_PARM_OFFSET()
+ ));
+
+ IPX_GET_IPX_ECB( pEcb );
+
+ IPXDUMPECB((pEcb, getES(), getSI(), ECB_TYPE_SPX, TRUE, FALSE, FALSE));
+
+ _VwSPXListenForSequencedPacket( pEcb,
+ ECB_PARM_ADDRESS());
+
+}
+
+
+VOID
+VwSPXSendSequencedPacket(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Sends a packet on an SPX connection
+
+ This call is Asynchronous
+
+Arguments:
+
+ Inputs
+ BX 16h
+ DX Connection ID
+ ES:SI ECB address
+
+ Outputs
+ Nothing
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ WORD connectionId = SPX_CONNECTION_PARM();
+ LPECB pEcb;
+
+ CHECK_INTERRUPTS("VwSPXSendSequencedPacket""VwSPXSendSequencedPacket");
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_SPXSendSequencedPacket,
+ IPXDBG_LEVEL_INFO,
+ "VwSPXSendSequencedPacket(%04x, %04x:%04x)\n",
+ connectionId,
+ getES(),
+ getSI()
+ ));
+
+ IPX_GET_IPX_ECB( pEcb );
+
+ IPXDUMPECB((pEcb, getES(), getSI(), ECB_TYPE_SPX, TRUE, TRUE, FALSE));
+
+ _VwSPXSendSequencedPacket( connectionId,
+ pEcb,
+ ECB_PARM_ADDRESS() );
+
+}
+
+
+VOID
+VwSPXTerminateConnection(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Terminates a connection
+
+ This call is Asynchronous
+
+Arguments:
+
+ Inputs
+ BX 13h
+ DX Connection ID
+ ES:SI ECB Address
+
+ Outputs
+ Nothing
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ WORD connectionId = SPX_CONNECTION_PARM();
+ LPECB pEcb;
+
+ CHECK_INTERRUPTS("VwSPXTerminateConnection");
+
+ IPX_GET_IPX_ECB( pEcb );
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_SPXTerminateConnection,
+ IPXDBG_LEVEL_INFO,
+ "VwSPXTerminateConnection(%04x, %04x:%04x)\n",
+ connectionId,
+ ECB_PARM_SEGMENT(),
+ ECB_PARM_OFFSET()
+ ));
+
+ _VwSPXTerminateConnection(connectionId, pEcb, ECB_PARM_ADDRESS());
+}
diff --git a/private/nw/vwipxspx/dll/vwinapi.c b/private/nw/vwipxspx/dll/vwinapi.c
new file mode 100644
index 000000000..303be996c
--- /dev/null
+++ b/private/nw/vwipxspx/dll/vwinapi.c
@@ -0,0 +1,1185 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ vwinapi.c
+
+Abstract:
+
+ ntVdm netWare (Vw) IPX/SPX Functions
+
+ Contains handlers for WOW IPX/SPX calls (netware functions). The IPX/SPX
+ APIs use WinSock to perform the actual operations
+
+ Contents:
+ VWinIPXCancelEvent
+ VWinIPXCloseSocket
+ VWinIPXDisconnectFromTarget
+ VWinIPXGetInternetworkAddress
+ VWinIPXGetIntervalMarker
+ VWinIPXGetLocalTarget
+ VWinIPXGetLocalTargetAsync
+ VWinIPXGetMaxPacketSize
+ VWinIPXInitialize
+ VWinIPXListenForPacket
+ VWinIPXOpenSocket
+ VWinIPXRelinquishControl
+ VWinIPXScheduleIPXEvent
+ VWinIPXSendPacket
+ VWinIPXSPXDeinit
+
+ VWinSPXAbortConnection
+ VWinSPXEstablishConnection
+ VWinSPXGetConnectionStatus
+ VWinSPXInitialize
+ VWinSPXListenForConnection
+ VWinSPXListenForSequencedPacket
+ VWinSPXSendSequencedPacket
+ VWinSPXTerminateConnection
+
+Author:
+
+ Yi-Hsin Sung ( yihsins ) 28-Oct-1993
+
+Environment:
+
+ User-mode Win32
+
+Revision History:
+
+ 28-Oct-1993 yihsins
+ Created
+
+--*/
+
+#include "vw.h"
+#pragma hdrstop
+
+//
+// functions
+//
+
+
+WORD
+VWinIPXCancelEvent(
+ IN DWORD IPXTaskID,
+ IN LPECB pEcb
+ )
+
+/*++
+
+Routine Description:
+
+ Cancels event described by an ECB
+
+ This call is Synchronous
+
+Arguments:
+
+ Inputs
+ IPXTaskID
+ pECB
+
+Return Value:
+
+ 00h Success
+ F9h Can't cancel ECB
+ FFh ECB not in use
+
+--*/
+
+{
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_IPXCancelEvent,
+ IPXDBG_LEVEL_INFO,
+ "VWinIPXCancelEvent\n"
+ ));
+
+ // ignore IPXTaskID for now
+ UNREFERENCED_PARAMETER( IPXTaskID );
+
+ return _VwIPXCancelEvent( pEcb );
+}
+
+
+VOID
+VWinIPXCloseSocket(
+ IN DWORD IPXTaskID,
+ IN WORD socketNumber
+ )
+
+/*++
+
+Routine Description:
+
+ Closes a socket and cancels any outstanding events on the socket.
+ Closing an unopened socket does not return an error
+ ESRs in cancelled ECBs are not called
+
+ This call is Synchronous
+
+Arguments:
+
+ Inputs
+ IPXTaskID
+ socketNumber
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_IPXCloseSocket,
+ IPXDBG_LEVEL_INFO,
+ "VWinIPXCloseSocket(%#x)\n",
+ B2LW(socketNumber)
+ ));
+
+ // ignore IPXTaskID for now
+ UNREFERENCED_PARAMETER( IPXTaskID );
+
+ _VwIPXCloseSocket( socketNumber );
+}
+
+
+VOID
+VWinIPXDisconnectFromTarget(
+ IN DWORD IPXTaskID,
+ IN LPBYTE pNetworkAddress
+ )
+
+/*++
+
+Routine Description:
+
+ Performs no action for NTVDM IPX
+
+ This call is Synchronous
+
+Arguments:
+
+ Inputs
+ IPXTaskID
+ pNetworkAddress
+
+ Outputs
+ Nothing
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_IPXDisconnectFromTarget,
+ IPXDBG_LEVEL_INFO,
+ "VWinIPXDisconnectFromTarget\n"
+ ));
+}
+
+
+VOID
+VWinIPXGetInternetworkAddress(
+ IN DWORD IPXTaskID,
+ OUT LPINTERNET_ADDRESS pNetworkAddress
+ )
+
+/*++
+
+Routine Description:
+
+ Returns a buffer containing the net number and node number for this
+ station.
+
+ This function cannot return an error (!)
+
+ Assumes: 1. GetInternetAddress has been successfully called in the
+ DLL initialization phase
+
+ This call is Synchronous
+
+Arguments:
+
+ Inputs
+ IPXTaskID
+
+ Outputs
+ pNetworkAddress
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_IPXGetInternetworkAddress,
+ IPXDBG_LEVEL_INFO,
+ "VWinIPXGetInternetworkAddress\n"
+ ));
+
+ // ignore IPXTaskID for now
+ UNREFERENCED_PARAMETER( IPXTaskID );
+
+ _VwIPXGetInternetworkAddress( pNetworkAddress );
+
+}
+
+
+WORD
+VWinIPXGetIntervalMarker(
+ IN DWORD IPXTaskID
+ )
+
+/*++
+
+Routine Description:
+
+ Just returns the tick count maintained by Asynchronous Event Scheduler
+
+ This call is Synchronous
+
+Arguments:
+
+ Inputs
+ IPXTaskID
+
+ Outputs
+
+Return Value:
+
+ The tick count.
+
+--*/
+
+{
+ WORD intervalMarker = _VwIPXGetIntervalMarker();
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_IPXGetIntervalMarker,
+ IPXDBG_LEVEL_INFO,
+ "VWinIPXGetIntervalMarker: Returning %04x\n",
+ intervalMarker
+ ));
+
+ // ignore IPXTaskID for now
+ UNREFERENCED_PARAMETER( IPXTaskID );
+
+ return intervalMarker;
+}
+
+
+WORD
+VWinIPXGetLocalTarget(
+ IN DWORD IPXTaskID,
+ IN LPBYTE pNetworkAddress,
+ OUT LPBYTE pImmediateAddress,
+ OUT ULPWORD pTransportTime
+ )
+
+/*++
+
+Routine Description:
+
+ Given a target address of the form (network address {4}, node address {6}),
+ returns the node address of the target if on the same network, or the node
+ address of the router which knows how to get to the next hop in reaching the
+ eventual target
+
+ This call is Synchronous
+
+Arguments:
+
+ Inputs
+ IPXTaskID
+ pNetworkAddress
+
+ Outputs
+ pImmediateAddress
+ pTransportTime
+
+
+Return Value:
+
+ 00h Success
+ F1h Ipx/Spx Not Initialized
+ FAh No path to destination node found
+
+--*/
+
+{
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_IPXGetLocalTarget,
+ IPXDBG_LEVEL_INFO,
+ "VWinIPXGetLocalTarget\n"
+ ));
+
+ // ignore IPXTaskID for now
+ UNREFERENCED_PARAMETER( IPXTaskID );
+
+ return _VwIPXGetLocalTarget( pNetworkAddress,
+ pImmediateAddress,
+ pTransportTime );
+}
+
+
+WORD
+VWinIPXGetLocalTargetAsync(
+ IN LPBYTE pSendAGLT,
+ OUT LPBYTE pListenAGLT,
+ IN WORD windowsHandle
+ )
+
+/*++
+
+Routine Description:
+
+ description-of-function.
+
+ This call is Asynchronous
+
+Arguments:
+
+ pSendAGLT
+ pListenAGLT
+ windowsHandle
+
+Return Value:
+
+ 00h Success
+ F1h Ipx/Spx Not Initialized
+ FAh No Local Target Identified
+
+--*/
+
+{
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_INFO,
+ "VWinIPXGetLocalTargetAsync\n"
+ ));
+
+ return IPX_SUCCESS; // return success for now
+}
+
+
+WORD
+VWinIPXGetMaxPacketSize(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Returns the maximum packet size the underlying network can handle
+
+ Assumes: 1. A successfull call to GetMaxPacketSize has been made during
+ DLL initialization
+ 2. Maximum packet size is constant
+
+ This call is Synchronous
+
+Arguments:
+
+ Inputs
+ None.
+
+Return Value:
+
+ The max packet size.
+
+--*/
+
+{
+ //
+ // this is a WORD function in DOS and Windows: always return MaxPacketSize
+ // in AX
+ //
+
+ WORD maxPacketSize = _VwIPXGetMaxPacketSize( NULL );
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_IPXGetMaxPacketSize,
+ IPXDBG_LEVEL_INFO,
+ "VWinIPXGetMaxPacketSize: PacketSize=%d\n",
+ maxPacketSize
+ ));
+
+ return maxPacketSize;
+}
+
+
+WORD
+VWinIPXInitialize(
+ IN OUT ULPDWORD pIPXTaskID,
+ IN WORD maxECBs,
+ IN WORD maxPacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ Get the entry address for the IPX Interface.
+
+Arguments:
+
+ Inputs
+ maxECBs
+ maxPacketSize
+
+ Output
+ pIPXTaskID
+
+Return Value:
+
+ 00h Success
+ F0h Ipx NotInstalled
+ F1h Ipx/Spx Not Initialized
+ F2h No Dos Memory
+ F3h No Free Ecb
+ F4h Lock Failed
+ F5h Over the maximum limit
+ F6h Ipx/Spx Previously Initialized
+
+--*/
+
+{
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_INFO,
+ "VWinIPXInitialize (MaxECBs=%04x, MaxPacketSize=%04x)\n",
+ maxECBs,
+ maxPacketSize
+ ));
+
+ UNREFERENCED_PARAMETER( maxECBs ); // ignore for now
+ UNREFERENCED_PARAMETER( maxPacketSize ); // ignore for now
+
+// *pIPXTaskID = 0; // BUGBUG Can we ignore this?
+
+ return IPX_SUCCESS;
+}
+
+
+VOID
+VWinIPXListenForPacket(
+ IN DWORD IPXTaskID,
+ IN LPECB pEcb,
+ IN ECB_ADDRESS EcbAddress
+ )
+
+/*++
+
+Routine Description:
+
+ Queue a listen request against a socket. All listen requests will be
+ completed asynchronously, unless cancelled by app
+
+ This call is Asynchronous
+
+Arguments:
+
+ Inputs
+ IPXTaskID
+ pEcb
+ EcbAddress
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_IPXListenForPacket,
+ IPXDBG_LEVEL_INFO,
+ "VWinIPXListenForPacket(%04x:%04x)\n",
+ HIWORD(EcbAddress),
+ LOWORD(EcbAddress)
+ ));
+
+ // ignore IPXTaskID for now
+ UNREFERENCED_PARAMETER( IPXTaskID );
+
+ (VOID) _VwIPXListenForPacket( pEcb, EcbAddress );
+}
+
+
+WORD
+VWinIPXOpenSocket(
+ IN DWORD IPXTaskID,
+ IN OUT ULPWORD pSocketNumber,
+ IN BYTE socketType
+ )
+
+/*++
+
+Routine Description:
+
+ Opens a socket for use by IPX or SPX.Puts the socket into non-blocking mode.
+ The socket will be bound to IPX.
+
+ This call is Synchronous
+
+Arguments:
+
+ Inputs
+ IPXTaskID
+ *pSocketNumber
+ socketType - Socket Longevity flag
+
+ Outputs
+ pSocketNumber - Assigned socket number
+
+Return Value:
+
+ 00h Success
+ F0h Ipx Not Installed
+ F1h Ipx/Spx Not Initialized
+ FEh Socket table full
+ FFh Socket already open
+
+--*/
+
+{
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_IPXOpenSocket,
+ IPXDBG_LEVEL_INFO,
+ "VwIPXOpenSocket(Life=%02x, Socket=%04x)\n",
+ socketType,
+ B2LW(*pSocketNumber)
+ ));
+
+ // ignore IPXTaskID for now
+ UNREFERENCED_PARAMETER( IPXTaskID );
+
+ return _VwIPXOpenSocket( pSocketNumber,
+ socketType,
+ 0 );
+
+}
+
+
+VOID
+VWinIPXRelinquishControl(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Just sleep for a nominal amount. Netware seems to be dependent on the
+ default setting of the PC clock, so one timer tick (1/18 second) would
+ seem to be a good value
+
+ This call is Synchronous
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_IPXRelinquishControl,
+ IPXDBG_LEVEL_INFO,
+ "VWinIPXRelinquishControl\n"
+ ));
+
+ _VwIPXRelinquishControl();
+}
+
+
+VOID
+VWinIPXScheduleIPXEvent(
+ IN DWORD IPXTaskID,
+ IN WORD time,
+ IN LPECB pEcb,
+ IN ECB_ADDRESS EcbAddress
+ )
+
+/*++
+
+Routine Description:
+
+ Schedules a an event to occur in some number of ticks. When the tick count
+ reaches 0, the ECB InUse field is cleared and any ESR called
+
+ This call is Asynchronous
+
+Arguments:
+
+ Inputs
+ IPXTaskID
+ time
+ pEcb
+ EcbAddress
+
+ Outputs
+ Nothing
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_IPXScheduleIPXEvent,
+ IPXDBG_LEVEL_INFO,
+ "VWinIPXScheduleIPXEvent(%04x:%04x, Time:%04x)\n",
+ HIWORD( EcbAddress ),
+ LOWORD( EcbAddress ),
+ time
+ ));
+
+ // ignore IPXTaskID for now
+ UNREFERENCED_PARAMETER( IPXTaskID );
+
+ _VwIPXScheduleIPXEvent( time, pEcb, EcbAddress );
+}
+
+
+VOID
+VWinIPXSendPacket(
+ IN DWORD IPXTaskID,
+ IN LPECB pEcb,
+ IN ECB_ADDRESS EcbAddress
+ )
+
+/*++
+
+Routine Description:
+
+ Sends a packet to the target machine/router. This call can be made on a
+ socket that is not open
+
+ The app must have filled in the following IPX_ECB fields:
+
+ EsrAddress
+ Socket
+ ImmediateAddress
+ FragmentCount
+ fragment descriptor fields
+
+ and the following IPX_PACKET fields:
+
+ PacketType
+ Destination.Net
+ Destination.Node
+ Destination.Socket
+
+ This call is Asynchronous
+
+Arguments:
+
+ Inputs
+ IPXTaskID
+ pEcb
+ EcbAddress
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_IPXSendPacket,
+ IPXDBG_LEVEL_INFO,
+ "VWinIPXSendPacket(%04x:%04x)\n",
+ HIWORD( EcbAddress ),
+ LOWORD( EcbAddress )
+ ));
+
+ // ignore IPXTaskID for now
+ UNREFERENCED_PARAMETER( IPXTaskID );
+
+ _VwIPXSendPacket( pEcb, EcbAddress, 0);
+}
+
+
+WORD
+VWinIPXSPXDeinit(
+ IN DWORD IPXTaskID
+ )
+
+/*++
+
+Routine Description:
+
+ Release any resources allocated to an application by NWIPXSPX.DLL
+ for use by other applications.
+
+ This call is Synchronous
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ 00h Successful
+ F1h IPX/SPX Not Initialized
+
+--*/
+
+{
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_INFO,
+ "VwIPXSPXDeinit\n"
+ ));
+
+ // ignore IPXTaskID for now
+ UNREFERENCED_PARAMETER( IPXTaskID );
+ return IPX_SUCCESS;
+}
+
+
+VOID
+VWinSPXAbortConnection(
+ IN WORD SPXConnectionID
+ )
+
+/*++
+
+Routine Description:
+
+ Abort an SPX connection.
+
+ This call is Synchronous
+
+Arguments:
+
+ SPXConnectionID
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_SPXAbortConnection,
+ IPXDBG_LEVEL_INFO,
+ "VWinSPXAbortConnection(%04x)\n",
+ SPXConnectionID
+ ));
+
+ _VwSPXAbortConnection(SPXConnectionID);
+}
+
+
+WORD
+VWinSPXEstablishConnection(
+ IN DWORD IPXTaskID,
+ IN BYTE retryCount,
+ IN BYTE watchDog,
+ OUT ULPWORD pSPXConnectionID,
+ IN LPECB pEcb,
+ IN ECB_ADDRESS EcbAddress
+ )
+
+/*++
+
+Routine Description:
+
+ Establish a connection with a listening socket.
+
+ This call is Synchronous
+
+Arguments:
+
+ Inputs
+ IPXTaskID
+ retryCount
+ watchDog
+ pEcb
+ EcbAddress
+
+ Outputs
+ pSPXConnectionID
+ pEcb
+
+Return Value:
+
+ 00h Success
+ EFh Connection Table Full
+ F1h IPX/SPX Not Initialized
+ FDh Malformed Packet
+ FFh Socket Not Opened
+
+--*/
+
+{
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_SPXEstablishConnection,
+ IPXDBG_LEVEL_INFO,
+ "VWinSPXEstablishConnection(%02x, %02x, %04x:%04x)\n",
+ retryCount,
+ watchDog,
+ HIWORD(EcbAddress),
+ LOWORD(EcbAddress)
+ ));
+
+ // ignore IPXTaskID for now
+ UNREFERENCED_PARAMETER( IPXTaskID );
+
+ return _VwSPXEstablishConnection( retryCount,
+ watchDog,
+ pSPXConnectionID,
+ pEcb,
+ EcbAddress );
+}
+
+
+WORD
+VWinSPXGetConnectionStatus(
+ IN DWORD IPXTaskID,
+ IN WORD SPXConnectionID,
+ IN LPSPX_CONNECTION_STATS pConnectionStats
+ )
+
+/*++
+
+Routine Description:
+
+ Return the status of an SPX connection.
+
+ This call is Synchronous
+
+Arguments:
+
+ Inputs
+ IPXTaskID
+ SPXConnectionID
+
+ Outputs
+ pConnectionStats
+
+Return Value:
+
+ 00h Success
+ EEh Invalid Connection
+ F1h IPX/SPX Not Initialized
+
+--*/
+
+{
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_SPXGetConnectionStatus,
+ IPXDBG_LEVEL_INFO,
+ "VWinSPXGetConnectionStatus\n"
+ ));
+
+ // ignore IPXTaskID for now
+ UNREFERENCED_PARAMETER( IPXTaskID );
+
+ return _VwSPXGetConnectionStatus( SPXConnectionID,
+ pConnectionStats );
+}
+
+
+WORD
+VWinSPXInitialize(
+ IN OUT ULPDWORD pIPXTaskID,
+ IN WORD maxECBs,
+ IN WORD maxPacketSize,
+ OUT LPBYTE pMajorRevisionNumber,
+ OUT LPBYTE pMinorRevisionNumber,
+ OUT ULPWORD pMaxConnections,
+ OUT ULPWORD pAvailableConnections
+ )
+
+/*++
+
+Routine Description:
+
+ Informs the app that SPX is present on this station
+
+ This call is Synchronous
+
+Arguments:
+
+ pIPXTaskID - on input, specifies how resources will be
+ allocated:
+
+ 0x00000000 - directly to calling application
+ 0xFFFFFFFE - directly to calling application,
+ but multiple initializations are
+ allowed
+ 0xFFFFFFFF - resources allocated in a pool for
+ multiple applications
+ maxECBs - maximum number of outstanding ECBs
+ maxPacketSize - maximum packet size to be sent by the app
+ pMajorRevisionNumber - returned SPX major version #
+ pMinorRevisionNumber - returned SPX minor version #
+ pMaxConnections - maximum connections supported by this SPX version
+ pAvailableConnections - number of connections available to this app
+
+Return Value:
+
+ WORD
+ 0x0000 SPX not installed
+ 0x00F1 IPX/SPX not installed
+ 0x00F2 no DOS memory
+ 0x00F3 no free ECBs
+ 0x00F4 lock failed
+ 0x00F5 exceeded maximum limit
+ 0x00F6 IPX/SPX already initialized
+ 0x00FF SPX installed
+
+--*/
+
+{
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_SPXInitialize,
+ IPXDBG_LEVEL_INFO,
+ "VWinSPXInitialize\n"
+ ));
+
+ UNREFERENCED_PARAMETER( maxECBs ); // ignore for now
+ UNREFERENCED_PARAMETER( maxPacketSize ); // ignore for now
+
+ //
+ // do the same thing as 16-bit windows and return the task ID unchanged
+ //
+
+// *pIPXTaskID = 0;
+
+ return _VwSPXInitialize( pMajorRevisionNumber,
+ pMinorRevisionNumber,
+ pMaxConnections,
+ pAvailableConnections );
+}
+
+
+VOID
+VWinSPXListenForConnection(
+ IN DWORD IPXTaskID,
+ IN BYTE retryCount,
+ IN BYTE watchDog,
+ IN LPECB pEcb,
+ IN ECB_ADDRESS EcbAddress
+ )
+
+/*++
+
+Routine Description:
+
+ Listens for an incoming connection request
+
+ This call is Asynchronous
+
+Arguments:
+
+ Inputs
+ IPXTaskID
+ retryCount
+ watchDogFlag
+ pEcb
+ EcbAddress
+
+ Outputs
+ Nothing
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_SPXListenForConnection,
+ IPXDBG_LEVEL_INFO,
+ "VWinSPXListenForConnection(%02x, %02x, %04x:%04x)\n",
+ retryCount,
+ watchDog,
+ HIWORD(EcbAddress),
+ LOWORD(EcbAddress)
+ ));
+
+ // ignore IPXTaskID for now
+ UNREFERENCED_PARAMETER( IPXTaskID );
+
+ _VwSPXListenForConnection( retryCount,
+ watchDog,
+ pEcb,
+ EcbAddress );
+}
+
+
+VOID
+VWinSPXListenForSequencedPacket(
+ IN DWORD IPXTaskID,
+ IN LPECB pEcb,
+ IN ECB_ADDRESS EcbAddress
+ )
+
+/*++
+
+Routine Description:
+
+ Attempts to receive an SPX packet.
+
+ This call is Asynchronous
+
+Arguments:
+
+ Inputs
+ IPXTaskID
+ pEcb
+ EcbAddress
+
+ Outputs
+ Nothing
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_SPXListenForSequencedPacket,
+ IPXDBG_LEVEL_INFO,
+ "VWinSPXListenForSequencedPacket(%04x:%04x)\n",
+ HIWORD(EcbAddress),
+ LOWORD(EcbAddress)
+ ));
+
+ // ignore IPXTaskID for now
+ UNREFERENCED_PARAMETER( IPXTaskID );
+
+ _VwSPXListenForSequencedPacket( pEcb,
+ EcbAddress );
+}
+
+
+VOID
+VWinSPXSendSequencedPacket(
+ IN DWORD IPXTaskID,
+ IN WORD SPXConnectionID,
+ IN LPECB pEcb,
+ IN ECB_ADDRESS EcbAddress
+ )
+
+/*++
+
+Routine Description:
+
+ Sends a packet on an SPX connection
+
+ This call is Asynchronous
+
+Arguments:
+
+ Inputs
+ IPXTaskID
+ SPXConnectionID
+ pEcb
+ EcbAddress
+
+ Outputs
+ Nothing
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_SPXSendSequencedPacket,
+ IPXDBG_LEVEL_INFO,
+ "VWinSPXSendSequencedPacket(%04x, %04x:%04x)\n",
+ SPXConnectionID,
+ HIWORD(EcbAddress),
+ LOWORD(EcbAddress)
+ ));
+
+ // ignore IPXTaskID for now
+ UNREFERENCED_PARAMETER( IPXTaskID );
+
+ _VwSPXSendSequencedPacket( SPXConnectionID,
+ pEcb,
+ EcbAddress );
+}
+
+
+VOID
+VWinSPXTerminateConnection(
+ IN DWORD IPXTaskID,
+ IN WORD SPXConnectionID,
+ IN LPECB pEcb,
+ IN ECB_ADDRESS EcbAddress
+ )
+
+/*++
+
+Routine Description:
+
+ Terminate an SPX connection by passing a connection ID and an
+ ECB address to SPX. Then return control to the calling application.
+
+ This call is Asynchronous
+
+Arguments:
+
+ Inputs
+ IPXTaskID
+ SPXConnectionID
+ pEcb
+ EcbAddress
+
+ Outputs
+ Nothing
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_SPXTerminateConnection,
+ IPXDBG_LEVEL_INFO,
+ "VWinSPXTerminateConnection(%04x, %04x:%04x)\n",
+ SPXConnectionID,
+ HIWORD(EcbAddress),
+ LOWORD(EcbAddress)
+ ));
+
+ // ignore IPXTaskID for now
+
+ UNREFERENCED_PARAMETER( IPXTaskID );
+
+ _VwSPXTerminateConnection(SPXConnectionID, pEcb, EcbAddress);
+}
diff --git a/private/nw/vwipxspx/dll/vwinapi.h b/private/nw/vwipxspx/dll/vwinapi.h
new file mode 100644
index 000000000..d706d7c87
--- /dev/null
+++ b/private/nw/vwipxspx/dll/vwinapi.h
@@ -0,0 +1,186 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ vwinapi.h
+
+Abstract:
+
+ Contains function prototypes for WIN IPX/SPX functions
+
+Author:
+
+
+Environment:
+
+ User-mode Win32
+
+Revision History:
+
+ 28-Oct-1993 yihsins
+ Created
+
+--*/
+
+WORD
+VWinIPXCancelEvent(
+ IN DWORD IPXTaskID,
+ IN LPECB pEcb
+ );
+
+VOID
+VWinIPXCloseSocket(
+ IN DWORD IPXTaskID,
+ IN WORD socketNumber
+ );
+
+VOID
+VWinIPXDisconnectFromTarget(
+ IN DWORD IPXTaskID,
+ OUT LPBYTE pNetworkAddress
+ );
+
+VOID
+VWinIPXGetInternetworkAddress(
+ IN DWORD IPXTaskID,
+ OUT LPINTERNET_ADDRESS pNetworkAddress
+ );
+
+WORD
+VWinIPXGetIntervalMarker(
+ IN DWORD IPXTaskID
+ );
+
+WORD
+VWinIPXGetLocalTarget(
+ IN DWORD IPXTaskID,
+ IN LPBYTE pNetworkAddress,
+ OUT LPBYTE pImmediateAddress,
+ OUT ULPWORD pTransportTime
+ );
+
+WORD
+VWinIPXGetLocalTargetAsync(
+ IN LPBYTE pSendAGLT,
+ OUT LPBYTE pListenAGLT,
+ IN WORD windowsHandle
+ );
+
+WORD
+VWinIPXGetMaxPacketSize(
+ VOID
+ );
+
+WORD
+VWinIPXInitialize(
+ IN OUT ULPDWORD pIPXTaskID,
+ IN WORD maxECBs,
+ IN WORD maxPacketSize
+ );
+
+VOID
+VWinIPXListenForPacket(
+ DWORD IPXTaskID,
+ LPECB pEcb,
+ ECB_ADDRESS EcbAddress
+ );
+
+WORD
+VWinIPXOpenSocket(
+ IN DWORD IPXTaskID,
+ IN OUT ULPWORD pSocketNumber,
+ IN BYTE socketType
+ );
+
+VOID
+VWinIPXRelinquishControl(
+ VOID
+ );
+
+VOID
+VWinIPXScheduleIPXEvent(
+ IN DWORD IPXTaskID,
+ IN WORD time,
+ IN LPECB pEcb,
+ IN ECB_ADDRESS EcbAddress
+ );
+
+VOID
+VWinIPXSendPacket(
+ IN DWORD IPXTaskID,
+ IN LPECB pEcb,
+ IN ECB_ADDRESS EcbAddress
+ );
+
+WORD
+VWinIPXSPXDeinit(
+ IN DWORD IPXTaskID
+ );
+
+VOID
+VWinSPXAbortConnection(
+ IN WORD SPXConnectionID
+ );
+
+WORD
+VWinSPXEstablishConnection(
+ IN DWORD IPXTaskID,
+ IN BYTE retryCount,
+ IN BYTE watchDog,
+ OUT ULPWORD pSPXConnectionID,
+ IN LPECB pEcb,
+ IN ECB_ADDRESS EcbAddress
+ );
+
+WORD
+VWinSPXGetConnectionStatus(
+ IN DWORD IPXTaskID,
+ IN WORD SPXConnectionID,
+ IN LPSPX_CONNECTION_STATS pConnectionStats
+ );
+
+WORD
+VWinSPXInitialize(
+ IN OUT DWORD UNALIGNED* pIPXTaskID,
+ IN WORD maxECBs,
+ IN WORD maxPacketSize,
+ OUT LPBYTE pMajorRevisionNumber,
+ OUT LPBYTE pMinorRevisionNumber,
+ OUT WORD UNALIGNED* pMaxConnections,
+ OUT WORD UNALIGNED* pAvailableConnections
+ );
+
+VOID
+VWinSPXListenForConnection(
+ IN DWORD IPXTaskID,
+ IN BYTE retryCount,
+ IN BYTE watchDog,
+ IN LPECB pEcb,
+ IN ECB_ADDRESS EcbAddress
+ );
+
+
+VOID
+VWinSPXListenForSequencedPacket(
+ IN DWORD IPXTaskID,
+ IN LPECB pEcb,
+ IN ECB_ADDRESS EcbAddress
+ );
+
+VOID
+VWinSPXSendSequencedPacket(
+ IN DWORD IPXTaskID,
+ IN WORD SPXConnectionID,
+ IN LPECB pEcb,
+ IN ECB_ADDRESS EcbAddress
+ );
+
+VOID
+VWinSPXTerminateConnection(
+ IN DWORD IPXTaskID,
+ IN WORD SPXConnectionID,
+ IN LPECB pEcb,
+ IN ECB_ADDRESS EcbAddress
+ );
diff --git a/private/nw/vwipxspx/dll/vwint.h b/private/nw/vwipxspx/dll/vwint.h
new file mode 100644
index 000000000..25ba92631
--- /dev/null
+++ b/private/nw/vwipxspx/dll/vwint.h
@@ -0,0 +1,146 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ vwint.h
+
+Abstract:
+
+ Contains internal function prototypes used by DOS/WIN IPX/SPX functions
+
+Author:
+
+ Yi-Hsin Sung (yihsins) 28-Oct-1993
+
+Environment:
+
+ User-mode Win32
+
+Revision History:
+
+ 28-Oct-1993 yihsins
+ Created
+
+--*/
+
+WORD
+_VwIPXCancelEvent(
+ IN LPECB pEcb
+ );
+
+VOID
+_VwIPXCloseSocket(
+ IN WORD SocketNumber
+ );
+
+VOID
+_VwIPXGetInternetworkAddress(
+ OUT LPINTERNET_ADDRESS pNetworkAddress
+ );
+
+WORD
+_VwIPXGetIntervalMarker(
+ VOID
+ );
+
+WORD
+_VwIPXGetLocalTarget(
+ IN LPBYTE pNetworkAddress,
+ OUT LPBYTE pImmediateAddress,
+ OUT ULPWORD pTransportTime
+ );
+
+WORD
+_VwIPXGetMaxPacketSize(
+ OUT ULPWORD pRetryCount
+ );
+
+WORD
+_VwIPXListenForPacket(
+ IN OUT LPECB pEcb,
+ IN ECB_ADDRESS EcbAddress
+ );
+
+WORD
+_VwIPXOpenSocket(
+ IN OUT ULPWORD pSocketNumber,
+ IN BYTE SocketType,
+ IN WORD DosPDB
+ );
+
+VOID
+_VwIPXRelinquishControl(
+ VOID
+ );
+
+VOID
+_VwIPXScheduleIPXEvent(
+ IN WORD Time,
+ IN LPECB pEcb,
+ IN ECB_ADDRESS EcbAddress
+ );
+
+VOID
+_VwIPXSendPacket(
+ IN LPECB pEcb,
+ IN ECB_ADDRESS EcbAddress,
+ IN WORD DosPDB
+ );
+
+VOID
+_VwSPXAbortConnection(
+ IN WORD SPXConnectionID
+ );
+
+WORD
+_VwSPXEstablishConnection(
+ IN BYTE RetryCount,
+ IN BYTE WatchDog,
+ OUT ULPWORD pSPXConnectionID,
+ IN LPECB pEcb,
+ IN ECB_ADDRESS EcbAddress
+ );
+
+WORD
+_VwSPXGetConnectionStatus(
+ IN WORD SPXConnectionID,
+ OUT LPSPX_CONNECTION_STATS pStats
+ );
+
+WORD
+_VwSPXInitialize(
+ OUT ULPBYTE pMajorRevisionNumber,
+ OUT ULPBYTE pMinorRevisionNumber,
+ OUT ULPWORD pMaxConnections,
+ OUT ULPWORD pAvailableConnections
+ );
+
+VOID
+_VwSPXListenForConnection(
+ IN BYTE RetryCount,
+ IN BYTE WatchDog,
+ IN LPECB pEcb,
+ IN ECB_ADDRESS EcbAddress
+ );
+
+VOID
+_VwSPXListenForSequencedPacket(
+ IN LPECB pEcb,
+ IN ECB_ADDRESS EcbAddress
+ );
+
+VOID
+_VwSPXSendSequencedPacket(
+ IN WORD SPXConnectionID,
+ IN LPECB pEcb,
+ IN ECB_ADDRESS EcbAddress
+ );
+
+VOID
+_VwSPXTerminateConnection(
+ IN WORD SPXConnectionID,
+ IN LPECB pEcb,
+ IN ECB_ADDRESS EcbAddress
+ );
diff --git a/private/nw/vwipxspx/dll/vwipx.c b/private/nw/vwipxspx/dll/vwipx.c
new file mode 100644
index 000000000..64ddcaf34
--- /dev/null
+++ b/private/nw/vwipxspx/dll/vwipx.c
@@ -0,0 +1,839 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ vwipx.c
+
+Abstract:
+
+ ntVdm netWare (Vw) IPX/SPX Functions
+
+ Vw: The peoples' network
+
+ Internal worker routines for DOS/WOW IPX calls (netware functions).
+ The IPX APIs use WinSock to perform the actual operations
+
+ Contents:
+ _VwIPXCancelEvent
+ _VwIPXCloseSocket
+ _VwIPXGetInternetworkAddress
+ _VwIPXGetIntervalMarker
+ _VwIPXGetLocalTarget
+ _VwIPXGetMaxPacketSize
+ _VwIPXListenForPacket
+ _VwIPXOpenSocket
+ _VwIPXRelinquishControl
+ _VwIPXScheduleIPXEvent
+ _VwIPXSendPacket
+
+Author:
+
+ Richard L Firth (rfirth) 30-Sep-1993
+
+Environment:
+
+ User-mode Win32
+
+Revision History:
+
+ 30-Sep-1993 rfirth
+ Created
+
+--*/
+
+#include "vw.h"
+#pragma hdrstop
+
+extern WORD AesTickCount;
+
+//
+// functions
+//
+
+
+WORD
+_VwIPXCancelEvent(
+ IN LPECB pEcb
+ )
+
+/*++
+
+Routine Description:
+
+ Internal routine shared by DOS and WIN that cancels event
+ described by an ECB
+
+ This call is Synchronous
+
+Arguments:
+
+ Inputs
+ pECB
+
+Return Value:
+
+ 00h Success
+ F9h Can't cancel ECB
+ FFh ECB not in use
+
+--*/
+
+{
+ LPXECB pXecb;
+ WORD status;
+
+ //
+ // BUGBUG: find out what real IPX does if given a NULL pointer
+ //
+
+ if (!pEcb) {
+ return IPX_ECB_NOT_IN_USE;
+ }
+
+ //
+ // BUGBUG: if this ECB references an SPX action then return 0xF9
+ //
+
+ //
+ // if the ECB is still in the state we left it then LinkAddress will be the
+ // address of the XECB which subsequently points back to the ECB. If both
+ // these pan out then we have an ECB which we have at least seen before.
+ // Maybe we can cancel it?
+ //
+ // Note: we grab the serialization semaphore here just in case the AES thread
+ // is about to complete the ECB
+ //
+
+ status = IPX_CANNOT_CANCEL;
+ RequestMutex();
+ pXecb = (LPXECB)pEcb->LinkAddress;
+ if (pXecb) {
+ try {
+ if (pXecb->Ecb == pEcb) {
+ status = IPX_SUCCESS;
+
+ //
+ // pXecb ok: increase reference count in case other thread tries
+ // to deallocate it while we're trying to cancel it
+ //
+
+ ++pXecb->RefCount;
+ }
+ } except(1) {
+
+ //
+ // bad pointer: bogus ECB
+ //
+
+ }
+ } else {
+
+ //
+ // NULL pointer: event probably completed already
+ //
+
+ status = IPX_ECB_NOT_IN_USE;
+ }
+ ReleaseMutex();
+ if (status == IPX_SUCCESS) {
+
+ ECB_CANCEL_ROUTINE cancelRoutine;
+
+ //
+ // we have an ECB to cancel. If we still have it, it will be on one of
+ // the socket queues, the timer list or the async completion list. If
+ // the latter we are in a race. Treat such events as already happened.
+ // We will cancel events on the timer list and queued send and receive
+ // events only
+ //
+
+ switch (pXecb->QueueId) {
+ case NO_QUEUE:
+ status = ECB_CC_CANCELLED;
+ goto cancel_exit;
+
+ case ASYNC_COMPLETION_QUEUE:
+ cancelRoutine = CancelAsyncEvent;
+ break;
+
+ case TIMER_QUEUE:
+ cancelRoutine = CancelTimerEvent;
+ break;
+
+ case SOCKET_LISTEN_QUEUE:
+ case SOCKET_SEND_QUEUE:
+ cancelRoutine = CancelSocketEvent;
+ break;
+
+ case CONNECTION_CONNECT_QUEUE:
+ case CONNECTION_SEND_QUEUE:
+
+ //
+ // SPXEstablishConnection and SPXSendSequencedPacket cannot be
+ // cancelled using IPXCancelEvent
+ //
+
+ status = ECB_CC_CANNOT_CANCEL;
+ goto cancel_exit;
+
+ case CONNECTION_ACCEPT_QUEUE:
+ case CONNECTION_LISTEN_QUEUE:
+ cancelRoutine = CancelConnectionEvent;
+ break;
+ }
+ return cancelRoutine(pXecb);
+ }
+
+ //
+ // app tried to sneak us an unknown ECB, -OR- the ECB was stomped on,
+ // destroying the LinkAddress and hence the address of the XECB. We
+ // could search the various lists looking for an XECB whose Ecb field
+ // matches pEcb, but if the app has scribbled over the ECB when we
+ // (make that Novell) told it not to, chances are it would fail real
+ // well on DOS. Probable worst case is that the app is terminating and
+ // the ECB may sometime later call an ESR which won't be there. Crashola
+ //
+
+cancel_exit:
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_IPXCancelEvent,
+ IPXDBG_LEVEL_ERROR,
+ "VwIPXCancelEvent: cannot find/cancel ECB %04x:%04x\n",
+ HIWORD(pEcb),
+ LOWORD(pEcb)
+ ));
+
+ pEcb->CompletionCode = (BYTE)status;
+ pEcb->InUse = ECB_IU_NOT_IN_USE;
+ return status;
+}
+
+
+VOID
+_VwIPXCloseSocket(
+ IN WORD socketNumber
+ )
+
+/*++
+
+Routine Description:
+
+ Closes a socket and cancels any outstanding events on the socket.
+ Closing an unopened socket does not return an error
+ ESRs in cancelled ECBs are not called
+
+ This call is Synchronous
+
+Arguments:
+
+ Inputs
+ socketNumber
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LPSOCKET_INFO pSocketInfo;
+
+ pSocketInfo = FindSocket(socketNumber);
+ if (pSocketInfo != NULL) {
+ KillSocket(pSocketInfo);
+ } else {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_IPXCloseSocket,
+ IPXDBG_LEVEL_WARNING,
+ "_VwIPXCloseSocket: can't locate socket 0x%04x\n",
+ B2LW(socketNumber)
+ ));
+
+ }
+}
+
+
+VOID
+_VwIPXGetInternetworkAddress(
+ IN LPINTERNET_ADDRESS pNetworkAddress
+ )
+
+/*++
+
+Routine Description:
+
+ Returns a buffer containing the net number and node number for this
+ station.
+
+ This function cannot return an error (!)
+
+ Assumes: 1. GetInternetAddress has been successfully called in the
+ DLL initialization phase
+
+ This call is Synchronous
+
+Arguments:
+
+ Inputs
+ Nothing.
+
+ Outputs
+ pNetworkAddress
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ CopyMemory((LPBYTE)pNetworkAddress,
+ (LPBYTE)&MyInternetAddress.sa_netnum,
+ sizeof(*pNetworkAddress)
+ );
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_IPXGetInternetworkAddress,
+ IPXDBG_LEVEL_INFO,
+ "VwIPXGetInternetworkAddress: %02x-%02x-%02x-%02x : %02x-%02x-%02x-%02x-%02x-%02x\n",
+ pNetworkAddress->Net[0] & 0xff,
+ pNetworkAddress->Net[1] & 0xff,
+ pNetworkAddress->Net[2] & 0xff,
+ pNetworkAddress->Net[3] & 0xff,
+ pNetworkAddress->Node[0] & 0xff,
+ pNetworkAddress->Node[1] & 0xff,
+ pNetworkAddress->Node[2] & 0xff,
+ pNetworkAddress->Node[3] & 0xff,
+ pNetworkAddress->Node[4] & 0xff,
+ pNetworkAddress->Node[5] & 0xff
+ ));
+
+}
+
+
+WORD
+_VwIPXGetIntervalMarker(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Just returns the tick count maintained by Asynchronous Event Scheduler
+
+ This call is Synchronous
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The tick count.
+
+--*/
+
+{
+ Sleep(0);
+ return AesTickCount;
+}
+
+
+WORD
+_VwIPXGetLocalTarget(
+ IN LPBYTE pNetworkAddress,
+ OUT LPBYTE pImmediateAddress,
+ OUT ULPWORD pTransportTime
+ )
+
+/*++
+
+Routine Description:
+
+ Given a target address of the form (network address {4}, node address {6}),
+ returns the node address of the target if on the same network, or the node
+ address of the router which knows how to get to the next hop in reaching the
+ eventual target
+
+ This call is Synchronous
+
+Arguments:
+
+ Inputs
+ pNetworkAddress
+
+ Outputs
+ pImmediateAddress
+ pTransportTime
+
+Return Value:
+
+ 00h Success
+ F1h Ipx/Spx Not Initialized
+ FAh No path to destination node found
+
+--*/
+
+{
+ //
+ // the transport handles real routing, so we always return the immediate
+ // address as the target address. The transport will only look at the
+ // target when routing
+ //
+
+ CopyMemory( pImmediateAddress,
+ pNetworkAddress + 4,
+ 6
+ );
+
+ *pTransportTime = 1; // ticks
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_IPXGetLocalTarget,
+ IPXDBG_LEVEL_INFO,
+ "VwIPXGetLocalTarget: IN: %02x-%02x-%02x-%02x:%02x-%02x-%02x-%02x-%02x-%02x OUT: %02x-%02x-%02x-%02x-%02x-%02x\n",
+ ((LPINTERNET_ADDRESS)pNetworkAddress)->Net[0] & 0xff,
+ ((LPINTERNET_ADDRESS)pNetworkAddress)->Net[1] & 0xff,
+ ((LPINTERNET_ADDRESS)pNetworkAddress)->Net[2] & 0xff,
+ ((LPINTERNET_ADDRESS)pNetworkAddress)->Net[3] & 0xff,
+ ((LPINTERNET_ADDRESS)pNetworkAddress)->Node[0] & 0xff,
+ ((LPINTERNET_ADDRESS)pNetworkAddress)->Node[1] & 0xff,
+ ((LPINTERNET_ADDRESS)pNetworkAddress)->Node[2] & 0xff,
+ ((LPINTERNET_ADDRESS)pNetworkAddress)->Node[3] & 0xff,
+ ((LPINTERNET_ADDRESS)pNetworkAddress)->Node[4] & 0xff,
+ ((LPINTERNET_ADDRESS)pNetworkAddress)->Node[5] & 0xff,
+ pImmediateAddress[0] & 0xff,
+ pImmediateAddress[1] & 0xff,
+ pImmediateAddress[2] & 0xff,
+ pImmediateAddress[3] & 0xff,
+ pImmediateAddress[4] & 0xff,
+ pImmediateAddress[5] & 0xff
+ ));
+
+ return IPX_SUCCESS;
+}
+
+
+
+WORD
+_VwIPXGetMaxPacketSize(
+ OUT ULPWORD pRetryCount
+ )
+
+/*++
+
+Routine Description:
+
+ Returns the maximum packet size the underlying network can handle
+
+ Assumes: 1. A successfull call to GetMaxPacketSize has been made during
+ DLL initialization
+ 2. Maximum packet size is constant
+
+ This call is Synchronous
+
+Arguments:
+
+ Outputs
+ pRetryCount
+
+
+Return Value:
+
+ The maximum packet size.
+
+--*/
+
+{
+ if ( pRetryCount ) {
+ *pRetryCount = 5; // arbitrary?
+ }
+ return MyMaxPacketSize;
+}
+
+
+WORD
+_VwIPXListenForPacket(
+ IN LPECB pEcb,
+ IN ECB_ADDRESS EcbAddress
+ )
+
+/*++
+
+Routine Description:
+
+ Queue a listen request against a socket. All listen requests will be
+ completed asynchronously, unless cancelled by app
+
+ This call is Asynchronous
+
+Arguments:
+
+ Inputs
+ pEcb
+ EcbAddress
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LPXECB pXecb = RetrieveXEcb(ECB_TYPE_IPX, pEcb, EcbAddress);
+ LPSOCKET_INFO pSocketInfo;
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_IPXListenForPacket,
+ IPXDBG_LEVEL_INFO,
+ "_VwIPXListenForPacket(%04x:%04x) socket=%04x ESR=%04x:%04x\n",
+ HIWORD(EcbAddress),
+ LOWORD(EcbAddress),
+ B2LW(pXecb->SocketNumber),
+ HIWORD(pXecb->EsrAddress),
+ LOWORD(pXecb->EsrAddress)
+ ));
+
+ //
+ // don't know what real IPX/SPX does if it gets a NULL pointer
+ //
+
+ if (!pXecb) {
+ return IPX_BAD_REQUEST;
+ }
+
+ //
+ // the socket must be open already before we can perform a listen
+ //
+
+ pSocketInfo = FindSocket(pXecb->SocketNumber);
+
+ //
+ // we also return NON_EXISTENT_SOCKET (0xFF) if the socket is in use for SPX
+ //
+
+ //
+ // BUGBUG: There is nothing in the farty netware documentation that explains
+ // what gets returned if this is the case, only a warning about IPX listens
+ // and sends can't be made on a socket open for SPX. Really definitive
+ //
+
+ if (!pSocketInfo || pSocketInfo->SpxSocket) {
+ CompleteEcb(pXecb, ECB_CC_NON_EXISTENT_SOCKET);
+ return IPX_NON_EXISTENT_SOCKET;
+ }
+
+ //
+ // initiate the receive. It may complete if there is data waiting or an
+ // error occurs, otherwise the ECB will be placed in a receive pending queue
+ // for this socket
+ //
+
+ if (GetIoBuffer(pXecb, FALSE, IPX_HEADER_LENGTH)) {
+ pXecb->Ecb->InUse = ECB_IU_LISTENING;
+ IpxReceiveFirst(pXecb, pSocketInfo);
+ } else {
+ CompleteEcb(pXecb, ECB_CC_CANCELLED);
+ }
+
+ //
+ // return success. Any errors will be communicated asynchronously - either
+ // indirectly by relevant values in CompletionCode and InUse fields of the
+ // ECB or directly by an ESR callback
+ //
+
+ return IPX_SUCCESS;
+}
+
+
+WORD
+_VwIPXOpenSocket(
+ IN OUT ULPWORD pSocketNumber,
+ IN BYTE socketType,
+ IN WORD dosPDB
+ )
+
+/*++
+
+Routine Description:
+
+ Opens a socket for use by IPX or SPX. Puts the socket into non-blocking mode.
+ The socket will be bound to IPX
+
+ This call is Synchronous
+
+Arguments:
+ Inputs
+ *pSocketNumber - The requested socket number
+ socketType - Socket Longevity flag
+ dosPDB - DOS PDB. This parameter is not part of the IPX API.
+ Added because we need to remember which DOS executable created
+ the socket: we need to clean-up short-lived sockets when the
+ executable terminates
+
+ Outputs
+ pSocketNumber - Assigned socket number
+
+Return Value:
+
+ 00h Success
+ F0h Ipx Not Installed
+ F1h Ipx/Spx Not Initialized
+ FEh Socket table full
+ FFh Socket already open
+
+--*/
+
+{
+ LPSOCKET_INFO pSocketInfo;
+ WORD status;
+
+ if ((pSocketInfo = AllocateSocket()) == NULL) {
+ return IPX_SOCKET_TABLE_FULL;
+ }
+ status = CreateSocket(SOCKET_TYPE_IPX, pSocketNumber, &pSocketInfo->Socket);
+ if (status == IPX_SUCCESS) {
+
+ //
+ // set up the SOCKET_INFO fields and add it to our list of open sockets
+ //
+
+ pSocketInfo->Owner = dosPDB;
+ pSocketInfo->SocketNumber = *pSocketNumber;
+
+ //
+ // treat socketType == 0 as short-lived, anything else as long-lived.
+ // There doesn't appear to be an error return if the flag is not 0 or 0xFF
+ //
+
+ pSocketInfo->LongLived = (BOOL)(socketType != 0);
+ QueueSocket(pSocketInfo);
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_IPXOpenSocket,
+ IPXDBG_LEVEL_INFO,
+ "_VwIPXOpenSocket: created socket %04x\n",
+ B2LW(*pSocketNumber)
+ ));
+
+ } else {
+ DeallocateSocket(pSocketInfo);
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_IPXOpenSocket,
+ IPXDBG_LEVEL_ERROR,
+ "_VwIPXOpenSocket: Failure: returning %x\n",
+ status
+ ));
+
+ }
+ return status;
+}
+
+
+VOID
+_VwIPXRelinquishControl(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Just sleep for a nominal amount.
+
+ This call is Synchronous
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Sleep(0);
+}
+
+
+
+VOID
+_VwIPXScheduleIPXEvent(
+ IN WORD time,
+ IN LPECB pEcb,
+ IN ECB_ADDRESS EcbAddress
+ )
+
+/*++
+
+Routine Description:
+
+ Schedules a an event to occur in some number of ticks. When the tick count
+ reaches 0, the ECB InUse field is cleared and any ESR called
+
+ This call is Asynchronous
+
+Arguments:
+
+ Inputs
+ time - the delay time ( number of 1/18 second ticks )
+ pEcb
+ EcbAddress
+
+ Outputs
+ Nothing
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LPXECB pXecb = RetrieveXEcb(ECB_TYPE_IPX, pEcb, EcbAddress);
+
+ ScheduleEvent(pXecb, time);
+}
+
+
+VOID
+_VwIPXSendPacket(
+ IN LPECB pEcb,
+ IN ECB_ADDRESS EcbAddress,
+ IN WORD DosPDB
+ )
+
+/*++
+
+Routine Description:
+
+ Sends a packet to the target machine/router. This call can be made on a
+ socket that is not open
+
+ The app must have filled in the following IPX_ECB fields:
+
+ EsrAddress
+ Socket
+ ImmediateAddress
+ FragmentCount
+ fragment descriptor fields
+
+ and the following IPX_PACKET fields:
+
+ PacketType
+ Destination.Net
+ Destination.Node
+ Destination.Socket
+
+ This call is Asynchronous
+
+Arguments:
+
+ Inputs
+ pEcb
+ EcbAddress
+ DosPDB
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LPXECB pXecb = RetrieveXEcb(ECB_TYPE_IPX, pEcb, EcbAddress);
+ LPSOCKET_INFO pSocketInfo;
+
+ //
+ // this function returns no immediate status so we must assume that the
+ // ECB pointer is valid
+ //
+
+ //
+ // check the ECB for correctness
+ //
+
+ if ((pXecb->Ecb->FragmentCount == 0)
+ || (ECB_FRAGMENT(pXecb->Ecb, 0)->Length < IPX_HEADER_LENGTH)) {
+ CompleteEcb(pXecb, ECB_CC_BAD_REQUEST);
+ return;
+ }
+
+ //
+ // IPXSendPacket() can be called on an unopened socket: we must try to
+ // temporarily allocate the socket
+ //
+ // Q: Is the following scenario possible with real IPX:
+ // IPXSendPacket() on unopened socket X
+ // Send fails & gets queued
+ // app makes IPXOpenSocket() call on X; X gets opened
+ //
+ // Currently, we would create the temporary socket and fail IPXOpenSocket()
+ // because it is already open!
+ //
+
+ pSocketInfo = FindSocket(pXecb->SocketNumber);
+ if (!pSocketInfo) {
+
+ //
+ // BUGBUG: when is temporary socket deleted? After send completed?
+ // when app dies? when? Novell documentation is not specific (used
+ // to say something else :-))
+ //
+
+ pSocketInfo = AllocateTemporarySocket();
+ if (pSocketInfo) {
+
+ //
+ // set up the SOCKET_INFO fields and add it to our list of open sockets
+ //
+
+ pSocketInfo->Owner = DosPDB;
+
+ //
+ // temporary sockets are always short-lived
+ //
+
+ pSocketInfo->LongLived = FALSE;
+ QueueSocket(pSocketInfo);
+
+ } else {
+
+ //
+ // BUGBUG: completion code???
+ //
+
+ CompleteEcb(pXecb, ECB_CC_SOCKET_TABLE_FULL);
+ return;
+ }
+ } else if (pSocketInfo->SpxSocket) {
+
+ //
+ // see complaint in IPXListenForPacket
+ //
+ // can't make IPX requests on socket opened for SPX
+ //
+ // BUGBUG: completion code??
+ //
+
+ CompleteEcb(pXecb, ECB_CC_NON_EXISTENT_SOCKET);
+ return;
+ }
+
+ //
+ // start the send: tries to send the data in one go. Either succeeds, fails
+ // with an error, or queues the ECB for subsequent attempts via AES/IPX
+ // deferred processing.
+ //
+ // In the first 2 cases, the ECB has been completed already
+ //
+
+ StartIpxSend(pXecb, pSocketInfo);
+}
diff --git a/private/nw/vwipxspx/dll/vwipx.h b/private/nw/vwipxspx/dll/vwipx.h
new file mode 100644
index 000000000..351351eab
--- /dev/null
+++ b/private/nw/vwipxspx/dll/vwipx.h
@@ -0,0 +1,122 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ vwipx.h
+
+Abstract:
+
+ Contains function prototypes for VWIPX.C
+
+Author:
+
+ Richard L Firth (rfirth) 25-Oct-1993
+
+Revision History:
+
+ 25-Oct-1993 rfirth
+ Created
+
+--*/
+
+VOID
+VwIPXCancelEvent(
+ VOID
+ );
+
+VOID
+VwIPXCloseSocket(
+ VOID
+ );
+
+VOID
+VwIPXDisconnectFromTarget(
+ VOID
+ );
+
+VOID
+VwIPXGenerateChecksum(
+ VOID
+ );
+
+VOID
+VwIPXGetInformation(
+ VOID
+ );
+
+VOID
+VwIPXGetInternetworkAddress(
+ VOID
+ );
+
+VOID
+VwIPXGetIntervalMarker(
+ VOID
+ );
+
+VOID
+VwIPXGetLocalTarget(
+ VOID
+ );
+
+VOID
+VwIPXGetLocalTargetAsync(
+ VOID
+ );
+
+VOID
+VwIPXGetMaxPacketSize(
+ VOID
+ );
+
+VOID
+VwIPXInitialize(
+ VOID
+ );
+
+VOID
+VwIPXListenForPacket(
+ VOID
+ );
+
+VOID
+VwIPXOpenSocket(
+ VOID
+ );
+
+VOID
+VwIPXRelinquishControl(
+ VOID
+ );
+
+VOID
+VwIPXScheduleAESEvent(
+ VOID
+ );
+
+VOID
+VwIPXScheduleIPXEvent(
+ VOID
+ );
+
+VOID
+VwIPXSendPacket(
+ VOID
+ );
+
+VOID
+VwIPXSendWithChecksum(
+ VOID
+ );
+
+VOID
+VwIPXSPXDeinit(
+ VOID
+ );
+
+VOID
+VwIPXVerifyChecksum(
+ VOID
+ );
diff --git a/private/nw/vwipxspx/dll/vwipxspx.def b/private/nw/vwipxspx/dll/vwipxspx.def
new file mode 100644
index 000000000..c62a71f84
--- /dev/null
+++ b/private/nw/vwipxspx/dll/vwipxspx.def
@@ -0,0 +1,64 @@
+LIBRARY VWIPXSPX
+
+DESCRIPTION 'WOW Network Support - IPX/SPX APIs'
+
+EXPORTS
+ VwInitialize
+ VwDispatcher
+
+ VwIPXCancelEvent
+ VwIPXCloseSocket
+ VwIPXDisconnectFromTarget
+ VwIPXGenerateChecksum
+ VwIPXGetInformation
+ VwIPXGetInternetworkAddress
+ VwIPXGetIntervalMarker
+ VwIPXGetLocalTarget
+ VwIPXGetLocalTargetAsync
+ VwIPXGetMaxPacketSize
+ VwIPXInitialize
+ VwIPXListenForPacket
+ VwIPXOpenSocket
+ VwIPXRelinquishControl
+ VwIPXScheduleAESEvent
+ VwIPXScheduleIPXEvent
+ VwIPXSendPacket
+ VwIPXSendWithChecksum
+ VwIPXSPXDeinit
+ VwIPXVerifyChecksum
+ VwSPXAbortConnection
+ VwSPXEstablishConnection
+ VwSPXGetConnectionStatus
+ VwSPXInitialize
+ VwSPXListenForConnection
+ VwSPXListenForSequencedPacket
+ VwSPXSendSequencedPacket
+ VwSPXTerminateConnection
+
+ VWinEsrCallback
+ VWinInitialize
+
+ VWinIPXCancelEvent
+ VWinIPXCloseSocket
+ VWinIPXDisconnectFromTarget
+ VWinIPXGetInternetworkAddress
+ VWinIPXGetIntervalMarker
+ VWinIPXGetLocalTarget
+ VWinIPXGetLocalTargetAsync
+ VWinIPXGetMaxPacketSize
+ VWinIPXInitialize
+ VWinIPXListenForPacket
+ VWinIPXOpenSocket
+ VWinIPXRelinquishControl
+ VWinIPXScheduleIPXEvent
+ VWinIPXSendPacket
+ VWinIPXSPXDeinit
+
+ VWinSPXAbortConnection
+ VWinSPXEstablishConnection
+ VWinSPXGetConnectionStatus
+ VWinSPXInitialize
+ VWinSPXListenForConnection
+ VWinSPXListenForSequencedPacket
+ VWinSPXSendSequencedPacket
+ VWinSPXTerminateConnection
diff --git a/private/nw/vwipxspx/dll/vwipxspx.h b/private/nw/vwipxspx/dll/vwipxspx.h
new file mode 100644
index 000000000..01ad6ec5a
--- /dev/null
+++ b/private/nw/vwipxspx/dll/vwipxspx.h
@@ -0,0 +1,586 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ vwipxspx.h
+
+Abstract:
+
+ Contains manifests, typedefs, structures, macros for NTVDM IPX/SPX support
+
+Author:
+
+ Richard L Firth (rfirth) 30-Sep-1993
+
+Environment:
+
+ Structures are expected to live in segmented VDM address space, but be
+ accessible from flat 32-bit protect mode. The VDM can be in real or protect
+ mode
+
+Revision History:
+
+ 30-Sep-1993 rfirth
+ Created
+
+--*/
+
+#ifndef _VWIPXSPX_H_
+#define _VWIPXSPX_H_
+
+//
+// FREE_OBJECT - in free version, just calls LocalFree. For debug version, fills
+// memory with some arbitrary value, then frees the pointer and checks that what
+// LocalFree thought that the pointer pointed at a valid, freeable object
+//
+
+#if DBG
+
+#define FREE_OBJECT(p) {\
+ FillMemory(p, sizeof(*p), 0xFF);\
+ VWASSERT(LocalFree((HLOCAL)(p)), NULL);\
+ }
+#else
+
+#define FREE_OBJECT(p) VWASSERT(LocalFree((HLOCAL)(p)), NULL)
+
+#endif
+
+//
+// simple function macros
+//
+
+//#define AllocateXecb() (LPXECB)LocalAlloc(LPTR, sizeof(XECB))
+//#define DeallocateXecb(p) FREE_OBJECT(p)
+#define AllocateBuffer(s) (LPVOID)LocalAlloc(LMEM_FIXED, (s))
+#define DeallocateBuffer(p) FREE_OBJECT(p)
+
+//
+// pseudo-types for 16-bit addresses
+//
+
+#define ESR_ADDRESS DWORD
+#define ECB_ADDRESS DWORD
+
+//
+// from Novell documentation, the default maximum open sockets. Max max is 150
+//
+
+#ifndef DEFAULT_MAX_OPEN_SOCKETS
+#define DEFAULT_MAX_OPEN_SOCKETS 20
+#endif
+
+#ifndef MAX_OPEN_SOCKETS
+#define MAX_OPEN_SOCKETS 150
+#endif
+
+#define SPX_INSTALLED 0xFF
+
+#define MAX_LISTEN_QUEUE_SIZE 5 // ?
+
+//
+// misc. macros
+//
+
+//
+// B2LW, L2Bx - big-endian to little-endian macros
+//
+
+#define B2LW(w) (WORD)(((WORD)(w) << 8) | ((WORD)(w) >> 8))
+#define B2LD(d) (DWORD)(B2LW((DWORD)(d) << 16) | B2LW((DWORD)(d) >> 16))
+#define L2BW(w) B2LW(w)
+#define L2BD(d) B2LD(d)
+
+//
+// miscellaneous manifests
+//
+
+#define ONE_TICK (1000/18) // 1/18 sec in milliseconds (55.55 mSec)
+#define SLEEP_TIME ONE_TICK // amount of time we Sleep() during IPXRelinquishControl
+
+//
+// options for IPXGetInformation
+//
+
+#define IPX_ODI 0x0001
+#define IPX_CHECKSUM_FUNCTIONS 0x0002
+
+//
+// IPX/SPX structures. The following structures are in VDM format, and should
+// be packed on a byte-boundary
+//
+// Netware maintains certain structure fields in network (big-endian) format
+//
+
+#include <packon.h>
+
+//
+// INTERNET_ADDRESS - structure returned by IPXGetInternetworkAddress
+//
+
+typedef struct {
+ BYTE Net[4];
+ BYTE Node[6];
+} INTERNET_ADDRESS ;
+
+typedef INTERNET_ADDRESS UNALIGNED *LPINTERNET_ADDRESS;
+
+//
+// NETWARE_ADDRESS - address of an application on the network, as defined by
+// its network segment, node address and socket number
+//
+
+typedef struct {
+ BYTE Net[4]; // hi-lo
+ BYTE Node[6]; // hi-lo
+ WORD Socket; // hi-lo
+} NETWARE_ADDRESS ;
+
+typedef NETWARE_ADDRESS UNALIGNED *LPNETWARE_ADDRESS;
+
+//
+// FRAGMENT - ECB/IPX/SPX buffers are split into 'fragments'
+//
+
+typedef struct {
+ LPVOID Address; // offset-segment
+ WORD Length; // hi-lo
+} FRAGMENT ;
+
+typedef FRAGMENT UNALIGNED *LPFRAGMENT;
+
+//
+// IPX_PACKET - format of packet submitted to IPX for sending. The maximum
+// size of an IPX packet is 576 bytes, 30 bytes header, 546 bytes data
+//
+
+typedef struct {
+ WORD Checksum; // always set to 0xFFFF
+ WORD Length; // set by IPX - header + data
+ BYTE TransportControl; // set by IPX to 0. Used by routers
+
+ //
+ // for IPX, PacketType is 0 (Unknown Packet Type) or 4 (Packet Exchange
+ // Packet)
+ //
+
+ BYTE PacketType;
+ NETWARE_ADDRESS Destination;
+ NETWARE_ADDRESS Source;
+ BYTE Data[]; // 546 bytes max.
+} IPX_PACKET ;
+
+typedef IPX_PACKET UNALIGNED *LPIPX_PACKET;
+
+#define IPX_HEADER_LENGTH sizeof(IPX_PACKET)
+#define MAXIMUM_IPX_PACKET_LENGTH 576
+#define MAXIMUM_IPX_DATA_LENGTH (MAXIMUM_IPX_PACKET_LENGTH - IPX_HEADER_LENGTH)
+
+#define IPX_PACKET_TYPE 4
+
+//
+// SPX_PACKET - format of packet submitted to SPX for sending. The maximum
+// size of an SPX packet is 576 bytes, 42 bytes header, 534 bytes data
+//
+
+typedef struct {
+ WORD Checksum; // always set to 0xFFFF
+ WORD Length; // set by IPX - header + data
+ BYTE TransportControl; // set by IPX to 0. Used by routers
+
+ //
+ // for SPX, PacketType is set to 5 (Sequenced Packet Protocol Packet)
+ //
+
+ BYTE PacketType;
+ NETWARE_ADDRESS Destination;
+ NETWARE_ADDRESS Source;
+
+ //
+ // ConnectionControl is a bitmap which control bi-directional flow over a
+ // link. The bits are defined (by Xerox SPP) as:
+ //
+ // 0-3 undefined
+ // 4 end-of-message
+ // This is the only bit which can be directly manipulated by an
+ // app. The bit is passed through unchanged by SPX
+ // 5 attention
+ // Ignored by SPX, but passed through
+ // 6 acknowledge
+ // Set by SPX if an ack is required
+ // 7 system packet
+ // Set by SPX if the packet is internal control. An app should
+ // never see this bit (i.e. should never see a system packet)
+ //
+
+ BYTE ConnectionControl;
+
+ //
+ // DataStreamType defines the type of data in the packet:
+ //
+ // 0x00 - 0xFD client-defined.
+ // Ignored by SPX
+ // 0xFE end-of-connection.
+ // When active connection is terminated, SPX
+ // generates and sends a packet with this bit set.
+ // This will be the last packet sent on the connection
+ // 0xFF end-of-connection acknowledgement
+ // SPX generates a system packet to acknowledge an
+ // end-of-connection packet
+ //
+
+ BYTE DataStreamType;
+ WORD SourceConnectId; // assigned by SPX
+ WORD DestinationConnectId;
+ WORD SequenceNumber; // managed by SPX
+ WORD AckNumber; // managed by SPX
+ WORD AllocationNumber; // managed by SPX
+ BYTE Data[]; // 534 bytes max.
+
+} SPX_PACKET ;
+
+typedef SPX_PACKET UNALIGNED *LPSPX_PACKET;
+
+#define SPX_HEADER_LENGTH sizeof(SPX_PACKET)
+#define MAXIMUM_SPX_PACKET_LENGTH MAXIMUM_IPX_PACKET_LENGTH
+#define MAXIMUM_SPX_DATA_LENGTH (MAXIMUM_SPX_PACKET_LENGTH - SPX_HEADER_LENGTH)
+
+#define SPX_PACKET_TYPE 5
+
+//
+// ConnectionControl flags
+//
+
+#define SPX_CONNECTION_RESERVED 0x0F
+#define SPX_END_OF_MESSAGE 0x10
+#define SPX_ATTENTION 0x20
+#define SPX_ACK_REQUIRED 0x40
+#define SPX_SYSTEM_PACKET 0x80
+
+//
+// DataStreamType values
+//
+
+#define SPX_DS_ESTABLISH 0x00
+#define SPX_DS_TERMINATE 0xfe
+
+//
+// IPX_ECB - Event Control Block. This structure is used by most IPX/SPX APIs,
+// especially when deferred IPX/AES processing is required. The following
+// structure is a socket-based ECB
+//
+
+typedef struct {
+
+ //
+ // LinkAddress is reserved for use by IPX. We use it to link the ECB onto
+ // a queue. We appropriate the space used for an x86 segmented address
+ // (real or protect mode) as a flat 32-bit pointer
+ //
+
+ ULPVOID LinkAddress; // offset-segment
+
+ //
+ // EsrAddress is non-NULL if an Event Service Routine will be called when
+ // the event described by the ECB completes. This will always be an x86
+ // segmented address (real or protect mode)
+ //
+
+ ESR_ADDRESS EsrAddress; // offset-segment
+
+ //
+ // IPX uses the InUse field to mark the ECB as owned by IPX (!0) or by the
+ // app (0):
+ //
+ // 0xF8 App tried to send a packet while IPX was busy; IPX queued
+ // the ECB
+ // 0xFA IPX is processing the ECB
+ // 0xFB IPX has used the ECB for some event and put it on a queue
+ // for processing
+ // 0xFC the ECB is waiting for an AES event to occur
+ // 0xFD the ECB is waiting for an IPX event to occur
+ // 0xFE IPX is listening on a socket for incoming packets
+ // 0xFF IPX is using the ECB to send a packet
+ //
+
+ BYTE InUse;
+
+ //
+ // CompletionCode is used to return a status from a deferred request. This
+ // field is not valid until InUse has been set to 0
+ //
+ // NOTE: We have to differentiate between AES and IPX ECBs on callbacks: due
+ // to their different sizes, we store the 16-bit segment and offset in
+ // different places. In order to differentiate the ECBs, we use CompletionCode
+ // field (AesWorkspace[0]) as the owner. The real CompletionCode for IPX ECBs
+ // goes in IPX_ECB_COMPLETE (DriverWorkspace[7]). But only for completed ECBs
+ // that have an ESR
+ //
+
+ BYTE CompletionCode;
+ WORD SocketNumber; // hi-lo
+
+ //
+ // the first word of IpxWorkspace is used to return the connection ID of
+ // an SPX connection
+ //
+
+ DWORD IpxWorkspace;
+ BYTE DriverWorkspace[12];
+
+ //
+ // ImmediateAddress is the local network node at the remote end of this
+ // connection. It is either the node address of the remote machine if it
+ // is on this LAN, or it is the node address of the router if the remote
+ // machine is on a different LAN
+ //
+ // This field must be initialized when talking over IPX, but not SPX
+ //
+
+ BYTE ImmediateAddress[6];
+
+ //
+ // FragmentCount - number of FRAGMENT structures that comprise the request.
+ // Must be at least 1
+ //
+
+ WORD FragmentCount;
+
+ //
+ // FragmentCount fragments start here
+ //
+
+} IPX_ECB ;
+
+typedef IPX_ECB UNALIGNED *LPIPX_ECB;
+
+//
+// ECB InUse values
+//
+
+#define ECB_IU_NOT_IN_USE 0x00
+#define ECB_IU_TEMPORARY 0xCC
+#define ECB_IU_LISTENING_SPX 0xF7 // same as win16 (by observation)
+#define ECB_IU_SEND_QUEUED 0xF8
+#define ECB_IU_AWAITING_CONNECTION 0xF9 // same as win16 (by observation)
+#define ECB_IU_BEING_PROCESSED 0xFA
+#define ECB_IU_AWAITING_PROCESSING 0xFB
+#define ECB_IU_AWAITING_AES_EVENT 0xFC
+#define ECB_IU_AWAITING_IPX_EVENT 0xFD
+#define ECB_IU_LISTENING 0xFE
+#define ECB_IU_SENDING 0xFF
+
+//
+// ECB CompletionCode values
+//
+
+#define ECB_CC_SUCCESS 0x00
+#define ECB_CC_CONNECTION_TERMINATED 0xEC
+#define ECB_CC_CONNECTION_ABORTED 0xED
+#define ECB_CC_INVALID_CONNECTION 0xEE
+#define ECB_CC_CONNECTION_TABLE_FULL 0xEF
+#define ECB_CC_CANNOT_CANCEL 0xF9
+#define ECB_CC_CANCELLED 0xFC
+#define ECB_CC_BAD_REQUEST 0xFD
+#define ECB_CC_BAD_SEND_REQUEST 0xFD
+#define ECB_CC_PACKET_OVERFLOW 0xFD
+#define ECB_CC_UNDELIVERABLE 0xFE
+#define ECB_CC_SOCKET_TABLE_FULL 0xFE
+#define ECB_CC_BAD_LISTEN_REQUEST 0xFF
+#define ECB_CC_HARDWARE_ERROR 0xFF
+#define ECB_CC_NON_EXISTENT_SOCKET 0xFF
+
+//
+// we commandeer certain (reserved) fields for our own internal use:
+//
+// LPECB EcbLink LinkAddress
+// PVOID Buffer32 DriverWorkspace[0]
+// WORD Length32 DriverWorkspace[4]
+// WORD Flags32 DriverWorkspace[6]
+// WORD OriginalEs DriverWorkspace[8]
+// WORD OriginalSi DriverWorkspace[10]
+//
+
+#define ECB_TYPE(p) (((LPIPX_ECB)(p))->CompletionCode)
+#define IPX_ECB_SEGMENT(p) (WORD)*((ULPWORD)&(((LPIPX_ECB)(p))->IpxWorkspace)+0)
+#define IPX_ECB_OFFSET(p) (WORD)*((ULPWORD)&(((LPIPX_ECB)(p))->IpxWorkspace)+2)
+#define IPX_ECB_BUFFER32(p) (ULPVOID)*(ULPVOID*)&(((LPIPX_ECB)(p))->DriverWorkspace[0])
+#define IPX_ECB_LENGTH32(p) (WORD)*(ULPWORD)&(((LPIPX_ECB)(p))->DriverWorkspace[4])
+#define IPX_ECB_FLAGS32(p) (((LPIPX_ECB)(p))->DriverWorkspace[6])
+#define IPX_ECB_COMPLETE(p) (((LPIPX_ECB)(p))->DriverWorkspace[7])
+
+#define SPX_ECB_CONNECTION_ID(p) (WORD)*(ULPWORD)&(((LPIPX_ECB)(p))->IpxWorkspace)
+
+//
+// ECB Flags32 flags
+//
+
+#define ECB_FLAG_BUFFER_ALLOCATED 0x01
+
+//
+// ECB types
+//
+
+#define ECB_TYPE_AES 0
+#define ECB_TYPE_IPX 1
+#define ECB_TYPE_SPX 2
+
+//
+// ECB owners
+//
+
+#define ECB_OWNER_IPX 0xFF
+#define ECB_OWNER_AES 0x00
+
+//
+// ECB_FRAGMENT - macro which gives the address of the first fragment structure
+// within a socket-based ECB
+//
+
+#define ECB_FRAGMENT(p, n) ((LPFRAGMENT)(((LPIPX_ECB)(p) + 1)) + (n))
+
+//
+// AES_ECB - used by AES, these socket-less ECBs are used to schedule events
+//
+
+typedef struct {
+ ULPVOID LinkAddress; // offset-segment
+ ESR_ADDRESS EsrAddress; // offset-segment
+ BYTE InUse;
+
+ //
+ // first 3 bytes overlay CompletionCode (1) and SocketNumber (2) fields of
+ // IPX_ECB. Last 2 bytes overlay first 2 bytes of IpxWorkspace (4) field of
+ // IPX_ECB. We use the 1st byte of the common unused fields as the ECB type
+ // (send/receive/timed-event)
+ //
+
+ BYTE AesWorkspace[5];
+} AES_ECB ;
+
+typedef AES_ECB UNALIGNED *LPAES_ECB;
+
+//
+// as with IPX_ECB, we 'borrow' some of the reserved fields for our own use
+//
+
+#define AES_ECB_SEGMENT(p) (WORD)*(ULPWORD)&(((LPAES_ECB)(p))->AesWorkspace[1])
+#define AES_ECB_OFFSET(p) (WORD)*(ULPWORD)&(((LPAES_ECB)(p))->AesWorkspace[3])
+
+//
+// LPECB - points to either IPX_ECB or AES_ECB. Both in VDM workspace
+//
+
+#define LPECB LPIPX_ECB
+
+//
+// SPX_CONNECTION_STATS - returned by SPXGetConnectionStatus. All WORD fields
+// are to be returned HiLo (ie to Hawaii). All fields come back from NT SPX
+// transport in HiLo format also (this was changed recently, used to be in
+// Intel order).
+//
+
+typedef struct {
+ BYTE State;
+ BYTE WatchDog;
+ WORD LocalConnectionId;
+ WORD RemoteConnectionId;
+ WORD LocalSequenceNumber;
+ WORD LocalAckNumber;
+ WORD LocalAllocNumber;
+ WORD RemoteAckNumber;
+ WORD RemoteAllocNumber;
+ WORD LocalSocket;
+ BYTE ImmediateAddress[6];
+ BYTE RemoteNetwork[4];
+ BYTE RemoteNode[6];
+ WORD RemoteSocket;
+ WORD RetransmissionCount;
+ WORD EstimatedRoundTripDelay;
+ WORD RetransmittedPackets;
+ WORD SuppressedPackets;
+} SPX_CONNECTION_STATS ;
+
+typedef SPX_CONNECTION_STATS UNALIGNED* LPSPX_CONNECTION_STATS;
+
+#include <packoff.h>
+
+//
+// 16-bit parameter get/set macros. These may change depending on requirements
+// of real/protect mode parameters (e.g. stack based vs. register based)
+//
+
+#define IPX_GET_AES_ECB(p) (p) = (LPAES_ECB)POINTER_FROM_WORDS(getES(), getSI(), sizeof(AES_ECB))
+#define IPX_GET_IPX_ECB(p) (p) = (LPIPX_ECB)POINTER_FROM_WORDS(getES(), getSI(), sizeof(IPX_ECB))
+#define IPX_GET_SOCKET(s) (s) = (WORD)getDX()
+#define IPX_GET_SOCKET_LIFE(l) (l) = (BYTE)getBP()
+#define IPX_GET_SOCKET_OWNER(o) (o) = (WORD)getCX()
+#define IPX_GET_BUFFER(p, s) (p) = (ULPBYTE)POINTER_FROM_WORDS(getES(), getSI(), (s))
+#define IPX_GET_ECB_SEGMENT() getES()
+#define IPX_GET_ECB_OFFSET() getSI()
+
+#define IPX_SET_STATUS(s) setAL((BYTE)(s))
+#define IPX_SET_SOCKET(s) setDX((WORD)(s))
+#define IPX_SET_INFORMATION(v) setDX((WORD)(v))
+
+#define SPX_SET_STATUS(s) setAL((BYTE)(s))
+#define SPX_SET_CONNECTION_ID(i) setDX((WORD)(i))
+
+//
+// macros returning 16-bit API parameters - may fetch register contents or values
+// from stack/memory
+//
+
+#define ECB_PARM_SEGMENT() getES()
+#define ECB_PARM_OFFSET() getSI()
+#define ECB_PARM_ADDRESS() (ECB_ADDRESS)MAKELONG(getSI(), getES())
+
+#define AES_ECB_PARM() RetrieveEcb(ECB_TYPE_AES)
+
+#define IPX_ECB_PARM() RetrieveEcb(ECB_TYPE_IPX)
+#define IPX_SOCKET_PARM() getDX()
+#define IPX_SOCKET_LIFE_PARM() (BYTE)getBP()
+#define IPX_SOCKET_OWNER_PARM() getCX()
+#define IPX_BUFFER_PARM(s) (ULPBYTE)POINTER_FROM_WORDS(getES(), getSI(), (s))
+#define IPX_TICKS_PARM() getBP()
+
+#define SPX_RETRY_COUNT_PARM() (BYTE)getBP()
+#define SPX_WATCHDOG_FLAG_PARM() ((BYTE)(getBP() >> 8))
+#define SPX_ECB_PARM() RetrieveEcb(ECB_TYPE_IPX)
+#define SPX_CONNECTION_PARM() getDX()
+#define SPX_BUFFER_PARM(s) (ULPBYTE)POINTER_FROM_WORDS(getES(), getSI(), (s))
+
+//
+// IPX error codes - same codes used in different circumstances
+//
+
+#define IPX_SUCCESS 0x00
+#define IPX_CANNOT_CANCEL 0xF9
+#define IPX_NO_PATH_TO_DESTINATION 0xFA
+#define IPX_CANCELLED 0xFC
+#define IPX_BAD_REQUEST 0xFD
+#define IPX_SOCKET_TABLE_FULL 0xFE
+#define IPX_UNDELIVERABLE 0xFE
+#define IPX_SOCKET_ALREADY_OPEN 0xFF
+#define IPX_HARDWARE_ERROR 0xFF
+#define IPX_NON_EXISTENT_SOCKET 0xFF
+#define IPX_ECB_NOT_IN_USE 0xFF
+
+//
+// SPX error codes - same codes used in different circumstances
+//
+
+#define SPX_SUCCESS 0x00
+#define SPX_CONNECTION_TERMINATED 0xEC
+#define SPX_CONNECTION_ABORTED 0xED
+#define SPX_INVALID_CONNECTION 0xEE
+#define SPX_CONNECTION_TABLE_FULL 0xEF
+#define SPX_SOCKET_CLOSED 0xFC
+#define SPX_PACKET_OVERFLOW 0xFD
+#define SPX_BAD_SEND_REQUEST 0xFD // malformed packet
+#define SPX_BAD_LISTEN_REQUEST 0xFF
+#define SPX_NON_EXISTENT_SOCKET 0xFF
+
+#endif // _VWIPXSPX_H_
diff --git a/private/nw/vwipxspx/dll/vwipxspx.rc b/private/nw/vwipxspx/dll/vwipxspx.rc
new file mode 100644
index 000000000..c355cffea
--- /dev/null
+++ b/private/nw/vwipxspx/dll/vwipxspx.rc
@@ -0,0 +1,11 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+#define VER_FILEDESCRIPTION_STR "Virtual Dos Machine IPX/SPX Interface Library"
+#define VER_INTERNALNAME_STR "VWIPXSPX.DLL"
+#define VER_ORIGINALFILENAME_STR "VWIPXSPX.DLL"
+
+#include "common.ver"
diff --git a/private/nw/vwipxspx/dll/vwmisc.c b/private/nw/vwipxspx/dll/vwmisc.c
new file mode 100644
index 000000000..2d7821dee
--- /dev/null
+++ b/private/nw/vwipxspx/dll/vwmisc.c
@@ -0,0 +1,74 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ vwmisc.c
+
+Abstract:
+
+ ntVdm netWare (Vw) IPX/SPX Functions
+
+ Vw: The peoples' network
+
+ Contains miscellaneous (non-IPX/SPX) functions
+
+ Contents:
+ VwTerminateProgram
+
+Author:
+
+ Richard L Firth (rfirth) 30-Sep-1993
+
+Environment:
+
+ User-mode Win32
+
+Revision History:
+
+ 30-Sep-1993 rfirth
+ Created
+
+--*/
+
+#include "vw.h"
+#pragma hdrstop
+
+//
+// functions
+//
+
+
+VOID
+VwTerminateProgram(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ When a DOS program terminates, we must close any open sockets that were
+ specified as SHORT_LIVED
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_ANY,
+ IPXDBG_LEVEL_INFO,
+ "VwTerminateProgram: PDB=%04x\n",
+ getCX()
+ ));
+
+ KillShortLivedSockets(getCX());
+}
diff --git a/private/nw/vwipxspx/dll/vwmisc.h b/private/nw/vwipxspx/dll/vwmisc.h
new file mode 100644
index 000000000..0367bc7d7
--- /dev/null
+++ b/private/nw/vwipxspx/dll/vwmisc.h
@@ -0,0 +1,27 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ vwipx.h
+
+Abstract:
+
+ Contains function prototypes for VWMISC.C
+
+Author:
+
+ Richard L Firth (rfirth) 25-Oct-1993
+
+Revision History:
+
+ 25-Oct-1993 rfirth
+ Created
+
+--*/
+
+VOID
+VwTerminateProgram(
+ VOID
+ );
diff --git a/private/nw/vwipxspx/dll/vwspx.c b/private/nw/vwipxspx/dll/vwspx.c
new file mode 100644
index 000000000..02ef58481
--- /dev/null
+++ b/private/nw/vwipxspx/dll/vwspx.c
@@ -0,0 +1,1339 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ vwspx.c
+
+Abstract:
+
+ ntVdm netWare (Vw) IPX/SPX Functions
+
+ Vw: The peoples' network
+
+ Contains internal routines for DOS/WOW SPX calls (netware functions).
+ The SPX APIs use WinSock to perform the actual operations
+
+ Contents:
+ _VwSPXAbortConnection
+ _VwSPXEstablishConnection
+ _VwSPXGetConnectionStatus
+ _VwSPXInitialize
+ _VwSPXListenForConnection
+ _VwSPXListenForSequencedPacket
+ _VwSPXSendSequencedPacket
+ _VwSPXTerminateConnection
+
+ The SPX functions build on the IPX functions (VWIPX.C). SPX maintains
+ connections, IPX maintains sockets. A socket may have a list of connections
+
+Author:
+
+ Richard L Firth (rfirth) 30-Sep-1993
+
+Environment:
+
+ User-mode Win32
+
+Revision History:
+
+ 30-Sep-1993 rfirth
+ Created
+
+--*/
+
+#include "vw.h"
+#pragma hdrstop
+
+//
+// functions
+//
+
+
+VOID
+_VwSPXAbortConnection(
+ IN WORD SPXConnectionID
+ )
+
+/*++
+
+Routine Description:
+
+ Aborts a connection. Because NWLink doesn't differentiate between abrupt
+ and graceful closes, this function has the same effect as
+ VwSPXTerminateConnection
+
+Arguments:
+
+ SPXConnectionID - connection to abort
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LPCONNECTION_INFO pConnectionInfo;
+
+ RequestMutex();
+ pConnectionInfo = FindConnection(SPXConnectionID);
+ if (pConnectionInfo) {
+ DequeueConnection(pConnectionInfo->OwningSocket, pConnectionInfo);
+ AbortOrTerminateConnection(pConnectionInfo, ECB_CC_CONNECTION_ABORTED);
+ } else {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_SPXAbortConnection,
+ IPXDBG_LEVEL_ERROR,
+ "VwSPXAbortConnection: cannot find connection %04x\n",
+ SPXConnectionID
+ ));
+
+ }
+ ReleaseMutex();
+}
+
+
+WORD
+_VwSPXEstablishConnection(
+ IN BYTE retryCount,
+ IN BYTE watchDogFlag,
+ OUT ULPWORD pSPXConnectionID,
+ IN LPECB pEcb,
+ IN ECB_ADDRESS EcbAddress
+ )
+
+/*++
+
+Routine Description:
+
+ Creates a connection with a remote SPX socket. The remote end can be on
+ this machine (i.e. same app in DOS world)
+
+ This call is Asynchronous
+
+Arguments:
+
+ Inputs
+ retryCount
+ watchDogFlag
+ pEcb
+ EcbAddress
+
+ Outputs
+ pSPXConnectionID
+
+Return Value:
+
+ 00h Attempting to talk to remote
+ EFh Local connection table full
+ FDh Fragment count not 1; buffer size not 42
+ FFh Send socket not open
+
+--*/
+
+{
+ LPXECB pXecb = RetrieveXEcb(ECB_TYPE_SPX, pEcb, EcbAddress);
+ LPSOCKET_INFO pSocketInfo;
+ LPCONNECTION_INFO pConnectionInfo;
+ WORD connectionId;
+ LPSPX_PACKET pPacket;
+ SOCKADDR_IPX destination;
+ int rc;
+ SOCKET s;
+
+ pSocketInfo = FindSocket(pXecb->SocketNumber);
+ if (!pSocketInfo) {
+ CompleteEcb(pXecb, ECB_CC_NON_EXISTENT_SOCKET);
+ return SPX_NON_EXISTENT_SOCKET;
+ }
+
+ //
+ // if no outstanding IPX operations, change socket to SPX
+ //
+
+ if (!pSocketInfo->SpxSocket) {
+ if (!(pSocketInfo->PendingSends && pSocketInfo->PendingListens)) {
+ rc = ReopenSocket(pSocketInfo);
+ } else {
+ rc = ECB_CC_BAD_SEND_REQUEST;
+ }
+ if (rc != SPX_SUCCESS) {
+ CompleteOrQueueEcb(pXecb, (BYTE)rc);
+ return SPX_BAD_SEND_REQUEST;
+ }
+ }
+
+ //
+ // real SPX will use the ECB to send an ESTABLISH CONNECTION packet. This
+ // is handled for us within the SPX transport. Nevertheless we must check
+ // the fragment and dismiss the request if its not sufficient
+ //
+
+ if ((pXecb->Ecb->FragmentCount != 1)
+ || (ECB_FRAGMENT(pXecb->Ecb, 0)->Length < SPX_HEADER_LENGTH)) {
+ CompleteEcb(pXecb, ECB_CC_BAD_SEND_REQUEST);
+ return SPX_BAD_SEND_REQUEST;
+ }
+
+ //
+ // the socket is open for SPX. Allocate a connection/connection ID
+ //
+
+ pConnectionInfo = AllocateConnection(pSocketInfo);
+ if (pConnectionInfo) {
+
+ //
+ // create new socket, bound to the same local address as the parent
+ // socket. This is the 'connection'
+ //
+
+#if REUSEADDR
+
+ connectionId = pSocketInfo->SocketNumber;
+ rc = CreateSocket(SOCKET_TYPE_SPX, &connectionId, &pConnectionInfo->Socket);
+ s = pConnectionInfo->Socket;
+// if (rc == SPX_SUCCESS) {
+
+#else
+
+ s = socket(AF_IPX, SOCK_SEQPACKET, NSPROTO_SPX);
+ if (s != INVALID_SOCKET) {
+
+ u_long arg = !0;
+
+ //
+ // put the socket in non-blocking I/O mode
+ //
+
+ rc = ioctlsocket(s, FIONBIO, &arg);
+ if (rc != SOCKET_ERROR) {
+
+ int true = 1;
+
+ rc = setsockopt(s,
+ NSPROTO_IPX,
+ IPX_RECVHDR,
+ (char FAR*)&true,
+ sizeof(true)
+ );
+ if (rc != SOCKET_ERROR) {
+ pConnectionInfo->Socket = s;
+ } else {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_SPXEstablishConnection,
+ IPXDBG_LEVEL_ERROR,
+ "VwSPXEstablishConnection: setsockopt(IPX_RECVHDR) returns %d\n",
+ WSAGetLastError()
+ ));
+
+ }
+ } else {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_SPXEstablishConnection,
+ IPXDBG_LEVEL_ERROR,
+ "VwSPXEstablishConnection: ioctlsocket(FIONBIO) returns %d\n",
+ WSAGetLastError()
+ ));
+
+ }
+ } else {
+ rc = WSAGetLastError();
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_SPXEstablishConnection,
+ IPXDBG_LEVEL_ERROR,
+ "VwSPXEstablishConnection: socket() returns %d\n",
+ rc
+ ));
+
+ }
+
+#endif
+
+ } else {
+ rc = !SPX_SUCCESS;
+ }
+
+ if (rc == SPX_SUCCESS) {
+ pConnectionInfo->State = CI_STARTING;
+ connectionId = pConnectionInfo->ConnectionId;
+
+ //
+ // set the ECB InUse field to 0xF7. Same as snowball by observation (and
+ // probably correct anyway since it looks as though 0xF7 means 'waiting
+ // to receive SPX packet', which is true in this case - normally SPX
+ // creates a connection by sending an establish frame then waits for the
+ // ack frame
+ //
+
+ pXecb->Ecb->InUse = ECB_IU_LISTENING_SPX;
+ } else {
+
+ //
+ // if we failed to get CONNECTION_INFO or create the new socket, return
+ // immediately with an error (socket table full?)
+ //
+
+ if (s != INVALID_SOCKET) {
+ closesocket(s);
+ }
+ if (pConnectionInfo) {
+ DeallocateConnection(pConnectionInfo);
+ }
+ CompleteEcb(pXecb, ECB_CC_CONNECTION_TABLE_FULL);
+ return SPX_CONNECTION_TABLE_FULL;
+ }
+
+ //
+ // get the destination info from the SPX header in VDM memory and set up the
+ // connection. If the connect request would wait then we leave AES to
+ // periodically check the progress of the request
+ //
+
+ pPacket = (LPSPX_PACKET)GET_FAR_POINTER(&ECB_FRAGMENT(pXecb->Ecb, 0)->Address,
+ IS_PROT_MODE(pXecb)
+ );
+ //
+ // fill in the packet details (app shouldn't look at these until the command
+ // completes). In 16-bit SPX, these values are filled in by the transport.
+ // Our transport does not return these values, so we have to 'invent' them,
+ // but since they are fairly static it should be ok (maybe the transport
+ // should return them)
+ //
+
+ pPacket->Checksum = 0xffff;
+ pPacket->Length = L2BW(SPX_HEADER_LENGTH);
+ pPacket->TransportControl = 0;
+ pPacket->PacketType = SPX_PACKET_TYPE;
+ pPacket->Source.Socket = pSocketInfo->SocketNumber;
+ pPacket->ConnectionControl = SPX_SYSTEM_PACKET | SPX_ACK_REQUIRED;
+ pPacket->DataStreamType = SPX_DS_ESTABLISH;
+ pPacket->SourceConnectId = pConnectionInfo->ConnectionId;
+ pPacket->DestinationConnectId = 0xffff;
+ pPacket->SequenceNumber = 0;
+ pPacket->AckNumber = 0;
+ pPacket->AllocationNumber = 0;
+
+ //
+ // get the destination address info
+ //
+
+ CopyMemory(&destination.sa_netnum,
+ (LPBYTE)&pPacket->Destination,
+ sizeof(pPacket->Destination)
+ );
+ destination.sa_family = AF_IPX;
+
+ //
+ // initiate the connection
+ //
+
+ rc = connect(s, (LPSOCKADDR)&destination, sizeof(destination));
+ if (rc != SOCKET_ERROR) {
+
+ //
+ // add the CONNECTION_INFO structure to the list of connections owned
+ // by this socket and set the connection state to ESTABLISHED
+ //
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_SPXEstablishConnection,
+ IPXDBG_LEVEL_INFO,
+ "VwSPXEstablishConnection: socket connected\n"
+ ));
+
+ RequestMutex();
+ QueueConnection(pSocketInfo, pConnectionInfo);
+ pConnectionInfo->State = CI_ESTABLISHED;
+ ReleaseMutex();
+
+ //
+ // the connection ID also appears in the first segment of the establish
+ // ECB
+ //
+
+ pPacket->SourceConnectId = connectionId;
+
+ //
+ // the SPXEstablishConnection ECB is done!
+ //
+
+ CompleteEcb(pXecb, ECB_CC_SUCCESS);
+ } else {
+ rc = WSAGetLastError();
+ if (rc == WSAEWOULDBLOCK) {
+
+ //
+ // the connect request is in progress. Add it to the queue of
+ // pending SPXEstablishConnection requests (SHOULD ONLY BE 1 PER
+ // CONNECTION!!!) and add the CONNECTION_INFO structure to the
+ // owning SOCKET_INFO structure
+ //
+
+ RequestMutex();
+ QueueEcb(pXecb,
+ &pConnectionInfo->ConnectQueue,
+ CONNECTION_CONNECT_QUEUE
+ );
+ QueueConnection(pSocketInfo, pConnectionInfo);
+ ReleaseMutex();
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_SPXEstablishConnection,
+ IPXDBG_LEVEL_INFO,
+ "VwSPXEstablishConnection: connect() queued\n"
+ ));
+
+ } else {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_SPXEstablishConnection,
+ IPXDBG_LEVEL_ERROR,
+ "VwSPXEstablishConnection: connect(%x) returns %d\n",
+ s,
+ rc
+ ));
+
+ //
+ // the connect request failed. Deallocate all resources (socket,
+ // CONNECTION_INFO, XECB) and return failure
+ //
+
+ closesocket(pConnectionInfo->Socket);
+ DeallocateConnection(pConnectionInfo);
+ CompleteEcb(pXecb, ECB_CC_CONNECTION_ABORTED);
+ return SPX_CONNECTION_ABORTED;
+ }
+ }
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_SPXEstablishConnection,
+ IPXDBG_LEVEL_INFO,
+ "VwSPXEstablishConnection: returning %04x\n",
+ connectionId
+ ));
+
+ *pSPXConnectionID = connectionId;
+ return SPX_SUCCESS;
+}
+
+
+WORD
+_VwSPXGetConnectionStatus(
+ IN WORD connectionId,
+ OUT LPSPX_CONNECTION_STATS pStats
+ )
+
+/*++
+
+Routine Description:
+
+ Returns buffer crammed full of useful statistics or something (hu hu huh)
+
+ This call is Synchronous
+
+Arguments:
+
+ Inputs
+ connectionId
+ pStats
+
+ Outputs
+ on output, buffer in pStats contains:
+
+ BYTE ConnectionStatus
+ BYTE WatchDogActive
+ WORD LocalConnectionID
+ WORD RemoteConnectionID
+ WORD SequenceNumber
+ WORD LocalAckNumber
+ WORD LocalAllocationNumber
+ WORD RemoteAckNumber
+ WORD RemoteAllocationNumber
+ WORD LocalSocket
+ BYTE ImmediateAddress[6]
+ BYTE RemoteNetwork[4]
+ WORD RetransmissionCount
+ WORD RetransmittedPackets
+ WORD SuppressedPackets
+
+Return Value:
+ 00h Connection is active
+ EEh No such connection
+
+--*/
+
+{
+ int rc;
+ IPX_SPXCONNSTATUS_DATA buf;
+ int buflen = sizeof(buf);
+ LPCONNECTION_INFO pConnectionInfo;
+
+ pConnectionInfo = FindConnection(connectionId);
+ if (!pConnectionInfo) {
+ return SPX_INVALID_CONNECTION;
+ }
+
+ //
+ // get the stats
+ //
+
+ rc = getsockopt(pConnectionInfo->Socket,
+ NSPROTO_IPX,
+ IPX_SPXGETCONNECTIONSTATUS,
+ (char FAR*)&buf,
+ &buflen
+ );
+ if (rc == SOCKET_ERROR) {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_SPXGetConnectionStatus,
+ IPXDBG_LEVEL_ERROR,
+ "VwSPXGetConnectionStatus: getsockopt() returns %d\n",
+ WSAGetLastError()
+ ));
+
+ //
+ // the request to get the stats failed - probably because the socket is
+ // not yet connected. Fill in those bits we know about
+ //
+
+ ZeroMemory((LPBYTE)pStats, sizeof(*pStats));
+ } else {
+
+ //
+ // copy the returned fields
+ //
+
+ pStats->RemoteConnectionId = buf.RemoteConnectionId;
+ pStats->LocalSequenceNumber = buf.LocalSequenceNumber;
+ pStats->LocalAckNumber = buf.LocalAckNumber;
+ pStats->LocalAllocNumber = buf.LocalAllocNumber;
+ pStats->RemoteAckNumber = buf.RemoteAckNumber;
+ pStats->RemoteAllocNumber = buf.RemoteAllocNumber;
+ pStats->LocalSocket = buf.LocalSocket;
+ CopyMemory(&pStats->ImmediateAddress,
+ &buf.ImmediateAddress,
+ sizeof(buf.ImmediateAddress)
+ );
+
+ //
+ // copy remote network as a DWORD. Endian format is same for both
+ //
+
+ *(ULPDWORD)&pStats->RemoteNetwork = *(LPDWORD)&buf.RemoteNetwork;
+ CopyMemory(&pStats->RemoteNode,
+ &buf.RemoteNode,
+ sizeof(buf.RemoteNode)
+ );
+ pStats->RemoteSocket = buf.RemoteSocket;
+ pStats->RetransmissionCount = buf.RetransmissionCount;
+ pStats->EstimatedRoundTripDelay = buf.EstimatedRoundTripDelay;
+ pStats->RetransmittedPackets = buf.RetransmittedPackets;
+ pStats->SuppressedPackets = buf.SuppressedPacket;
+ }
+
+ //
+ // fill in common, known fields
+ //
+
+ pStats->State = pConnectionInfo->State; // not returned by NWIPX
+ pStats->WatchDog = 0x02; // see novell dog-umentation
+ pStats->LocalConnectionId = L2BW(pConnectionInfo->ConnectionId);
+ pStats->LocalSocket = pConnectionInfo->OwningSocket->SocketNumber;
+
+ DUMPSTATS(pStats);
+
+ //
+ // we are returning some kind o stats - therefore success
+ //
+
+ return SPX_SUCCESS;
+}
+
+
+WORD
+_VwSPXInitialize(
+ OUT ULPBYTE pMajorRevisionNumber,
+ OUT ULPBYTE pMinorRevisionNumber,
+ OUT ULPWORD pMaxConnections,
+ OUT ULPWORD pAvailableConnections
+ )
+
+/*++
+
+Routine Description:
+
+ Informs the app that SPX is present on this station
+
+ This call is Synchronous
+
+Arguments:
+
+ Inputs
+
+ Outputs
+ pMajorRevisionNumber - SPX Major revision number
+ pminorRevisionNumber - SPX Minor revision number
+ pMaxConnections - Maximum SPX connections supported
+ normally from SHELL.CFG
+ pAvailableConnections - Available SPX connections
+
+Return Value:
+
+ 00h Not installed
+ FFh Installed
+
+--*/
+
+{
+
+ //
+ // The following values are returned same as per Windows For Workgroups
+ // v3.10
+ //
+
+ *pMajorRevisionNumber = 3;
+ *pMinorRevisionNumber = 10;
+ *pMaxConnections = 128;
+ *pAvailableConnections = *pMaxConnections - 1 ;
+
+ return SPX_INSTALLED;
+}
+
+
+VOID
+_VwSPXListenForConnection(
+ IN BYTE retryCount,
+ IN BYTE watchDogFlag,
+ IN LPECB pEcb,
+ IN ECB_ADDRESS EcbAddress
+ )
+
+/*++
+
+Routine Description:
+
+ Listens for an incoming connection request
+
+ This call is Asynchronous
+
+Arguments:
+
+ Inputs
+ retryCount
+ watchDogFlag
+ pEcb
+ EcbAddress
+
+ Outputs
+ Nothing
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LPXECB pXecb = RetrieveXEcb(ECB_TYPE_SPX, pEcb, EcbAddress);
+ LPSOCKET_INFO pSocketInfo;
+ LPCONNECTION_INFO pConnectionInfo;
+ SOCKET sock;
+ SOCKET conn;
+ SOCKADDR_IPX remoteAddress;
+ int rc;
+ BYTE completionCode;
+
+ //
+ // it turns out that SPXListenForConnection doesn't need a fragment to
+ // receive connection info - that is handled by SPXListenForSequencedPacket
+ // that the app has dutifully initiated
+ //
+
+ pSocketInfo = FindSocket(pXecb->SocketNumber);
+ if (!pSocketInfo) {
+ completionCode = ECB_CC_NON_EXISTENT_SOCKET;
+ goto lc_completion_exit;
+ }
+
+ //
+ // if no outstanding IPX operations, change socket to SPX
+ //
+
+ if (!pSocketInfo->SpxSocket) {
+ if (!(pSocketInfo->PendingSends && pSocketInfo->PendingListens)) {
+ rc = ReopenSocket(pSocketInfo);
+ } else {
+ rc = ECB_CC_BAD_LISTEN_REQUEST;
+ }
+ if (rc != SPX_SUCCESS) {
+ completionCode = (BYTE)rc;
+ goto lc_completion_exit;
+ }
+ }
+
+ //
+ // the socket is open for SPX. Allocate a connection/connection ID
+ //
+
+ pConnectionInfo = AllocateConnection(pSocketInfo);
+ if (!pConnectionInfo) {
+ completionCode = ECB_CC_CONNECTION_TABLE_FULL;
+ goto lc_completion_exit;
+ }
+
+ //
+ // put the socket into listening state and try to accept a connection
+ //
+
+ sock = pSocketInfo->Socket;
+
+ //
+ // BUGBUG: if the socket is already listening, will probably return an
+ // error: just queue
+ //
+
+ rc = listen(sock, MAX_LISTEN_QUEUE_SIZE);
+ if (rc != SOCKET_ERROR) {
+
+ int addressLength = sizeof(remoteAddress);
+
+ conn = accept(sock, (LPSOCKADDR)&remoteAddress, &addressLength);
+ if (conn != SOCKET_ERROR) {
+
+ //
+ // we want to receive the frame headers from this socket
+ //
+
+ BOOL bval = TRUE;
+
+ rc = setsockopt(conn,
+ NSPROTO_IPX,
+ IPX_RECVHDR,
+ (char FAR*)&bval,
+ sizeof(bval)
+ );
+ if (rc != SOCKET_ERROR) {
+
+ //
+ // update the CONNECTION_INFO structure with the actual socket
+ // identifier and set the connection state to established
+ //
+
+ pConnectionInfo->Socket = conn;
+ pConnectionInfo->State = CI_ESTABLISHED;
+
+ //
+ // add the CONNECTION_INFO structure to the list of connections owned
+ // by this socket
+ //
+
+ RequestMutex();
+ QueueConnection(pSocketInfo, pConnectionInfo);
+ ReleaseMutex();
+
+ //
+ // update the app's ECB with the connection ID
+ //
+
+ SPX_ECB_CONNECTION_ID(pXecb->Ecb) = pConnectionInfo->ConnectionId;
+
+ //
+ // and with the partner address info
+ //
+
+ CopyMemory(&pXecb->Ecb->DriverWorkspace,
+ &remoteAddress.sa_netnum,
+ sizeof(pXecb->Ecb->DriverWorkspace)
+ );
+ completionCode = ECB_CC_SUCCESS;
+ goto lc_completion_exit;
+ } else {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_SPXListenForConnection,
+ IPXDBG_LEVEL_ERROR,
+ "VwSPXListenForConnection: setsockopt(RECVHDR) returns %d\n",
+ WSAGetLastError()
+ ));
+
+ //
+ // BUGBUG: value?
+ //
+
+ closesocket(conn);
+ completionCode = ECB_CC_CONNECTION_ABORTED;
+ goto lc_deallocate_exit;
+ }
+ } else {
+ rc = WSAGetLastError();
+ if (rc == WSAEWOULDBLOCK) {
+
+ //
+ // the accept request is in progress. Add it to the queue of
+ // pending SPXListenForConnection requests (SHOULD ONLY BE 1 PER
+ // CONNECTION!!!) and add the CONNECTION_INFO structure to the
+ // owning SOCKET_INFO structure
+ //
+
+ pConnectionInfo->State = CI_WAITING; // waiting for incoming connect
+ RequestMutex();
+ QueueEcb(pXecb,
+ &pConnectionInfo->AcceptQueue,
+ CONNECTION_ACCEPT_QUEUE
+ );
+ QueueConnection(pSocketInfo, pConnectionInfo);
+ pXecb->Ecb->InUse = ECB_IU_AWAITING_CONNECTION;
+ ReleaseMutex();
+ } else {
+
+ //
+ // the accept request failed. Deallocate all resources
+ // (CONNECTION_INFO, XECB) and complete the ECB with a failure
+ // indication
+ //
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_SPXListenForConnection,
+ IPXDBG_LEVEL_ERROR,
+ "VwSPXListenForConnection: accept() returns %d\n",
+ rc
+ ));
+
+ //
+ // BUGBUG: completion code?
+ //
+
+ completionCode = ECB_CC_CONNECTION_ABORTED;
+ goto lc_deallocate_exit;
+ }
+ }
+ } else {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_SPXListenForConnection,
+ IPXDBG_LEVEL_ERROR,
+ "VwSPXListenForConnection: listen() returns %d\n",
+ WSAGetLastError()
+ ));
+
+ //
+ // listen failed? Bogus. Complete the ECB and we're outta here
+ //
+
+ //
+ // BUGBUG: completion code?
+ //
+
+ completionCode = ECB_CC_CONNECTION_ABORTED;
+ goto lc_deallocate_exit;
+ }
+
+ //
+ // here if we queued the listen request
+ //
+
+ return;
+
+lc_deallocate_exit:
+ DeallocateConnection(pConnectionInfo);
+
+lc_completion_exit:
+ CompleteEcb(pXecb, completionCode);
+}
+
+
+VOID
+_VwSPXListenForSequencedPacket(
+ IN LPECB pEcb,
+ IN ECB_ADDRESS EcbAddress
+ )
+
+/*++
+
+Routine Description:
+
+ Attempts to receive an SPX packet. This call is made against the top-level
+ socket (the socket in SPX-speak, not the connection). We can receive a
+ packet from any connection assigned to this socket. In this function, we
+ just queue the ECB (since there is no return status, we expect that the
+ app has supplied an ESR) and let AES handle it
+
+ This call is Asynchronous
+
+Arguments:
+
+ Inputs
+ pEcb
+ EcbAddress
+
+ Outputs
+ Nothing
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LPXECB pXecb = RetrieveXEcb(ECB_TYPE_SPX, pEcb, EcbAddress);
+ LPSOCKET_INFO pSocketInfo;
+ int rc;
+ BOOL dummy ;
+ BYTE status;
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_SPXListenForSequencedPacket,
+ IPXDBG_LEVEL_INFO,
+ "VwSPXListenForSequencedPacket(%04x:%04x) socket=%04x ESR=%04x:%04x\n",
+ HIWORD(pXecb->EcbAddress),
+ LOWORD(pXecb->EcbAddress),
+ B2LW(pXecb->SocketNumber),
+ HIWORD(pXecb->EsrAddress),
+ LOWORD(pXecb->EsrAddress)
+ ));
+
+ pSocketInfo = FindSocket(pXecb->SocketNumber);
+ if (!pSocketInfo) {
+ status = ECB_CC_NON_EXISTENT_SOCKET;
+ goto lp_exit;
+ }
+
+ //
+ // if no outstanding IPX operations, change socket to SPX
+ //
+
+ if (!pSocketInfo->SpxSocket) {
+ if (!(pSocketInfo->PendingSends && pSocketInfo->PendingListens)) {
+ rc = ReopenSocket(pSocketInfo);
+ } else {
+ rc = ECB_CC_BAD_LISTEN_REQUEST;
+ }
+ if (rc != SPX_SUCCESS) {
+ status = (BYTE)rc;
+ goto lp_exit;
+ }
+ }
+
+ //
+ // the first fragment must be large enough to hold an SPX packet header
+ //
+
+ if ((pXecb->Ecb->FragmentCount == 0)
+ || (ECB_FRAGMENT(pXecb->Ecb, 0)->Length < SPX_HEADER_LENGTH)) {
+ status = ECB_CC_BAD_LISTEN_REQUEST;
+ goto lp_exit;
+ }
+
+ //
+ // we have a socket and the receive buffer looks good. Get a buffer for recv()
+ //
+
+ if (!GetIoBuffer(pXecb, FALSE, SPX_HEADER_LENGTH)) {
+ status = ECB_CC_BAD_LISTEN_REQUEST;
+ goto lp_exit;
+ } else {
+
+ //
+ // when recv() is attempted against this request, it will be the first
+ // time we tried to receive anything to this buffer. That means (if we
+ // get anything) that the buffer will contain the length of the entire
+ // frame
+ //
+
+ pXecb->Flags |= XECB_FLAG_FIRST_RECEIVE;
+ }
+
+ //
+ // mark the VDM ECB as in use
+ //
+
+ pXecb->Ecb->InUse = ECB_IU_LISTENING_SPX;
+
+ //
+ // add this ECB to the queue of listens for the top-level socket and quit
+ //
+
+ RequestMutex();
+
+ if ((pXecb->Ecb->FragmentCount == 1) &&
+ (ECB_FRAGMENT(pXecb->Ecb, 0)->Length == SPX_HEADER_LENGTH))
+ {
+ QueueEcb(pXecb, &pSocketInfo->HeaderQueue, SOCKET_HEADER_QUEUE);
+ }
+ else
+ {
+ QueueEcb(pXecb, &pSocketInfo->ListenQueue, SOCKET_LISTEN_QUEUE);
+ }
+
+ ReleaseMutex();
+
+ //
+ // see if we are ready to rock
+ //
+
+ CheckPendingSpxRequests(&dummy);
+ return;
+
+lp_exit:
+ CompleteOrQueueEcb(pXecb, status);
+}
+
+
+VOID
+_VwSPXSendSequencedPacket(
+ IN WORD connectionId,
+ IN LPECB pEcb,
+ IN ECB_ADDRESS EcbAddress
+ )
+
+/*++
+
+Routine Description:
+
+ Sends a packet on an SPX connection
+
+ This call is Asynchronous
+
+Arguments:
+
+ Inputs
+ connectionId
+ pEcb
+ EcbAddress
+
+ Outputs
+ Nothing
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LPXECB pXecb = RetrieveXEcb(ECB_TYPE_SPX, pEcb, EcbAddress);
+ LPCONNECTION_INFO pConnectionInfo;
+ int rc;
+ BOOL addToQueue;
+ LPSPX_PACKET pPacket;
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_SPXSendSequencedPacket,
+ IPXDBG_LEVEL_INFO,
+ "VwSPXSendSequencedPacket(%04x:%04x) Connection=%04x ESR=%04x:%04x\n",
+ HIWORD(pXecb->EcbAddress),
+ LOWORD(pXecb->EcbAddress),
+ connectionId,
+ HIWORD(pXecb->EsrAddress),
+ LOWORD(pXecb->EsrAddress)
+ ));
+
+ IPXDUMPECB((pXecb->Ecb,
+ HIWORD(pXecb->EcbAddress),
+ LOWORD(pXecb->EcbAddress),
+ ECB_TYPE_SPX,
+ TRUE,
+ TRUE,
+ IS_PROT_MODE(pXecb)
+ ));
+
+ //
+ // find the connection. No need to check if this is an SPX socket: if we
+ // can't find the connection, its a bad connection, else the socket must
+ // be open for SPX
+ //
+
+ pConnectionInfo = FindConnection(connectionId);
+ if (!pConnectionInfo || (pConnectionInfo->State != CI_ESTABLISHED)) {
+ CompleteOrQueueEcb(pXecb, ECB_CC_INVALID_CONNECTION);
+ return;
+ }
+
+ //
+ // the first fragment must be large enough to hold an SPX packet header
+ //
+
+ if ((pXecb->Ecb->FragmentCount == 0)
+ || (ECB_FRAGMENT(pXecb->Ecb, 0)->Length < SPX_HEADER_LENGTH)) {
+ CompleteOrQueueEcb(pXecb, ECB_CC_BAD_SEND_REQUEST);
+ return;
+ }
+ if (!GetIoBuffer(pXecb, TRUE, SPX_HEADER_LENGTH)) {
+ CompleteOrQueueEcb(pXecb, ECB_CC_BAD_SEND_REQUEST);
+ return;
+ }
+
+ pPacket = (LPSPX_PACKET)GET_FAR_POINTER(
+ &(ECB_FRAGMENT(pXecb->Ecb, 0)->Address),
+ IS_PROT_MODE(pXecb)
+ );
+
+ //
+ // fill in the following fields in the SPX header:
+ //
+ // Checksum
+ // Length
+ // TransportControl
+ // Source (network, node, socket)
+ //
+ // BUGBUG: Does real IPX modify these fields in app memory?
+ // If so, does the app expect modified fields?
+ // If not, we need to always copy then modify memory,
+ // even if only 1 fragment
+ //
+
+ pPacket->Checksum = 0xFFFF;
+
+ //
+ // since the transport adds the SPX header, we subtracted the length of
+ // the header from our transmit length; add it back when updating the
+ // header in the app's space
+ //
+
+ pPacket->Length = L2BW(pXecb->Length + SPX_HEADER_LENGTH);
+ pPacket->TransportControl = 0;
+ CopyMemory((LPBYTE)&pPacket->Source,
+ &MyInternetAddress.sa_netnum,
+ sizeof(MyInternetAddress.sa_netnum)
+ + sizeof(MyInternetAddress.sa_nodenum)
+ );
+ pPacket->Source.Socket = pConnectionInfo->OwningSocket->SocketNumber;
+
+ //
+ // if we allocated a buffer then there is >1 fragment. Collect them
+ //
+
+ if (pXecb->Flags & XECB_FLAG_BUFFER_ALLOCATED) {
+ GatherData(pXecb, SPX_HEADER_LENGTH);
+ }
+
+ //
+ // BUGBUG: length check: >576 == error??
+ //
+
+ //
+ // mark the VDM ECB as in use
+ //
+
+ pXecb->Ecb->InUse = ECB_IU_SENDING;
+
+ //
+ // if there is a send queued on this connection already, add this request
+ // to the back of the queue and let AES do the rest
+ //
+
+ RequestMutex();
+ if (pConnectionInfo->SendQueue.Head) {
+ addToQueue = TRUE;
+ } else {
+
+ int dataStreamType;
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_SPXSendSequencedPacket,
+ IPXDBG_LEVEL_INFO,
+ "VwSPXSendSequencedPacket: sending %d (0x%x) bytes from %08x\n",
+ pXecb->Length,
+ pXecb->Length,
+ pXecb->Data
+ ));
+
+ //
+ // no outstanding sends queued for this connection. Start sending this
+ // packet
+ //
+
+ dataStreamType = (int)pPacket->DataStreamType;
+ rc = setsockopt(pConnectionInfo->Socket,
+ NSPROTO_IPX,
+ IPX_DSTYPE,
+ (char FAR*)&dataStreamType,
+ sizeof(dataStreamType)
+ );
+ if (rc != SOCKET_ERROR) {
+
+ //
+ // if the app set the END_OF_MESSAGE bit in the ConnectionControl
+ // field then set the flags to 0: NWLink will automatically set the
+ // end-of-message bit in the packet; otherwise set flags to MSG_PARTIAL
+ // to indicate to NWLink that it *shouldn't* set the bit in the packet
+ //
+
+ int flags = (pPacket->ConnectionControl & SPX_END_OF_MESSAGE)
+ ? 0
+ : MSG_PARTIAL
+ ;
+
+ rc = send(pConnectionInfo->Socket, pXecb->Data, pXecb->Length, flags);
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_SPXSendSequencedPacket,
+ IPXDBG_LEVEL_INFO,
+ "VwSPXSendSequencedPacket: send() returns %d\n",
+ rc
+ ));
+
+ if (rc == pXecb->Length) {
+
+ //
+ // all data sent
+ //
+
+ CompleteOrQueueIo(pXecb, ECB_CC_SUCCESS);
+ addToQueue = FALSE;
+ } else if (rc == SOCKET_ERROR) {
+ rc = WSAGetLastError();
+ if (rc == WSAEWOULDBLOCK) {
+
+ //
+ // can't send right now. Queue it for AES
+ //
+
+ addToQueue = TRUE;
+ }
+ } else {
+
+ //
+ // partial data sent. Update the buffer pointer and length fields
+ // and queue this request
+ //
+
+ pXecb->Data += rc;
+ pXecb->Length -= (WORD)rc;
+ addToQueue = TRUE;
+ }
+ } else {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_SPXSendSequencedPacket,
+ IPXDBG_LEVEL_ERROR,
+ "VwSPXSendSequencedPacket: setsockopt(IPX_DSTYPE) returns %d\n",
+ WSAGetLastError()
+ ));
+
+ CompleteOrQueueIo(pXecb, ECB_CC_BAD_REQUEST);
+ }
+ }
+
+ //
+ // if addToQueue set then we can't do anything right now - add this
+ // request to the send queue
+ //
+
+ if (addToQueue) {
+
+ IPXDBGPRINT((__FILE__, __LINE__,
+ FUNCTION_SPXSendSequencedPacket,
+ IPXDBG_LEVEL_WARNING,
+ "VwSPXSendSequencedPacket: adding XECB %08x to send queue\n",
+ pXecb
+ ));
+
+ QueueEcb(pXecb, &pConnectionInfo->SendQueue, CONNECTION_SEND_QUEUE);
+ }
+ ReleaseMutex();
+}
+
+
+VOID
+_VwSPXTerminateConnection(
+ IN WORD SPXConnectionID,
+ IN LPECB pEcb,
+ IN ECB_ADDRESS EcbAddress
+ )
+
+/*++
+
+Routine Description:
+
+ Terminates a connection
+
+Arguments:
+
+ SPXConnectionID - connection to terminate
+ pEcb - pointer to 16-bit ECB to use
+ EcbAddress - address of 16-bit ECB in 16:16 format
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LPCONNECTION_INFO pConnectionInfo;
+ LPXECB pXecb = RetrieveXEcb(ECB_TYPE_SPX, pEcb, EcbAddress);
+ BYTE status;
+ BYTE completionCode;
+
+ RequestMutex();
+ pConnectionInfo = FindConnection(SPXConnectionID);
+ if (pConnectionInfo) {
+
+ //
+ // once dequeued, pConnectionInfo no longer points to OwningSocket
+ //
+
+ WORD socketNumber = pConnectionInfo->OwningSocket->SocketNumber;
+
+ DequeueConnection(pConnectionInfo->OwningSocket, pConnectionInfo);
+ if ((pXecb->Ecb->FragmentCount >= 1)
+ && (ECB_FRAGMENT(pXecb->Ecb, 0)->Length >= SPX_HEADER_LENGTH)) {
+
+ LPSPX_PACKET pPacket;
+ SOCKADDR_IPX remote;
+ int remoteLen = sizeof(remote);
+
+ completionCode = ECB_CC_CONNECTION_TERMINATED;
+ status = ECB_CC_SUCCESS;
+
+ //
+ // fill in the packet header: this would normally contain the
+ // acknowledgement packet from the remote partner
+ //
+
+ pPacket = (LPSPX_PACKET)GET_FAR_POINTER(
+ &(ECB_FRAGMENT(pXecb->Ecb, 0)->Address),
+ IS_PROT_MODE(pXecb)
+ );
+ pPacket->Checksum = 0xffff;
+ pPacket->Length = L2BW(SPX_HEADER_LENGTH);
+ pPacket->TransportControl = 0;
+ pPacket->PacketType = SPX_PACKET_TYPE;
+ getpeername(pConnectionInfo->Socket, (LPSOCKADDR)&remote, &remoteLen);
+ CopyMemory((LPBYTE)&pPacket->Destination,
+ (LPBYTE)&remote.sa_netnum,
+ sizeof(NETWARE_ADDRESS)
+ );
+ CopyMemory((LPBYTE)&pPacket->Source,
+ (LPBYTE)&MyInternetAddress.sa_netnum,
+ sizeof(INTERNET_ADDRESS)
+ );
+ pPacket->Source.Socket = socketNumber;
+ pPacket->ConnectionControl = SPX_ACK_REQUIRED;
+ pPacket->DataStreamType = SPX_DS_TERMINATE;
+ pPacket->SourceConnectId = pConnectionInfo->ConnectionId;
+ pPacket->DestinationConnectId = 0;
+ pPacket->SequenceNumber = 0;
+ pPacket->AckNumber = 0;
+ pPacket->AllocationNumber = 0;
+
+ } else {
+ completionCode = ECB_CC_CONNECTION_ABORTED;
+ status = ECB_CC_BAD_REQUEST;
+ }
+ AbortOrTerminateConnection(pConnectionInfo, completionCode);
+ } else {
+ status = ECB_CC_INVALID_CONNECTION;
+ }
+ ReleaseMutex();
+ CompleteOrQueueEcb(pXecb, status);
+}
diff --git a/private/nw/vwipxspx/dll/vwspx.h b/private/nw/vwipxspx/dll/vwspx.h
new file mode 100644
index 000000000..68e1b63fa
--- /dev/null
+++ b/private/nw/vwipxspx/dll/vwspx.h
@@ -0,0 +1,62 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ vwspx.h
+
+Abstract:
+
+ Contains function prototypes for VWSPX.C
+
+Author:
+
+ Richard L Firth (rfirth) 25-Oct-1993
+
+Revision History:
+
+ 25-Oct-1993 rfirth
+ Created
+
+--*/
+
+VOID
+VwSPXAbortConnection(
+ VOID
+ );
+
+VOID
+VwSPXEstablishConnection(
+ VOID
+ );
+
+VOID
+VwSPXGetConnectionStatus(
+ VOID
+ );
+
+VOID
+VwSPXInitialize(
+ VOID
+ );
+
+VOID
+VwSPXListenForConnection(
+ VOID
+ );
+
+VOID
+VwSPXListenForSequencedPacket(
+ VOID
+ );
+
+VOID
+VwSPXSendSequencedPacket(
+ VOID
+ );
+
+VOID
+VwSPXTerminateConnection(
+ VOID
+ );
diff --git a/private/nw/vwipxspx/dll/vwvdm.h b/private/nw/vwipxspx/dll/vwvdm.h
new file mode 100644
index 000000000..2fd23ba22
--- /dev/null
+++ b/private/nw/vwipxspx/dll/vwvdm.h
@@ -0,0 +1,151 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ vwvdm.h
+
+Abstract:
+
+ Contains macros, manifests, includes for dealing with VDM
+
+Author:
+
+ Richard L Firth (rfirth) 25-Oct-1993
+
+Revision History:
+
+ 25-Oct-1993 rfirth
+ Created
+
+--*/
+
+#ifndef _VWVDM_H_
+#define _VWVDM_H_
+
+//
+// unaligned pointers - non-Intel platforms must use UNALIGNED to access data
+// in VDM which can (and most likely will) be aligned on odd-byte and word
+// boundaries
+//
+
+#ifndef ULPBYTE
+#define ULPBYTE BYTE UNALIGNED FAR*
+#endif
+
+#ifndef ULPWORD
+#define ULPWORD WORD UNALIGNED FAR*
+#endif
+
+#ifndef ULPDWORD
+#define ULPDWORD DWORD UNALIGNED FAR*
+#endif
+
+#ifndef ULPVOID
+#define ULPVOID VOID UNALIGNED FAR*
+#endif
+
+//
+// VDM macros
+//
+
+#define MSW_PE 0x0001 // Protect-mode Enable bit in x86 Machine Status Word
+
+//
+// POINTER_FROM_WORDS - returns 32-bit pointer to address in VDM memory described
+// by seg:off. If seg:off = 0:0, returns NULL
+//
+
+#define POINTER_FROM_WORDS(seg, off, size) \
+ _inlinePointerFromWords((WORD)(seg), (WORD)(off), (WORD)(size))
+
+//
+// _inlinePointerFromWords - the POINTER_FROM_WORDS macro is inefficient if the
+// arguments are calls to eg. getES(), getBX() - the calls are made twice if
+// the pointer turns out to be non-zero. Use an inline function to achieve the
+// same results, but only call function arguments once
+//
+
+__inline LPVOID _inlinePointerFromWords(WORD seg, WORD off, WORD size) {
+ return (seg | off)
+ ? (LPVOID)GetVDMPointer((ULONG)(MAKELONG(off, seg)), size, (CHAR)((getMSW() & MSW_PE) ? TRUE : FALSE))
+ : NULL;
+}
+
+//
+// GET_POINTER - does the same thing as POINTER_FROM_WORDS, but we know beforehand
+// which processor mode we are in
+//
+
+#define GET_POINTER(seg, off, size, mode) \
+ _inlineGetPointer((WORD)(seg), (WORD)(off), (WORD)(size), (BOOL)(mode))
+
+__inline LPVOID _inlineGetPointer(WORD seg, WORD off, WORD size, BOOL mode) {
+ return (seg | off)
+ ? (LPVOID)GetVDMPointer(MAKELONG(off, seg), size, (UCHAR)mode)
+ : NULL;
+}
+
+//
+// GET_FAR_POINTER - same as READ_FAR_POINTER with the same proviso as for
+// GET_POINTER
+//
+
+#define GET_FAR_POINTER(addr, mode) ((LPBYTE)(GET_POINTER(GET_SELECTOR(addr), GET_OFFSET(addr), sizeof(LPBYTE), mode)))
+
+//
+// GET_SELECTOR - retrieves the selector word from the intel 32-bit far pointer
+// (DWORD) pointed at by <pointer> (remember: stored as offset, segment)
+//
+
+#define GET_SELECTOR(pointer) READ_WORD((LPWORD)(pointer)+1)
+
+//
+// GET_SEGMENT - same as GET_SELECTOR
+//
+
+#define GET_SEGMENT(pointer) GET_SELECTOR(pointer)
+
+//
+// GET_OFFSET - retrieves the offset word from an intel 32-bit far pointer
+// (DWORD) pointed at by <pointer> (remember: stored as offset, segment)
+//
+
+#define GET_OFFSET(pointer) READ_WORD((LPWORD)(pointer))
+
+//
+// READ_FAR_POINTER - read the pair of words in VDM memory, currently pointed at
+// by a 32-bit flat pointer and convert them to a 32-bit flat pointer
+//
+
+#define READ_FAR_POINTER(addr) ((LPBYTE)(POINTER_FROM_WORDS(GET_SELECTOR(addr), GET_OFFSET(addr), sizeof(LPBYTE))))
+
+//
+// READ_WORD - read a single 16-bit little-endian word from VDM memory. On non
+// Intel platforms, use unaligned pointer to access data
+//
+
+#define READ_WORD(addr) (*((ULPWORD)(addr)))
+
+//
+// READ_DWORD - read a 4-byte little-endian double word from VDM memory. On non
+// Intel platforms, use unaligned pointer to access data
+//
+
+#define READ_DWORD(addr) (*((ULPDWORD)(addr)))
+
+//
+// ARRAY_ELEMENTS - gives the number of elements of a particular type in an
+// array
+//
+
+#define ARRAY_ELEMENTS(a) (sizeof(a)/sizeof((a)[0]))
+
+//
+// LAST_ELEMENT - returns the index of the last element in array
+//
+
+#define LAST_ELEMENT(a) (ARRAY_ELEMENTS(a)-1)
+
+#endif // _VWVDM_H_