SPI.CPP

/*++ 

Copyright (c) 1996 Intel Corporation
Copyright 1996 - 1998 Microsoft Corporation
All Rights Reserved

Permission is granted to use, copy and distribute this software and
its documentation for any purpose and without fee, provided, that
the above copyright notice and this statement appear in all copies.
Intel makes no representations about the suitability of this
software for any purpose. This software is provided "AS IS."

Intel specifically disclaims all warranties, express or implied,
and all liability, including consequential and other indirect
damages, for the use of this software, including liability for
infringement of any proprietary rights, and including the
warranties of merchantability and fitness for a particular purpose.
Intel does not assume any responsibility for any errors which may
appear in this software nor any responsibility to update it.

Module Name:

SPI.CPP :

Abstract:

Contains all the entry points for the WS2SPI. This module implements a
sample WinSock2 layered service provider.

--*/

#include "precomp.h"


// The WinSock2 UpcallTable.
WSPUPCALLTABLEgUpCallTable;
LPWPUCOMPLETEOVERLAPPEDREQUESTlpWPUCompleteOverlappedRequest;

// Variables to track Startup/Cleanup Pairing.
CRITICAL_SECTION gInitCriticalSection;
DWORD gStartupCount=0;


// The catalog of providers
PDCATALOG gProviderCatalog;

// The worker thread for overlapped functions
#define UNINITIALIZED_THREAD ((PDWORKERTHREAD)-1)
PDWORKERTHREAD gWorkerThread=UNINITIALIZED_THREAD;

// The window for translation of async select messages
#define UNINITIALIZED_WINDOW ((PDASYNCWINDOW)-1)
PDASYNCWINDOW gAsyncWindow=UNINITIALIZED_WINDOW;

// The buffer manager for providers that modify the data stream
PDBUFFERMANAGER gBufferManager;

char gLibraryName[MAX_PATH] ="LSP.DLL";

#define SetBlockingProvider(Provider)\
(TlsIndex!=0xFFFFFFFF)\
? TlsSetValue (TlsIndex, Provider)\
: NULL

#define GetBlockingProvider()\
(TlsIndex!=0xFFFFFFFF)\
? TlsGetValue (TlsIndex)\
: NULL

PDASYNCWINDOW
GetAsyncWindow (
)
/*++
Routine Description:

Gets the pointer to async window object (creates and initializes
the object if not already created)
Arguments:
None
Return Value:
Pointer to async window object if successfull, NULL otherwise

--*/
{
// Quick check if object was already initialized (it can be NULL
// if we failed initialization in which case we do not
// want to retry)
if (gAsyncWindow!=UNINITIALIZED_WINDOW)
;
else {
EnterCriticalSection (&gInitCriticalSection);
// Recheck under protection of the critical section
if (gAsyncWindow == UNINITIALIZED_WINDOW) {
PDASYNCWINDOW asyncWindow;
// Attempt to create and initialize the object
// If creation or initialization fails, set global object
// pointer to NULL to prevent further initialization attepmts
asyncWindow = new DASYNCWINDOW;
if (asyncWindow!=NULL) {
if (asyncWindow->Initialize()==NO_ERROR) {
gAsyncWindow = asyncWindow;
}
else {
delete asyncWindow;
gAsyncWindow = NULL;
}
}
}
LeaveCriticalSection (&gInitCriticalSection);
}
return gAsyncWindow;
}


PDWORKERTHREAD
GetWorkerThread (
)
/*++
Routine Description:

Gets the pointer to worker thread object (creates and initializes
the object if not already created)
Arguments:
None
Return Value:
Pointer to worker thread object if successfull, NULL otherwise

--*/
{
// Quick check if object was already initialized (it can be NULL
// if we failed initialization in which case we do not
// want to retry)
if (gWorkerThread!=UNINITIALIZED_THREAD)
;
else {
EnterCriticalSection (&gInitCriticalSection);
// Recheck under protection of the critical section
if (gWorkerThread == UNINITIALIZED_THREAD) {
PDWORKERTHREAD workerThread;
// Attempt to create and initialize the object
// If creation or initialization fails, set global object
// pointer to NULL to prevent further initialization attepmts
workerThread = new DWORKERTHREAD;
if (workerThread!=NULL) {
if (workerThread->Initialize()==NO_ERROR) {
gWorkerThread = workerThread;
}
else {
delete workerThread;
gWorkerThread = NULL;
}
}
}
LeaveCriticalSection (&gInitCriticalSection);
}
return gWorkerThread;
}


SOCKET
WSPAPI
WSPAccept(
IN SOCKET s,
OUT struct sockaddr FAR *addr,
OUT INT FAR *addrlen,
IN LPCONDITIONPROC lpfnCondition,
IN DWORD dwCallbackData,
OUT INT FAR *lpErrno
)
/*++
Routine Description:

Conditionally accept a connection based on the return value of a condition
function, and optionally create and/or join a socket group.

Arguments:

s - A descriptor identiying a socket which is listening for
connections after a WSPListen().

addr - An optional pointer to a buffer which receives the address
of the connecting entity, as known to the service
provider. The exact format of the addr arguement is
determined by the address family established when the
socket was created.

addrlen - An optional pointer to an integer which contains the
length of the address addr.

lpfnCondition - The procedure instance address of an optional, WinSock 2
client supplied condition function which will make an
accept/reject decision based on the caller information
passed in as parameters, and optionally creaetd and/or
join a socket group by assigning an appropriate value to
the result parameter of this function.

dwCallbackData - Callback data to be passed back to the WinSock 2 client as
a condition function parameter. This parameter is not
interpreted by the service provider.

lpErrno - A pointer to the error code.

Return Value:

If no error occurs, WSPAccept() returns a value of type SOCKET which is a
descriptor for the accepted socket. Otherwise, a value of INVALID_SOCKET
is returned, and a specific error code is available in lpErrno.

--*/
{
INT ReturnValue;
PDPROVIDER Provider;
PDSOCKET Socket;
PDSOCKET NewSocket;
SOCKET ProviderSocket;
SOCKET NewProviderSocket;
DWORD ThisProviderCatalogEntryId;


// Debug/Trace stuff

if (PREAPINOTIFY(( DTCODE_WSPAccept,
&ReturnValue,
gLibraryName,
&s,
&addr,
&addrlen,
&lpfnCondition,
&dwCallbackData,
&lpErrno)) ) {
return(ReturnValue);
}

//
// Get our DSOCKET object
//
ReturnValue = gUpCallTable.lpWPUQuerySocketHandleContext(
s,
(DWORD*)&Socket,
lpErrno);

if (SOCKET_ERROR != ReturnValue){

Provider = Socket->GetDProvider();
ProviderSocket = Socket->GetProviderSocket();

SetBlockingProvider (Provider);
NewProviderSocket = Provider->WSPAccept(
ProviderSocket,
addr,
addrlen,
lpfnCondition,
dwCallbackData,
lpErrno);
SetBlockingProvider (NULL);

if (INVALID_SOCKET != NewProviderSocket){

//
// Create a new socket object and initialize it.
NewSocket = new DSOCKET;
if (NewSocket){
ThisProviderCatalogEntryId =
gProviderCatalog->GetLocalProvider()->GetProtocolInfo()->dwCatalogEntryId;

ReturnValue = gUpCallTable.lpWPUCreateSocketHandle(
ThisProviderCatalogEntryId,
(DWORD) NewSocket,
lpErrno);
DEBUGF( DBG_TRACE,
("Accept Returning Socket %X\n", ReturnValue));

if (INVALID_SOCKET != ReturnValue){
NewSocket->Initialize(
Provider,
NewProviderSocket,
Socket->GetCatalogEntryId(),
ReturnValue);

} //if
else{
delete NewSocket;
Provider->WSPCloseSocket (NewProviderSocket, lpErrno);
} //else
} //if
} //if
} //if

POSTAPINOTIFY(( DTCODE_WSPAccept,
&ReturnValue,
gLibraryName,
&s,
&addr,
&addrlen,
&lpfnCondition,
&dwCallbackData,
&lpErrno));

return(ReturnValue);
}



BOOL
PASCAL FAR
WSPAcceptEx (
IN SOCKET sListenSocket,
IN SOCKET sAcceptSocket,
IN PVOID lpOutputBuffer,
IN DWORD dwReceiveDataLength,
IN DWORD dwLocalAddressLength,
IN DWORD dwRemoteAddressLength,
OUT LPDWORD lpdwBytesReceived,
IN LPOVERLAPPED lpOverlapped
)
/*++
Routine Description:
Accepts a new connection, returns the local and remote address,
and receives the first block of data sent by the client application.

Arguments:
sListenSocket- A descriptor identifying a socket that has
already been called with the listen function.
A server application waits for attempts to
connect on this socket.
sAcceptSocket- A descriptor identifying a socket on which to
accept an incoming connection. This socket must
not be bound or connected.
lpOutputBuffer- A pointer to a buffer that receives the first
block of data sent on a new connection,
the local address of the server, and the remote
address of the client. The receive data is
written to the first part of the buffer starting
at offset zero, while the addresses are written
to the latter part of the buffer. This parameter
must be specified.
dwReceiveDataLength - The number of bytes in the buffer that will be
used for receiving data. If this parameter is
specified as zero, then no receive operation is
performed in conjunction with accepting the connection.
Instead, the AcceptEx function completes as soon
as a connection arrives without waiting for any
data.
dwLocalAddressLength - The number of bytes reserved for the local
address information. This must be at least
16 bytes more than the maximum address length
for the transport protocol in use.
dwRemoteAddressLength - The number of bytes reserved for the remote
address information. This must be at least
16 bytes more than the maximum address length
for the transport protocol in use.
lpdwBytesReceived- A pointer to a DWORD that receives the count
of bytes received. This is set only if the
operation completes synchronously.
If it returns ERROR_IO_PENDING and is completed
later, then this DWORD is never set and you must
obtain the number of bytes read from the
completion notification mechanism.
lpOverlapped- An OVERLAPPED structure that is used to process
the request. This parameter must be specified;
it cannot be NULL.

Return Value:

If no error occurs, the AcceptEx function completed successfully
and a value of TRUE is returned.
If the function fails, AcceptEx returns FALSE. The WSAGetLastError
function can then be called to return extended error information.
If WSAGetLastError returns ERROR_IO_PENDING, then the operation
was successfully initiated and is still in progress

--*/

{
PDSOCKETListenSocket, AcceptSocket;
INTErrno, ReturnValue;
PDPROVIDERProvider;
SOCKETProviderListenSocket, ProviderAcceptSocket;
//
// Get our DSOCKET objects
//
ReturnValue = gUpCallTable.lpWPUQuerySocketHandleContext(
sListenSocket,
(DWORD*)&ListenSocket,
&Errno);

if (SOCKET_ERROR != ReturnValue){
ReturnValue = gUpCallTable.lpWPUQuerySocketHandleContext(
sAcceptSocket,
(DWORD*)&AcceptSocket,
&Errno);

if (SOCKET_ERROR != ReturnValue){
if (lpOverlapped) {
if ((lpOverlapped->hEvent==NULL)
|| ResetEvent ((HANDLE)((DWORD)lpOverlapped->hEvent&0xFFFFFFFE))) {
PDWORKERTHREAD Thread = GetWorkerThread ();
if (Thread!=NULL) {
// Setup the user overlapped struct
lpOverlapped->Internal = WSS_OPERATION_IN_PROGRESS;
lpOverlapped->InternalHigh = 0;
ReturnValue = Thread->QueueOverlappedAcceptEx(
ListenSocket,
AcceptSocket,
lpOutputBuffer,
dwReceiveDataLength,
dwLocalAddressLength,
dwRemoteAddressLength,
lpOverlapped,
&Errno);
}
else {
ReturnValue = SOCKET_ERROR;
Errno = WSAENOBUFS;
}
}
else {
ReturnValue = SOCKET_ERROR;
Errno = WSA_INVALID_PARAMETER;
}
}
else {
Provider = ListenSocket->GetDProvider ();
ProviderListenSocket = ListenSocket->GetProviderSocket ();
ProviderAcceptSocket = AcceptSocket->GetProviderSocket ();

SetBlockingProvider (Provider);
ReturnValue = Provider->AcceptEx (
ProviderListenSocket,
ProviderAcceptSocket,
lpOutputBuffer,
dwReceiveDataLength,
dwLocalAddressLength,
dwRemoteAddressLength,
lpdwBytesReceived,
lpOverlapped,
&Errno);
SetBlockingProvider (NULL);
}
}
}
if (ReturnValue==NO_ERROR)
return TRUE;
else {
SetLastError (Errno);
return FALSE;
}
}




INT
WSPAPI
WSPAddressToString(
IN LPSOCKADDR lpsaAddress,
IN DWORD dwAddressLength,
IN LPWSAPROTOCOL_INFOW lpProtocolInfo,
OUT LPWSTR lpszAddressString,
IN OUT LPDWORD lpdwAddressStringLength,
OUT LPINT lpErrno )
/*++

Routine Description:

WSPAddressToString() converts a SOCKADDR structure into a human-readable
string representation of the address. This is intended to be used mainly
for display purposes. If the caller wishes the translation to be done by a
particular provider, it should supply the corresponding WSAPROTOCOL_INFO
struct in the lpProtocolInfo parameter.

Arguments:

lpsaAddress - points to a SOCKADDR structure to translate into a string.

dwAddressLength - the length of the Address SOCKADDR.

lpProtocolInfo - (optional) the WSAPROTOCOL_INFO struct for a particular
provider.

lpszAddressString - a buffer which receives the human-readable address
string.

lpdwAddressStringLength - on input, the length of the AddressString buffer.
On output, returns the length of the string
actually copied into the buffer.

Return Value:

The return value is 0 if the operation was successful. Otherwise the value
SOCKET_ERROR is returned
--*/
{
INT ReturnValue;
PDPROVIDER Provider;
PPROTO_CATALOG_ITEM BaseProviderCatalogEntry;

if (PREAPINOTIFY(( DTCODE_WSPAddressToString,
&ReturnValue,
gLibraryName,
&lpsaAddress,
&dwAddressLength,
&lpProtocolInfo,
&lpszAddressString,
&lpdwAddressStringLength,
&lpErrno)) ){
return(ReturnValue);
} //if

//
// Get the catlog entry for the next provider in the chain
//
ReturnValue = gProviderCatalog->FindNextProviderInChain(
lpProtocolInfo,
&Provider,
&BaseProviderCatalogEntry);

if (NO_ERROR == ReturnValue){

//
ReturnValue = Provider->WSPAddressToString(
lpsaAddress,
dwAddressLength,
BaseProviderCatalogEntry
? BaseProviderCatalogEntry->GetProtocolInfo()
: lpProtocolInfo,
lpszAddressString,
lpdwAddressStringLength,
lpErrno);
} //if

POSTAPINOTIFY(( DTCODE_WSPAddressToString,
&ReturnValue,
gLibraryName,
&lpsaAddress,
&dwAddressLength,
&lpProtocolInfo,
&lpszAddressString,
&lpdwAddressStringLength,
&lpErrno));

return(ReturnValue);
}





INT
WSPAPI
WSPAsyncSelect(
IN SOCKET s,
IN HWND hWnd,
IN unsigned int wMsg,
IN long lEvent,
OUT INT FAR *lpErrno
)
/*++
Routine Description:

Request Windows message-based event notification of network events for a
socket.

Arguments:

s - A descriptor identiying a socket for which event notification is
required.

hWnd - A handle identifying the window which should receive a message
when a network event occurs.

wMsg - The message to be sent when a network event occurs.

lEvent - bitmask which specifies a combination of network events in which
the WinSock client is interested.

lpErrno - A pointer to the error code.

Return Value:

The return value is 0 if the WinSock client's declaration of interest in
the netowrk event set was successful. Otherwise the value SOCKET_ERROR is
returned, and a specific error code is available in lpErrno.

--*/
{
INT ReturnValue;
PDSOCKET Socket;

if (PREAPINOTIFY(( DTCODE_WSPAsyncSelect,
&ReturnValue,
gLibraryName,
&s,
&hWnd,
&wMsg,
&lEvent,
&lpErrno)) ) {
return(ReturnValue);
}

//
// Get our DSOCKET object
//
ReturnValue = gUpCallTable.lpWPUQuerySocketHandleContext(
s,
(DWORD*)&Socket,
lpErrno);
if (SOCKET_ERROR != ReturnValue){
PDASYNCWINDOW AsyncWindow = GetAsyncWindow ();
if (AsyncWindow!=NULL) {
Socket->RegisterAsyncOperation(
hWnd,
wMsg,
lEvent);

*lpErrno = NO_ERROR;
// Register this socket with the worker thread.
*lpErrno = AsyncWindow->RegisterSocket(Socket);

if (NO_ERROR == *lpErrno){
ReturnValue = NO_ERROR;
} //if
else{
ReturnValue = SOCKET_ERROR;
} //else
}
else {
ReturnValue = SOCKET_ERROR;
*lpErrno = WSAENOBUFS;
}

} //if

POSTAPINOTIFY(( DTCODE_WSPAsyncSelect,
&ReturnValue,
gLibraryName,
&s,
&hWnd,
&wMsg,
&lEvent,
&lpErrno));

return(ReturnValue);
}



INT
WSPAPI
WSPBind(
IN SOCKET s,
IN const struct sockaddr FAR *name,
IN INT namelen,
OUT INT FAR *lpErrno
)
/*++
Routine Description:

Associate a local address (i.e. name) with a socket.

Arguments:

s - A descriptor identifying an unbound socket.

name - The address to assign to the socket. The sockaddr structure is
defined as follows:

struct sockaddr {
u_short sa_family;
char sa_data[14];
};

Except for the sa_family field,
sockaddr contents are epxressed
in network byte order.

namelen - The length of the name.

lpErrno - A pointer to the error code.

Return Value:

If no erro occurs, WSPBind() returns 0. Otherwise, it returns
SOCKET_ERROR, and a specific error code is available in lpErrno.

--*/
{
INT ReturnValue;
PDPROVIDER Provider;
PDSOCKET Socket;
SOCKET ProviderSocket;


if (PREAPINOTIFY(( DTCODE_WSPBind,
&ReturnValue,
gLibraryName,
&s,
&name,
&namelen,
&lpErrno)) ) {

return(ReturnValue);
}

//
// Get our DSOCKET object
//
ReturnValue = gUpCallTable.lpWPUQuerySocketHandleContext(
s,
(DWORD*)&Socket,
lpErrno);

if (SOCKET_ERROR != ReturnValue){
Provider = Socket->GetDProvider();
ProviderSocket = Socket->GetProviderSocket();

ReturnValue = Provider->WSPBind(
ProviderSocket,
name,
namelen,
lpErrno);


POSTAPINOTIFY(( DTCODE_WSPBind,
&ReturnValue,
gLibraryName,
&s,
&name,
&namelen,
&lpErrno));
}

return(ReturnValue);

}



INT
WSPAPI
WSPCancelBlockingCall(OUT INT FAR *lpErrno)
/*++
Routine Description:

Cancel a blocking call which is currently in progress.

Arguments:

lpErrno - A pointer to the error code.

Return Value:

The value returned by WSPCancelBlockingCall() is 0 if the operation was
successfully canceled. Otherwise the value SOCKET_ERROR is returned,
and a
specific error code is available in lpErrno.

--*/
{
INT ReturnValue;
PDPROVIDERProvider;

if (PREAPINOTIFY(( DTCODE_WSPCancelBlockingCall,
&ReturnValue,
gLibraryName,
&lpErrno)) ) {
return(ReturnValue);
}

Provider = (PDPROVIDER)TlsGetValue (TlsIndex);
if (Provider!=NULL) {
ReturnValue = Provider->WSPCancelBlockingCall(
lpErrno);
}
else {
ReturnValue = SOCKET_ERROR;
*lpErrno = WSAEINVAL;
}

POSTAPINOTIFY(( DTCODE_WSPCancelBlockingCall,
&ReturnValue,
gLibraryName,
&lpErrno));

return(ReturnValue);
}



INT
WSPAPI
WSPCleanup(
OUT INT FAR *lpErrno
)
/*++
Routine Description:

Terminate use of the WinSock service provider.

Arguments:

lpErrno - A pointer to the error code.

Return Value:

The return value is 0 if the operation has been successfully initiated.
Otherwise the value SOCKET_ERROR is returned,
and a specific error number
is available in lpErrno.

--*/

{
INT ReturnValue;

if (PREAPINOTIFY(( DTCODE_WSPCleanup,
&ReturnValue,
gLibraryName,
&lpErrno)) ) {
return(ReturnValue);
}

EnterCriticalSection(&gInitCriticalSection);
if (gStartupCount > 0){
gStartupCount--;
if (gStartupCount == 0){

DEBUGF( DBG_TRACE,
("Tearing down layered provider\n"));

if (gAsyncWindow!=UNINITIALIZED_WINDOW) {
if (gAsyncWindow!=NULL)
//Kill the worker thread
gAsyncWindow->Destroy ();
gAsyncWindow = UNINITIALIZED_WINDOW;
}

if (gWorkerThread!=UNINITIALIZED_THREAD) {
if (gWorkerThread!=NULL)
//Kill the worker thread
gWorkerThread->Destroy ();
gWorkerThread = UNINITIALIZED_THREAD;
}

// To let threads wake up and figure out that
// they being cleaned up
Sleep (100);

DSOCKET::DSocketClassCleanup ();

// Kill the ProviderCatalog
delete(gProviderCatalog);

//Kill the buffer manager
delete(gBufferManager);
DEBUGF( DBG_TRACE,
("Tearing down Complete\n"));

} //if
} //if
ReturnValue = NO_ERROR;
*lpErrno = NO_ERROR;

LeaveCriticalSection(&gInitCriticalSection);

POSTAPINOTIFY(( DTCODE_WSPCleanup,
&ReturnValue,
gLibraryName,
&lpErrno));

return(ReturnValue);

}



INT
WSPAPI
WSPCloseSocket(
IN SOCKET s,
OUT INT FAR *lpErrno
)
/*++
Routine Description:

Close a socket.

Arguments:

s - A descriptor identifying a socket.

lpErrno - A pointer to the error code.

Return Value:

If no erro occurs, WSPCloseSocket() returns 0. Otherwise, a value of
SOCKET_ERROR is returned, and a specific error code is available in
lpErrno.

--*/
{
INT ReturnValue;
PDSOCKET Socket;
PDPROVIDER Provider;
SOCKET ProviderSocket;


if (PREAPINOTIFY(( DTCODE_WSPCloseSocket,
&ReturnValue,
gLibraryName,
&s,
&lpErrno)) ) {
return(ReturnValue);
}

//
// Get our DSOCKET object
//
ReturnValue = gUpCallTable.lpWPUQuerySocketHandleContext(
s,
(DWORD*)&Socket,
lpErrno);
if (SOCKET_ERROR != ReturnValue){
Provider = Socket->GetDProvider();
ProviderSocket = Socket->GetProviderSocket();
DEBUGF( DBG_TRACE,
("Closing socket %X\n",s));

Socket->Remove ();

ReturnValue = Provider->WSPCloseSocket(
ProviderSocket,
lpErrno);

if (NO_ERROR==ReturnValue) {
gUpCallTable.lpWPUCloseSocketHandle(
Socket->GetSocketHandle(),
lpErrno);

delete(Socket);

ReturnValue = NO_ERROR;
}
} //if


POSTAPINOTIFY(( DTCODE_WSPCloseSocket,
&ReturnValue,
gLibraryName,
&s,
&lpErrno));

return(ReturnValue);

}



INT
WSPAPI
WSPConnect(
IN SOCKET s,
IN const struct sockaddr FAR *name,
IN INT namelen,
IN LPWSABUF lpCallerData,
IN LPWSABUF lpCalleeData,
IN LPQOS lpSQOS,
IN LPQOS lpGQOS,
OUT INT FAR *lpErrno
)
/*++
Routine Description:

Establish a connection to a peer,
exchange connect data,
and specify needed
quality of service based on the supplied flow spec.

Arguments:

s - A descriptor identifying an unconnected socket.

name - The name of the peer to which the socket is to be connected.

namelen - The length of the name.

lpCallerData - A pointer to the user data that is to be transferred to the
peer during connection established.

lpCalleeData - A pointer to a buffer into which may be copied any user data
received from the peer during connection establishment.

lpSQOS - A pointer to the flow specs for socket s, one for each
direction.

lpGQOS - A pointer to the flow specs for the socket group (if
applicable).

lpErrno - A pointer to the error code.

Return Value:

If no error occurs, WSPConnect() returns NO_ERROR. Otherwise, it
returns SOCKET_ERROR, and a specific erro rcode is available in lpErrno.

--*/
{
INT ReturnValue;
PDSOCKET Socket;
PDPROVIDER Provider;
SOCKET ProviderSocket;

if (PREAPINOTIFY(( DTCODE_WSPConnect,
&ReturnValue,
gLibraryName,
&s,
&name,
&namelen,

&lpCallerData, 
&lpCalleeData,
&lpSQOS,
&lpGQOS,
&lpErrno)) ) {
return(ReturnValue);
}

//
// Get our DSOCKET object
//
ReturnValue = gUpCallTable.lpWPUQuerySocketHandleContext(
s,
(DWORD*)&Socket,
lpErrno);
if (SOCKET_ERROR != ReturnValue){
Provider = Socket->GetDProvider();
ProviderSocket = Socket->GetProviderSocket();

SetBlockingProvider (Provider);
ReturnValue = Provider->WSPConnect(
ProviderSocket,
name,
namelen,
lpCallerData,
lpCalleeData,
lpSQOS,
lpGQOS,
lpErrno);
SetBlockingProvider (NULL);
}//if

POSTAPINOTIFY(( DTCODE_WSPConnect,
&ReturnValue,
gLibraryName,
&s,
&name,
&namelen,
&lpCallerData,
&lpCalleeData,
&lpSQOS,
&lpGQOS,
&lpErrno));

return(ReturnValue);

}



INT
WSPAPI
WSPDuplicateSocket(
IN SOCKET s,
IN DWORD dwProcessID,
OUT LPWSAPROTOCOL_INFOW lpProtocolInfo,
OUT INT FAR *lpErrno
)
/*++
Routine Description:

descriptor for a shared socket.


Arguments:

s - Specifies the local socket descriptor.

dwProcessID - Specifies the ID of the target process for which the
shared socket will be used.

lpProtocolInfo - A pointer to a buffer allocated by the client that is
large enough to contain a WSAPROTOCOL_INFOA struct. The
service provider copies the protocol info struct contents
to this buffer.

lpErrno - A pointer to the error code

Return Value:

If no error occurs, WPSDuplicateSocket() returns zero. Otherwise, the
value of SOCKET_ERROR is returned, and a specific error number is available
in lpErrno.

--*/
{
INTReturnValue=SOCKET_ERROR;
PDPROVIDERProvider;
PDSOCKETSocket;
SOCKETProviderSocket;
PPROTO_CATALOG_ITEMChainCatalogItem;
DWORDReserved;

if (PREAPINOTIFY(( DTCODE_WSPDuplicateSocket,
&ReturnValue,
gLibraryName,
&s,
&dwProcessID,
&lpProtocolInfo,
&lpErrno)) ) {
return(ReturnValue);
}


//
// Get our DSOCKET object
//
ReturnValue = gUpCallTable.lpWPUQuerySocketHandleContext(
s,
(DWORD*)&Socket,
lpErrno);
if (SOCKET_ERROR != ReturnValue){
// Get chain catalog entry
ReturnValue = gProviderCatalog->GetCatalogItemFromCatalogEntryId(
Socket->GetCatalogEntryId(),
&ChainCatalogItem);
if (NO_ERROR==ReturnValue) {
// Call next provider to duplicate its socket
Provider = Socket->GetDProvider();
ProviderSocket = Socket->GetProviderSocket();

ReturnValue = Provider->WSPDuplicateSocket(
ProviderSocket,
dwProcessID,
lpProtocolInfo,
lpErrno);
if (NO_ERROR==ReturnValue) {
// Replace returned protocol infor
// with chain protocol info and
// carefully restore provider reserved field.
Reserved = lpProtocolInfo->dwProviderReserved;
*lpProtocolInfo = *ChainCatalogItem->GetProtocolInfo ();
lpProtocolInfo->dwProviderReserved = Reserved;
}


} // if
} //if

POSTAPINOTIFY(( DTCODE_WSPDuplicateSocket,
&ReturnValue,
gLibraryName,
&s,
&dwProcessID,
&lpProtocolInfo,
&lpErrno));

return(ReturnValue);

}



INT
WSPAPI
WSPEnumNetworkEvents(
IN SOCKET s,
OUT WSAEVENT hEventObject,
OUT LPWSANETWORKEVENTS lpNetworkEvents,
OUT INT FAR *lpErrno
)
/*++
Routine Description:

Report occurrences of network events for the indicated socket.

Arguments:

s - A descriptor identifying the socket.

hEventObject - An optional handle identifying an associated event object
to be reset.

lpNetworkEvents - A pointer to a WSANETWORKEVENTS struct which is filled
with a record of occurred network events and any
associated error codes.

lpErrno - A pointer to the error code.

Return Value:

The return value is NO_ERROR if the operation was successful.
Otherwise the value SOCKET_ERROR is returned, and a specific error number
is available in lpErrno.

--*/
{
INT ReturnValue;
PDSOCKET Socket;
PDPROVIDER Provider;
SOCKET ProviderSocket;

if (PREAPINOTIFY(( DTCODE_WSPEnumNetworkEvents,
&ReturnValue,
gLibraryName,
&s,
&hEventObject,
&lpNetworkEvents,
&lpErrno)) ) {
return(ReturnValue);
}

//
// Get our DSOCKET object
//
ReturnValue = gUpCallTable.lpWPUQuerySocketHandleContext(
s,
(DWORD*)&Socket,
lpErrno);
if (SOCKET_ERROR != ReturnValue){
Provider = Socket->GetDProvider();
ProviderSocket = Socket->GetProviderSocket();

ReturnValue = Provider->WSPEnumNetworkEvents(
ProviderSocket,
hEventObject,
lpNetworkEvents,
lpErrno);
} //if

POSTAPINOTIFY(( DTCODE_WSPEnumNetworkEvents,
&ReturnValue,
gLibraryName,
&s,
&hEventObject,
&lpNetworkEvents,
&lpErrno));

return(ReturnValue);

}



INT
WSPAPI
WSPEventSelect(
IN SOCKET s,
IN OUT WSAEVENT hEventObject,
IN long lNetworkEvents,
OUT INT FAR *lpErrno
)
/*++
Routine Description:

Specify an event object to be associated with the supplied set of network
events.

Arguments:

s - A descriptor identifying the socket.

hEventObject - A handle identifying the event object to be associated
with the supplied set of network events.

lNetworkEvents - A bitmask which specifies the combination of network
events in which the WinSock client has interest.

lpErrno - A pointer to the error code.

Return Value:

The return value is 0 if the WinSock client's specification of the network
events and the associated event object was successful. Otherwise the value
SOCKET_ERROR is returned, and a specific error number is available in
lpErrno

--*/
{
INT ReturnValue;
PDSOCKET Socket;
PDPROVIDER Provider;
SOCKET ProviderSocket;


if (PREAPINOTIFY(( DTCODE_WSPEventSelect,
&ReturnValue,
gLibraryName,
&s,
&hEventObject,
&lNetworkEvents,
&lpErrno)) ) {
return(ReturnValue);
}

//
// Get our DSOCKET object
//
ReturnValue = gUpCallTable.lpWPUQuerySocketHandleContext(
s,
(DWORD*)&Socket,
lpErrno);
if (SOCKET_ERROR != ReturnValue){
Provider = Socket->GetDProvider();
ProviderSocket = Socket->GetProviderSocket();

ReturnValue = Provider->WSPEventSelect(
ProviderSocket,
hEventObject,
lNetworkEvents,
lpErrno);
} //if

POSTAPINOTIFY(( DTCODE_WSPEventSelect,
&ReturnValue,
gLibraryName,
&s,
&hEventObject,
&lNetworkEvents,
&lpErrno));

return(ReturnValue);

}



INT
WSPAPI
WSPGetOverlappedResult(
IN SOCKET s,
IN LPWSAOVERLAPPED lpOverlapped,
IN LPDWORD lpcbTransfer,
IN BOOL fWait,
OUT LPDWORD lpdwFlags,
OUT INT FAR *lpErrno
)
/*++
Routine Description:

Returns the results of an overlapped operation on the specified socket.

Arguments:

s - Identifies the socket. This is the same socket that was
specified when the overlapped operation was started by a
call to WSPRecv(), WSPRecvFrom(), WSPSend(), WSPSendTo(), or
WSPIoctl().

lpOverlapped - Points to a WSAOVERLAPPED structure that was specified
when the overlapped operation was started.

lpcbTransfer - Points to a 32-bit variable that receives the number of
bytes that were actually transferred by a send or receive
operation, or by WSPIoctl().

fWait - Specifies whether the function should wait for the pending
overlapped operation to complete. If TRUE, the function
does not return until the operation has been completed. If
FALSE and the operation is still pending, the function
returns FALSE and lperrno is WSA_IO_INCOMPLETE.

lpdwFlags - Points to a 32-bit variable that will receive one or more
flags that supplement the completion status. If the
overlapped operation was initiated via WSPRecv() or
WSPRecvFrom(), this parameter will contain the results value
for lpFlags parameter.

lpErrno - A pointer to the error code.

Return Value:

If WSPGetOverlappedResult() succeeds,the return value is TRUE. This means
that the overlapped operation has completed successfully and that the value
pointed to by lpcbTransfer has been updated. If WSPGetOverlappedResult()
returns FALSE, this means that either the overlapped operation has not
completed or the overlapped operation completed but with errors, or that
completion status could not be determined due to errors in one or more
parameters to WSPGetOverlappedResult(). On failure, the value pointed to
by lpcbTransfer will not be updated. lpErrno indicates the cause of the
failure (either of WSPGetOverlappedResult() or of the associated overlapped
operation).

--*/
{
INT ReturnValue;

if (PREAPINOTIFY(( DTCODE_WSPGetOverlappedResult,
&ReturnValue,
gLibraryName,
&s,
&lpOverlapped,
&lpcbTransfer,
&fWait,
&lpdwFlags,
&lpErrno)) ) {
return(ReturnValue);
}

if (lpOverlapped->Internal!=WSS_OPERATION_IN_PROGRESS) {
*lpcbTransfer = lpOverlapped->InternalHigh;
*lpdwFlags = lpOverlapped->Offset;
*lpErrno = lpOverlapped->OffsetHigh;
ReturnValue = lpOverlapped->OffsetHigh==0;
}
else if (fWait) {
ReturnValue = WaitForSingleObject (lpOverlapped->hEvent, INFINITE);
if ((ReturnValue==WAIT_OBJECT_0)
&& (lpOverlapped->Internal!=WSS_OPERATION_IN_PROGRESS)) {
*lpcbTransfer = lpOverlapped->InternalHigh;
*lpdwFlags = lpOverlapped->Offset;
*lpErrno = lpOverlapped->OffsetHigh;
ReturnValue = lpOverlapped->OffsetHigh==0;
}
else {
ReturnValue = FALSE;
*lpErrno = WSASYSCALLFAILURE;
}
}
else {
*lpErrno = WSA_IO_PENDING;
ReturnValue = FALSE;
}

POSTAPINOTIFY(( DTCODE_WSPGetOverlappedResult,
&ReturnValue,
gLibraryName,
&s,
&lpOverlapped,
&lpcbTransfer,
&fWait,
&lpdwFlags,
&lpErrno));

return(ReturnValue);
}



INT
WSPAPI
WSPGetPeerName(
IN SOCKET s,
OUT struct sockaddr FAR *name,
OUT INT FAR *namelen,
OUT INT FAR *lpErrno
)
/*++
Routine Description:

Get the address of the peer to which a socket is connected.

Arguments:

s - A descriptor identifying a connected socket.

name - A pointer to the structure which is to receive the name of the
peer.

namelen - A pointer to an integer which, on input, indicates the size of
the structure pointed to by name, and on output indicates the
size of the returned name.

lpErrno - A pointer to the error code.

Return Value:

If no error occurs, WSPGetPeerName() returns NO_ERROR. Otherwise, a
value of SOCKET_ERROR is returned, and a specific error code is available
in lpErrno

--*/
{
INT ReturnValue;
PDSOCKET Socket;
PDPROVIDER Provider;
SOCKET ProviderSocket;


if (PREAPINOTIFY(( DTCODE_WSPGetPeerName,
&ReturnValue,
gLibraryName,
&s,
&name,
&namelen,
&lpErrno)) ) {
return(ReturnValue);
}

//
// Get our DSOCKET object
//
ReturnValue = gUpCallTable.lpWPUQuerySocketHandleContext(
s,
(DWORD*)&Socket,
lpErrno);
if (SOCKET_ERROR != ReturnValue){
Provider = Socket->GetDProvider();
ProviderSocket = Socket->GetProviderSocket();

ReturnValue = Provider->WSPGetPeerName(
ProviderSocket,
name,
namelen,
lpErrno);

} //if

POSTAPINOTIFY(( DTCODE_WSPGetPeerName,
&ReturnValue,
gLibraryName,
&s,
&name,
&namelen,
&lpErrno));

return(ReturnValue);
}



INT
WSPAPI
WSPGetQOSByName(
IN SOCKET s,
IN LPWSABUF lpQOSName,
IN LPQOS lpQOS,
OUT INT FAR *lpErrno
)
/*++
Routine Description:

Initializes a QOS structure based on a named template.

Arguments:

s - A descriptor identifying a socket.

lpQOSName - Specifies the QOS template name.

lpQOS - A pointer to the QOS structure to be filled.

lpErrno - A pointer to the error code.

Return Value:

If the function succeeds, the return value is TRUE. If the function fails,
the return value is FALSE, and a specific error code is available in
lpErrno.

--*/
{
INT ReturnValue;
PDSOCKET Socket;
PDPROVIDER Provider;
SOCKET ProviderSocket;


if (PREAPINOTIFY(( DTCODE_WSPGetQOSByName,
&ReturnValue,
gLibraryName,
&s,
&lpQOSName,
&lpQOS,
&lpErrno)) ) {
return(ReturnValue);
}

//
// Get our DSOCKET object
//
ReturnValue = gUpCallTable.lpWPUQuerySocketHandleContext(
s,
(DWORD*)&Socket,
lpErrno);
if (SOCKET_ERROR != ReturnValue){
Provider = Socket->GetDProvider();
ProviderSocket = Socket->GetProviderSocket();

ReturnValue = Provider->WSPGetQOSByName(
ProviderSocket,
lpQOSName,
lpQOS,
lpErrno);
} //if

POSTAPINOTIFY(( DTCODE_WSPGetQOSByName,
&ReturnValue,
gLibraryName,
&s,
&lpQOSName,
&lpQOS,
&lpErrno));

return(ReturnValue);
}



INT
WSPAPI
WSPGetSockName(
IN SOCKET s,
OUT struct sockaddr FAR *name,
OUT INT FAR *namelen,
OUT INT FAR *lpErrno
)
/*++
Routine Description:

Get the local name for a socket.

Arguments:

s - A descriptor identifying a bound socket.

name - A pointer to a structure used to supply the address (name) of the
socket.

namelen - A pointer to an integer which, on input, indicates the size of
the structure pointed to by name, and on output indicates the
size of the returned name

lpErrno - A Pointer to the error code.

Return Value:

If no error occurs, WSPGetSockName() returns NO_ERROR. Otherwise, a
value of SOCKET_ERROR is returned, and a specific error code is available
in lpErrno.

--*/
{
INT ReturnValue;
PDSOCKET Socket;
PDPROVIDER Provider;
SOCKET ProviderSocket;


if (PREAPINOTIFY(( DTCODE_WSPGetSockName,
&ReturnValue,
gLibraryName,
&s,
&name,
&namelen,
&lpErrno)) ) {
return(ReturnValue);
}

//
// Get our DSOCKET object
//
ReturnValue = gUpCallTable.lpWPUQuerySocketHandleContext(
s,
(DWORD*)&Socket,
lpErrno);
if (SOCKET_ERROR != ReturnValue){
Provider = Socket->GetDProvider();
ProviderSocket = Socket->GetProviderSocket();

ReturnValue = Provider->WSPGetSockName(
ProviderSocket,
name,
namelen,
lpErrno);
} //if

POSTAPINOTIFY(( DTCODE_WSPGetSockName,
&ReturnValue,
gLibraryName,
&s,
&name,
&namelen,
&lpErrno));

return(ReturnValue);
}



INT
WSPAPI
WSPGetSockOpt(
IN SOCKET s,
IN INT level,
IN INT optname,
OUT char FAR *optval,
OUT INT FAR *optlen,
OUT INT FAR *lpErrno
)
/*++
Routine Description:

Retrieve a socket option.

Arguments:

s - A descriptor identifying a socket.

level - The level at which the option is defined; the supported levels
include SOL_SOCKET (See annex for more protocol-specific levels.)

optname - The socket option for which the value is to be retrieved.

optval - A pointer to the buffer in which the value for the requested
option is to be returned.

optlen - A pointer to the size of the optval buffer.

lpErrno - A pointer to the error code.

Return Value:

If no error occurs, WSPGetSockOpt() returns 0. Otherwise, a value of
SOCKET_ERROR is returned, and a specific error code is available in
lpErrno.

--*/
{
INT ReturnValue;
PDSOCKET Socket;
PDPROVIDER Provider;
SOCKET ProviderSocket;


if (PREAPINOTIFY(( DTCODE_WSPGetSockOpt,
&ReturnValue,
gLibraryName,
&s,
&level,
&optname,
&optval,
&optlen,
&lpErrno)) ) {
return(ReturnValue);
}

//
// Get our DSOCKET object
//
ReturnValue = gUpCallTable.lpWPUQuerySocketHandleContext(
s,
(DWORD*)&Socket,
lpErrno);
if (SOCKET_ERROR != ReturnValue){
Provider = Socket->GetDProvider();
ProviderSocket = Socket->GetProviderSocket();

ReturnValue = Provider->WSPGetSockOpt(
ProviderSocket,
level,
optname,
optval,
optlen,
lpErrno);
} //if

POSTAPINOTIFY(( DTCODE_WSPGetSockOpt,
&ReturnValue,
gLibraryName,
&s,
&level,
&optname,
&optval,
&optlen,
&lpErrno));

return(ReturnValue);
}


INT
WSPAPI
WSPIoctl(
IN SOCKET s,
IN DWORD dwIoControlCode,
IN LPVOID lpvInBuffer,
IN DWORD cbInBuffer,
IN LPVOID lpvOutBuffer,
IN DWORD cbOutBuffer,
IN LPDWORD lpcbBytesReturned,
IN LPWSAOVERLAPPED lpOverlapped,
IN LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
IN LPWSATHREADID lpThreadId,
OUT INT FAR *lpErrno
)
/*++
Routine Description:

Control the mode of a socket.

Arguments:

s - Handle to a socket

dwIoControlCode - Control code of operation to perform

lpvInBuffer - Address of input buffer

cbInBuffer - Size of input buffer

lpvOutBuffer - Address of output buffer

cbOutBuffer - Size of output buffer

lpcbBytesReturned - A pointer to the size of output buffer's contents.

lpOverlapped - Address of WSAOVERLAPPED structure

lpCompletionRoutine - A pointer to the completion routine called when the
operation has been completed.

lpThreadId - A pointer to a thread ID structure to be used by the
provider

lpErrno - A pointer to the error code.

Return Value:

If no error occurs and the operation has completed immediately, WSPIoctl()
returns 0. Note that in this case the completion routine, if specified,
will have already been queued. Otherwise, a value of SOCKET_ERROR is
returned, and a specific error code is available in lpErrno. The error
code WSA_IO_PENDING indicates that an overlapped operation has been
successfully initiated and that conpletion will be indicated at a later
time. Any other error code indicates that no overlapped operation was
initiated and no completion indication will occur.

--*/
{
INT ReturnValue;
PDSOCKET Socket;
PDPROVIDER Provider;
SOCKET ProviderSocket;


if (PREAPINOTIFY(( DTCODE_WSPIoctl,
&ReturnValue,
gLibraryName,
&s,
&dwIoControlCode,
&lpvInBuffer,
&cbInBuffer,
&lpvOutBuffer,
&cbOutBuffer,
&lpcbBytesReturned,
&lpOverlapped,
&lpCompletionRoutine,
&lpThreadId,
&lpErrno)) ) {
return(ReturnValue);
}


//
// Get our DSOCKET object
//
ReturnValue = gUpCallTable.lpWPUQuerySocketHandleContext(
s,
(DWORD*)&Socket,
lpErrno);
if (SOCKET_ERROR != ReturnValue){
if (lpOverlapped){
if (lpCompletionRoutine
|| (lpOverlapped->hEvent==NULL)
|| ResetEvent ((HANDLE)((DWORD)lpOverlapped->hEvent&0xFFFFFFFE))) {
PDWORKERTHREAD Thread = GetWorkerThread ();
if (Thread!=NULL) {
// Setup the user overlapped struct
lpOverlapped->Internal = WSS_OPERATION_IN_PROGRESS;
lpOverlapped->InternalHigh = 0;
ReturnValue = Thread->QueueOverlappedIoctl(
Socket,
dwIoControlCode,
lpvInBuffer,
cbInBuffer,
lpvOutBuffer,
cbOutBuffer,
lpcbBytesReturned,
lpOverlapped,
lpCompletionRoutine,
lpThreadId,
lpErrno);
}
else {
ReturnValue = SOCKET_ERROR;
*lpErrno = WSAENOBUFS;
}
}
else {
ReturnValue = SOCKET_ERROR;
*lpErrno = WSA_INVALID_PARAMETER;
}
}
else {
Provider = Socket->GetDProvider ();
ProviderSocket = Socket->GetProviderSocket ();

ReturnValue = Provider->WSPIoctl(
ProviderSocket,
dwIoControlCode,
lpvInBuffer,
cbInBuffer,
lpvOutBuffer,
cbOutBuffer,
lpcbBytesReturned,
lpOverlapped,
lpCompletionRoutine,
lpThreadId,
lpErrno);
if ((dwIoControlCode==SIO_GET_EXTENSION_FUNCTION_POINTER)
&& (NO_ERROR==ReturnValue)) {
ReturnValue = Provider->InterceptExtensions (
lpvInBuffer,
lpvOutBuffer,
lpErrno);
}
}
} //if

POSTAPINOTIFY(( DTCODE_WSPIoctl,
&ReturnValue,
gLibraryName,
&s,
&dwIoControlCode,
&lpvInBuffer,
&cbInBuffer,
&lpvOutBuffer,
&cbOutBuffer,
&lpcbBytesReturned,
&lpOverlapped,
&lpCompletionRoutine,
&lpThreadId,
&lpErrno));

return(ReturnValue);
}


SOCKET
WSPAPI
WSPJoinLeaf(
IN SOCKET s,
IN const struct sockaddr FAR *name,
IN INT namelen,
IN LPWSABUF lpCallerData,
IN LPWSABUF lpCalleeData,
IN LPQOS lpSQOS,
IN LPQOS lpGQOS,
IN DWORD dwFlags,
OUT INT FAR *lpErrno
)
/*++
Routine Description:

Join a leaf node into a multipoint session, exchange connect data, and
specify needed quality of service based on the supplied flow specs.

Arguments:

s - A descriptor identifying a multipoint socket.

name - The name of the peer to which the socket is to be joined.

namelen - The length of the name.

lpCallerData - A pointer to the user data that is to be transferred to the
peer during multipoint session establishment.

lpCalleeData - A pointer to the user data that is to be transferred back
from the peer during multipoint session establishment.

lpSQOS - A pointer to the flow specs for socket s, one for each
direction.

lpGQOS - A pointer to the flow specs for the socket group (if
applicable).

dwFlags - Flags to indicate that the socket is acting as a sender,
receiver, or both.

lpErrno - A pointer to the error code.

Return Value:

If no error occurs, WSPJoinLeaf() returns a value of type SOCKET which is a
descriptor for the newly created multipoint socket. Otherwise,a value of
INVALID_SOCKET is returned, and a specific error code is available in
lpErrno.

--*/
{
INT ReturnValue;
PDSOCKET Socket, NewSocket;
PDPROVIDER Provider;
SOCKET ProviderSocket, NewProviderSocket;
DWORD ThisProviderCatalogEntryId;


if (PREAPINOTIFY(( DTCODE_WSPJoinLeaf,
&ReturnValue,
gLibraryName,
&s,
&name,
&namelen,
&lpCallerData,
&lpCalleeData,
&lpSQOS,
&lpGQOS,
&dwFlags,
&lpErrno)) ) {
return(ReturnValue);
}

//
// Get our DSOCKET object
//
ReturnValue = gUpCallTable.lpWPUQuerySocketHandleContext(
s,
(DWORD*)&Socket,
lpErrno);
if (SOCKET_ERROR != ReturnValue){
Provider = Socket->GetDProvider();
ProviderSocket = Socket->GetProviderSocket();

NewProviderSocket = Provider->WSPJoinLeaf(
ProviderSocket,
name,
namelen,
lpCallerData,
lpCalleeData,
lpSQOS,
lpGQOS,
dwFlags,

lpErrno); 
if (NewProviderSocket!=INVALID_SOCKET) {
if (NewProviderSocket!=ProviderSocket) {
//
// Create a new socket object and initialize it.
NewSocket = new DSOCKET;
if (NewSocket){
ThisProviderCatalogEntryId =
gProviderCatalog->GetLocalProvider()->GetProtocolInfo()->dwCatalogEntryId;

ReturnValue = gUpCallTable.lpWPUCreateSocketHandle(
ThisProviderCatalogEntryId,
(DWORD) NewSocket,
lpErrno);
DEBUGF( DBG_TRACE,
("JoinLeaf Returning Socket %X\n", ReturnValue));

if (INVALID_SOCKET != ReturnValue){
NewSocket->Initialize(
Provider,
NewProviderSocket,
Socket->GetCatalogEntryId(),
ReturnValue);

} //if
else{
delete NewSocket;
Provider->WSPCloseSocket (NewProviderSocket, lpErrno);
} //else
}
}
else
ReturnValue = s;
}
else
ReturnValue = INVALID_SOCKET;
} //if

POSTAPINOTIFY(( DTCODE_WSPJoinLeaf,
&ReturnValue,
gLibraryName,
&s,
&name,
&namelen,
&lpCallerData,
&lpCalleeData,
&lpSQOS,
&lpGQOS,
&dwFlags,
&lpErrno));

return(ReturnValue);

}



INT
WSPAPI
WSPListen(
IN SOCKET s,
IN INT backlog,
OUT INT FAR *lpErrno
)
/*++
Routine Description:

Establish a socket to listen for incoming connections.

Arguments:

s - A descriptor identifying a bound,
unconnected socket.

backlog - The maximum length to which the queue of pending connections may
grow. If this value is SOMAXCONN,
then the service provider
should set the backlog to a maximum "reasonable" value.

lpErrno - A pointer to the error code.

Return Value:

If no error occurs, WSPListen() returns 0. Otherwise, a value of
SOCKET_ERROR is returned, and a specific error code is available in
lpErrno.

--*/
{
INT ReturnValue;
PDSOCKET Socket;
PDPROVIDER Provider;
SOCKET ProviderSocket;


if (PREAPINOTIFY(( DTCODE_WSPListen,
&ReturnValue,
gLibraryName,
&s,
&backlog,
&lpErrno)) ) {
return(ReturnValue);
}

//
// Get our DSOCKET object
//
ReturnValue = gUpCallTable.lpWPUQuerySocketHandleContext(
s,
(DWORD*)&Socket,
lpErrno);
if (SOCKET_ERROR != ReturnValue){
Provider = Socket->GetDProvider();
ProviderSocket = Socket->GetProviderSocket();

ReturnValue = Provider->WSPListen(
ProviderSocket,
backlog,
lpErrno);
} //if

POSTAPINOTIFY(( DTCODE_WSPListen,
&ReturnValue,
gLibraryName,
&s,
&backlog,
&lpErrno));

return(ReturnValue);
}



INT
WSPAPI
WSPRecv(
IN SOCKET s,
IN LPWSABUF lpBuffers,
IN DWORD dwBufferCount,
IN LPDWORD lpNumberOfBytesRecvd,
IN OUT LPDWORD lpFlags,
IN LPWSAOVERLAPPED lpOverlapped,
IN LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
IN LPWSATHREADID lpThreadId,
OUT INT FAR *lpErrno
)
/*++
Routine Description:

Receive data on a socket.

Arguments:

s - A descriptor identifying a connected socket.

lpBuffers - A pointer to an array of WSABUF structures. Each
WSABUF structure contains a pointer to a buffer and
the length of the buffer.

dwBufferCount - The number of WSABUF structures in the lpBuffers
array.

lpNumberOfBytesRecvd - A pointer to the number of bytes received by this
call.

lpFlags - A pointer to flags.

lpOverlapped - A pointer to a WSAOVERLAPPED structure.

lpCompletionRoutine - A pointer to the completion routine called when the
receive operation has been completed.

lpThreadId - A pointer to a thread ID structure to be used by the
provider in a subsequent call to WPUQueueApc().

lpErrno - A pointer to the error code.

Return Value:

If no error occurs and the receive operation has completed immediately,
WSPRecv() returns the number of bytes received. If the connection has been
closed, it returns 0. Note that in this case the completion routine, if
specified, will have already been queued. Otherwise, a value of
SOCKET_ERROR is returned, and a specific error code is available in
lpErrno. The error code WSA_IO_PENDING indicates that the overlapped an
operation has been successfully initiated and that completion will be
indicated at a later time. Any other error code indicates that no
overlapped operations was initiated and no completion indication will
occur.
--*/
{
INT ReturnValue;
PDSOCKET Socket;
PDPROVIDER Provider;
SOCKET ProviderSocket;
LPWSABUF InternalBuffers;
DWORD InternalBufferCount;


if (PREAPINOTIFY(( DTCODE_WSPRecv,
&ReturnValue,
gLibraryName,
&s,
&lpBuffers,
&dwBufferCount,
&lpNumberOfBytesRecvd,
&lpFlags,
&lpOverlapped,
&lpCompletionRoutine,
&lpThreadId,
&lpErrno)) ) {
return(ReturnValue);
}

//
// Get our DSOCKET object
//
ReturnValue = gUpCallTable.lpWPUQuerySocketHandleContext(
s,
(DWORD*)&Socket,
lpErrno);
if (SOCKET_ERROR != ReturnValue){

// Get Internal buffers to send down to the lower provider.
ReturnValue = gBufferManager->AllocBuffer(
lpBuffers,
dwBufferCount,
&InternalBuffers,
&InternalBufferCount);

if (NO_ERROR == ReturnValue){
//Is this a overlapped operation.
if (lpOverlapped){
if (lpCompletionRoutine
|| (lpOverlapped->hEvent==NULL)
|| ResetEvent ((HANDLE)((DWORD)lpOverlapped->hEvent&0xFFFFFFFE))) {
PDWORKERTHREAD Thread = GetWorkerThread ();
if (Thread!=NULL) {
// Setup the user overlapped struct
lpOverlapped->Internal = WSS_OPERATION_IN_PROGRESS;
lpOverlapped->InternalHigh = 0;
ReturnValue = Thread->QueueOverlappedRecv(
Socket,
lpBuffers,
dwBufferCount,
lpNumberOfBytesRecvd,
lpFlags,
lpOverlapped,
lpCompletionRoutine,
lpThreadId,
InternalBuffers,
InternalBufferCount,
lpErrno);
}
else {
ReturnValue = SOCKET_ERROR;
*lpErrno = WSAENOBUFS;
}
}
else {
ReturnValue = SOCKET_ERROR;
*lpErrno = WSA_INVALID_PARAMETER;
}
} //if
else{
Provider = Socket->GetDProvider();
ProviderSocket = Socket->GetProviderSocket();

SetBlockingProvider (Provider);
ReturnValue = Provider->WSPRecv(
ProviderSocket,
InternalBuffers,
InternalBufferCount,
lpNumberOfBytesRecvd,
lpFlags,
lpOverlapped,
lpCompletionRoutine,
lpThreadId,
lpErrno);
SetBlockingProvider (NULL);
if (ReturnValue==NO_ERROR) {
gBufferManager->CopyBuffer (InternalBuffers,
InternalBufferCount,
0,
*lpNumberOfBytesRecvd,
lpBuffers,
dwBufferCount,
0);
}
gBufferManager->FreeBuffer (InternalBuffers, InternalBufferCount);
} //else
} //if
} //if

POSTAPINOTIFY(( DTCODE_WSPRecv,
&ReturnValue,
gLibraryName,
&s,
&lpBuffers,
&dwBufferCount,
&lpNumberOfBytesRecvd,
&lpFlags,
&lpOverlapped,
&lpCompletionRoutine,
&lpThreadId,
&lpErrno));

return(ReturnValue);
}



INT
WSPAPI
WSPRecvDisconnect(
IN SOCKET s,
IN LPWSABUF lpInboundDisconnectData,
OUT INT FAR *lpErrno
)
/*++
Routine Description:

Terminate reception on a socket, and retrieve the disconnect data if the
socket is connection-oriented.

Arguments:

s - A descriptor identifying a socket.

lpInboundDisconnectData - A pointer to a buffer into which disconnect data
is to be copied.

lpErrno - A pointer to the error code.

Return Value:

If no error occurs, WSPRecvDisconnect() returns NO_ERROR. Otherwise,
a value of SOCKET_ERROR is returned, and a specific error code is available
in lpErrno.

--*/
{
INT ReturnValue;
PDSOCKET Socket;
PDPROVIDER Provider;
SOCKET ProviderSocket;


if (PREAPINOTIFY(( DTCODE_WSPRecvDisconnect,
&ReturnValue,
gLibraryName,
&s,
&lpInboundDisconnectData,
&lpErrno)) ) {
return(ReturnValue);
}

//
// Get our DSOCKET object
//
ReturnValue = gUpCallTable.lpWPUQuerySocketHandleContext(
s,
(DWORD*)&Socket,
lpErrno);

if (SOCKET_ERROR != ReturnValue){
Provider = Socket->GetDProvider();
ProviderSocket = Socket->GetProviderSocket();

ReturnValue = Provider->WSPRecvDisconnect(
ProviderSocket,
lpInboundDisconnectData,
lpErrno);
} //if

POSTAPINOTIFY(( DTCODE_WSPRecvDisconnect,
&ReturnValue,
gLibraryName,
&s,
&lpInboundDisconnectData,
&lpErrno));

return(ReturnValue);

}



INT
WSPAPI
WSPRecvFrom(
IN SOCKET s,
IN LPWSABUF lpBuffers,
IN DWORD dwBufferCount,
IN LPDWORD lpNumberOfBytesRecvd,
IN OUT LPDWORD lpFlags,
OUT struct sockaddr FAR * lpFrom,
IN LPINT lpFromlen,
IN LPWSAOVERLAPPED lpOverlapped,
IN LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
IN LPWSATHREADID lpThreadId,
OUT INT FAR *lpErrno
)
/*++
Routine Description:

Receive a datagram and store the source address.

Arguments:

s - A descriptor identifying a socket.

lpBuffers - A pointer to an array of WSABUF structures. Each
WSABUF structure contains a pointer to a buffer and
the length of the buffer.

dwBufferCount - The number of WSABUF structures in the lpBuffers
array.

lpNumberOfBytesRecvd - A pointer to the number of bytes received by this
call.

lpFlags - A pointer to flags.

lpFrom - An optional pointer to a buffer which will hold the
source address upon the completion of the overlapped
operation.

lpFromlen - A pointer to the size of the from buffer, required
only if lpFrom is specified.

lpOverlapped - A pointer to a WSAOVERLAPPED structure.

CompletionRoutine - A pointer to the completion routine called when the
receive operation has been completed.

lpThreadId - A pointer to a thread ID structure to be used by the
provider in a subsequent call to WPUQueueApc().

lpErrno - A pointer to the error code.

Return Value:

If no error occurs and the receive operation has completed immediately,
WSPRecvFrom() returns the number of bytes received. If the connection has
been closed, it returns 0. Note that in this case the completion routine,
if specified will have already been queued. Otherwise, a value of
SOCKET_ERROR is returned, and a specific error code is available in
lpErrno. The error code WSA_IO_PENDING indicates that the overlapped
operation has been successfully initiated and that completion will be
indicated at a later time. Any other error code indicates that no
overlapped operations was initiated and no completion indication will
occur.

--*/
{
INT ReturnValue;
PDSOCKET Socket;
PDPROVIDER Provider;
SOCKET ProviderSocket;
LPWSABUF InternalBuffers;
DWORD InternalBufferCount;


if (PREAPINOTIFY(( DTCODE_WSPRecvFrom,
&ReturnValue,
gLibraryName,
&s,
&lpBuffers,
&dwBufferCount,
&lpNumberOfBytesRecvd,
&lpFlags,
&lpFrom,
&lpFromlen,
&lpOverlapped,
&lpCompletionRoutine,
&lpThreadId,
&lpErrno)) ) {
return(ReturnValue);
}

//
// Get our DSOCKET object
//
ReturnValue = gUpCallTable.lpWPUQuerySocketHandleContext(
s,
(DWORD*)&Socket,
lpErrno);
if (SOCKET_ERROR != ReturnValue){

// Get Internal buffers to send down to the lower provider.
ReturnValue = gBufferManager->AllocBuffer(
lpBuffers,
dwBufferCount,
&InternalBuffers,
&InternalBufferCount);

if (NO_ERROR == ReturnValue){
//Is this a overlapped operation.
if (lpOverlapped){
if (lpCompletionRoutine
|| (lpOverlapped->hEvent==NULL)
|| ResetEvent ((HANDLE)((DWORD)lpOverlapped->hEvent&0xFFFFFFFE))) {
PDWORKERTHREAD Thread = GetWorkerThread ();
if (Thread!=NULL) {
// Setup the user overlapped struct
lpOverlapped->Internal = WSS_OPERATION_IN_PROGRESS;
lpOverlapped->InternalHigh = 0;
ReturnValue = Thread->QueueOverlappedRecvFrom(
Socket,
InternalBuffers,
InternalBufferCount,
lpNumberOfBytesRecvd,
lpFlags,
lpFrom,
lpFromlen,
lpOverlapped,
lpCompletionRoutine,
lpThreadId,
InternalBuffers,
InternalBufferCount,
lpErrno);
}
else {
ReturnValue = SOCKET_ERROR;
*lpErrno = WSAENOBUFS;
}
}
else {
ReturnValue = SOCKET_ERROR;
*lpErrno = WSA_INVALID_PARAMETER;
}
} //if
else{
Provider = Socket->GetDProvider();
ProviderSocket = Socket->GetProviderSocket();

SetBlockingProvider (Provider);
ReturnValue = Provider->WSPRecvFrom(
ProviderSocket,
lpBuffers,
dwBufferCount,
lpNumberOfBytesRecvd,
lpFlags,
lpFrom,
lpFromlen,
lpOverlapped,
lpCompletionRoutine,
lpThreadId,
lpErrno);
SetBlockingProvider (NULL);
if (ReturnValue==NO_ERROR) {
gBufferManager->CopyBuffer (InternalBuffers,
InternalBufferCount,
0,
*lpNumberOfBytesRecvd,
lpBuffers,
dwBufferCount,
0);
}
gBufferManager->FreeBuffer (InternalBuffers, InternalBufferCount);
} //else
} //if
} //if

POSTAPINOTIFY(( DTCODE_WSPRecvFrom,
&ReturnValue,
gLibraryName,
&s,
&lpBuffers,
&dwBufferCount,
&lpNumberOfBytesRecvd,
&lpFlags,
&lpFrom,
&lpFromlen,
&lpOverlapped,
&lpCompletionRoutine,
&lpThreadId,
&lpErrno));

return(ReturnValue);
}

typedef struct association
{
SOCKET ProviderSocket;
SOCKET UserSocket;
} SOCKETASSOCIATION, *PSOCKETASSOCIATION;

typedef struct
{
UINT AssociationCount;
PSOCKETASSOCIATION Associations;
} SOCKETMAP, *PSOCKETMAP;



INT
TransferUserFdSetToProviderFdSet(
IN fd_set * UserSet,
OUT fd_set * ProviderSet,
OUT PSOCKETMAP SocketMap,
OUT LPINT Errno)
{
INT ReturnCode;
UINT Index;
PDSOCKET Socket;

ReturnCode= NO_ERROR;
SocketMap->AssociationCount = 0;
SocketMap->Associations = NULL;
ProviderSet->fd_count = 0;

if (UserSet && (UserSet->fd_count > 0)){
if (UserSet->fd_count > FD_SETSIZE){
*Errno = WSAENOBUFS;
return(SOCKET_ERROR);
} //if
SocketMap->Associations = (PSOCKETASSOCIATION)new BYTE[
(sizeof(SOCKETASSOCIATION) * UserSet->fd_count)];
if (SocketMap->Associations){

for (Index=0;Index < UserSet->fd_count ;Index++ ){

ReturnCode = gUpCallTable.lpWPUQuerySocketHandleContext(
UserSet->fd_array[Index],
(DWORD*)&Socket,
Errno);
if (NO_ERROR != ReturnCode){
delete(SocketMap->Associations);
SocketMap->Associations = NULL;
*Errno = WSAEINVAL;
break;
} //if

SocketMap->Associations[Index].ProviderSocket =
Socket->GetProviderSocket();
SocketMap->Associations[Index].UserSocket =
UserSet->fd_array[Index];
ProviderSet->fd_array[Index] =
SocketMap->Associations[Index].ProviderSocket;

ProviderSet->fd_count++;
SocketMap->AssociationCount++;
} //for
} //if
else{
ReturnCode =SOCKET_ERROR;
*Errno = WSAENOBUFS;
} //else
} //if
return(ReturnCode);
}

INT
TransferProviderFdSetToUserFdSet(
IN fd_set * UserSet,
OUT fd_set * ProviderSet,
IN PSOCKETMAP SocketMap,
OUT LPINT Errno)
{
INT ReturnCode;
UINT ProviderIndex;
UINT AssociationIndex;

ReturnCode= NO_ERROR;

if (UserSet) {
UserSet->fd_count = 0;
for (ProviderIndex = 0;
ProviderIndex < ProviderSet->fd_count;
ProviderIndex++){

for (AssociationIndex =0;
AssociationIndex < SocketMap->AssociationCount;
AssociationIndex++){

if (ProviderSet->fd_array[ProviderIndex] ==
SocketMap->Associations[AssociationIndex].ProviderSocket){

UserSet->fd_array[ProviderIndex] =
SocketMap->Associations[AssociationIndex].UserSocket;
UserSet->fd_count++;
} //if
} //for
} //for
delete SocketMap->Associations;
} //if

return(ReturnCode);

}

INT
WSPAPI
WSPSelect(
IN INT nfds,
IN OUT fd_set FAR *readfds,
IN OUT fd_set FAR *writefds,
IN OUT fd_set FAR *exceptfds,
IN const struct timeval FAR *timeout,
OUT INT FAR *lpErrno
)
/*++
Routine Description:

Determine the status of one or more sockets.

Arguments:

nfds - This argument is ignored and included only for the sake of
compatibility.

readfds - An optional pointer to a set of sockets to be checked for
readability.

writefds - An optional pointer to a set of sockets to be checked for
writability

exceptfds - An optional pointer to a set of sockets to be checked for
errors.

timeout - The maximum time for WSPSelect() to wait, or NULL for a
blocking operation.

lpErrno - A pointer to the error code.

Return Value:

WSPSelect() returns the total number of descriptors which are ready and
contained in the fd_set structures, 0 if the time limit expired, or
SOCKET_ERROR if an error occurred. If the return value is SOCKET_ERROR, a
specific error code is available in lpErrno.

--*/
{
INT ReturnValue;
PDPROVIDER Provider;
SOCKET SocketHandle;
BOOL FoundSocket=FALSE;
PDSOCKET Socket;
fd_set InternalReadfds;
fd_set InternalWritefds;
fd_set InternalExceptfds;
SOCKETMAP ReadMap;
SOCKETMAP WriteMap;
SOCKETMAP ExceptMap;

if (PREAPINOTIFY(( DTCODE_WSPSelect,
&ReturnValue,
gLibraryName,
&nfds,
&readfds,
&writefds,
&exceptfds,
&timeout,
&lpErrno)) ) {
return(ReturnValue);
}

// Look for a socket in the three fd_sets handed in. The first
// socket found will be used to select the service provider to
// service this call
if (readfds && readfds->fd_count){

SocketHandle = readfds->fd_array[0];
FoundSocket = TRUE;
} //if

if (!FoundSocket && writefds && writefds->fd_count ){

SocketHandle = writefds->fd_array[0];
FoundSocket = TRUE;
} //if

if (!FoundSocket && exceptfds && exceptfds->fd_count ){

SocketHandle = exceptfds->fd_array[0];
FoundSocket = TRUE;
} //if
if (FoundSocket){
//
// Get our DSOCKET object
//
ReturnValue = gUpCallTable.lpWPUQuerySocketHandleContext(
SocketHandle,
(DWORD*)&Socket,
lpErrno);
if (SOCKET_ERROR != ReturnValue){
Provider = Socket->GetDProvider();

TransferUserFdSetToProviderFdSet(
readfds,
&InternalReadfds,
&ReadMap,
lpErrno);
TransferUserFdSetToProviderFdSet(
writefds,
&InternalWritefds,
&WriteMap,
lpErrno);
TransferUserFdSetToProviderFdSet(
exceptfds,
&InternalExceptfds,
&ExceptMap,
lpErrno);
if (NO_ERROR == *lpErrno){
SetBlockingProvider (Provider);
ReturnValue = Provider->WSPSelect(
nfds,
&InternalReadfds,
&InternalWritefds,
&InternalExceptfds,
timeout,
lpErrno);
SetBlockingProvider (NULL);
TransferProviderFdSetToUserFdSet(
readfds,
&InternalReadfds,
&ReadMap,
lpErrno);
TransferProviderFdSetToUserFdSet(
writefds,
&InternalWritefds,
&WriteMap,
lpErrno);
TransferProviderFdSetToUserFdSet(
exceptfds,
&InternalExceptfds,
&ExceptMap,
lpErrno);
DEBUGF( DBG_TRACE,
("Select Returns %X\n",ReturnValue));

} //if
else{
DEBUGF( DBG_TRACE,
("**Select failed**\n"));

ReturnValue = SOCKET_ERROR;
} //else
}
} //if
else{
ReturnValue = SOCKET_ERROR;
*lpErrno = WSAEINVAL;
} //else/if

POSTAPINOTIFY(( DTCODE_WSPSelect,
&ReturnValue,
gLibraryName,
&nfds,
&readfds,
&writefds,
&exceptfds,
&timeout,
&lpErrno));

return(ReturnValue);
}




INT
WSPAPI
WSPSend(
IN SOCKET s,
IN LPWSABUF lpBuffers,
IN DWORD dwBufferCount,
IN LPDWORD lpNumberOfBytesSent,
IN DWORD dwFlags,
IN LPWSAOVERLAPPED lpOverlapped,
IN LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
IN LPWSATHREADID lpThreadId,
OUT INT FAR *lpErrno
)
/*++
Routine Description:

Send data on a connected socket.

Arguments:

s - A descriptor identifying a connected socket.

lpBuffers - A pointer to an array of WSABUF structures. Each
WSABUF structure contains a pointer to a buffer and
the length of the buffer.

dwBufferCount - The number of WSABUF structures in the lpBuffers
array.

lpNumberOfBytesSent - A pointer to the number of bytes sent by this call.

dwFlags - Flags.

lpOverlapped - A pointer to a WSAOVERLAPPED structure.

lpCompletionRoutine - A pointer to the completion routine called when the
send operation has been completed.

lpThreadId - A pointer to a thread ID structure to be used by the
provider in a subsequent call to WPUQueueApc().

lpErrno - A pointer to the error code.

Return Value:

If no error occurs and the send operation has completed immediately,
WSPSend() returns the number of bytes received. If the connection has been
closed, it returns 0. Note that in this case the completion routine, if
specified, will have already been queued. Otherwise, a value of
SOCKET_ERROR is returned, and a specific error code is available in
lpErrno. The error code WSA_IO_PENDING indicates that the overlapped
operation has been successfully initiated and that completion will be
indicated at a later time. Any other error code indicates that no
overlapped operation was initiated and no completion indication will occur.

--*/
{
INT ReturnValue;
PDSOCKET Socket;
PDPROVIDER Provider;
SOCKET ProviderSocket;
LPWSABUF InternalBuffers;
DWORD InternalBufferCount;

if (PREAPINOTIFY(( DTCODE_WSPSend,
&ReturnValue,
gLibraryName,
&s,
&lpBuffers,
&dwBufferCount,

&lpNumberOfBytesSent, 
&dwFlags,
&lpOverlapped,
&lpCompletionRoutine,
&lpThreadId,
&lpErrno)) ) {
return(ReturnValue);
}

//
// Get our DSOCKET object
//
ReturnValue = gUpCallTable.lpWPUQuerySocketHandleContext(
s,
(DWORD*)&Socket,
lpErrno);
if (SOCKET_ERROR != ReturnValue){

// Get Internal buffers to send down to the lower provider.
ReturnValue = gBufferManager->AllocBuffer(
lpBuffers,
dwBufferCount,
&InternalBuffers,
&InternalBufferCount);

if (NO_ERROR == ReturnValue){
// Copy the user buffers
ReturnValue = gBufferManager->CopyBuffer(
lpBuffers,
dwBufferCount,
0,
0xFFFFFFFF,// Max bytes to copy
InternalBuffers,
InternalBufferCount,
0);
} //if

if (NO_ERROR == ReturnValue){
//Is this a overlapped operation.
if (lpOverlapped){
if (lpCompletionRoutine
|| (lpOverlapped->hEvent==NULL)
|| ResetEvent ((HANDLE)((DWORD)lpOverlapped->hEvent&0xFFFFFFFE))) {
PDWORKERTHREAD Thread = GetWorkerThread ();
if (Thread!=NULL) {
// Setup the user overlapped struct
lpOverlapped->Internal = WSS_OPERATION_IN_PROGRESS;
lpOverlapped->InternalHigh = 0;
ReturnValue = Thread->QueueOverlappedSend(
Socket,
InternalBuffers,
InternalBufferCount,
lpNumberOfBytesSent,
dwFlags,
lpOverlapped,
lpCompletionRoutine,
lpThreadId,
lpErrno);
}
else {
ReturnValue = SOCKET_ERROR;
*lpErrno = WSAENOBUFS;
}
}
else {
ReturnValue = SOCKET_ERROR;
*lpErrno = WSA_INVALID_PARAMETER;
}

} //if
else{
Provider = Socket->GetDProvider();
ProviderSocket = Socket->GetProviderSocket();

SetBlockingProvider (Provider);
ReturnValue = Provider->WSPSend(
ProviderSocket,
InternalBuffers,
InternalBufferCount,
lpNumberOfBytesSent,
dwFlags,
lpOverlapped,
lpCompletionRoutine,
lpThreadId,
lpErrno);
SetBlockingProvider (NULL);
gBufferManager->FreeBuffer (InternalBuffers, InternalBufferCount);
} //else
} //if
} //if
POSTAPINOTIFY(( DTCODE_WSPSend,
&ReturnValue,
gLibraryName,
&s,
&lpBuffers,
&dwBufferCount,
&lpNumberOfBytesSent,
&dwFlags,
&lpOverlapped,
&lpCompletionRoutine,
&lpThreadId,
&lpErrno));

return(ReturnValue);
}



INT
WSPAPI
WSPSendDisconnect(
IN SOCKET s,
IN LPWSABUF lpOutboundDisconnectData,
OUT INT FAR *lpErrno
)
/*++
Routine Description:

Initiate termination of the connection for the socket and send disconnect
data.

Arguments:

s - A descriptor identifying a socket.

lpOutboundDisconnectData - A pointer to the outgoing disconnect data.

lpErrno - A pointer to the error code.

Return Value:

If no error occurs, WSPSendDisconnect() returns 0. Otherwise, a value of
SOCKET_ERROR is returned, and a specific error code is available in
lpErrno.

--*/
{
INT ReturnValue;
PDSOCKET Socket;
PDPROVIDER Provider;
SOCKET ProviderSocket;


if (PREAPINOTIFY(( DTCODE_WSPSendDisconnect,
&ReturnValue,
gLibraryName,
&s,
&lpOutboundDisconnectData,
&lpErrno)) ) {
return(ReturnValue);
}

//
// Get our DSOCKET object
//
ReturnValue = gUpCallTable.lpWPUQuerySocketHandleContext(
s,
(DWORD*)&Socket,
lpErrno);
if (SOCKET_ERROR != ReturnValue){
Provider = Socket->GetDProvider();
ProviderSocket = Socket->GetProviderSocket();

ReturnValue = Provider->WSPSendDisconnect(
ProviderSocket,
lpOutboundDisconnectData,
lpErrno);
} //if

POSTAPINOTIFY(( DTCODE_WSPSendDisconnect,
&ReturnValue,
gLibraryName,
&s,
&lpOutboundDisconnectData,
&lpErrno));

return(ReturnValue);

}



INT
WSPAPI
WSPSendTo(
IN SOCKET s,
IN LPWSABUF lpBuffers,
IN DWORD dwBufferCount,
IN LPDWORD lpNumberOfBytesSent,
IN DWORD dwFlags,
IN const struct sockaddr FAR * lpTo,
IN INT iTolen,
IN LPWSAOVERLAPPED lpOverlapped,
IN LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
IN LPWSATHREADID lpThreadId,
OUT INT FAR *lpErrno
)
/*++
Routine Description:

Send data to a specific destination using overlapped I/O.

Arguments:

s - A descriptor identifying a socket.

lpBuffers - A pointer to an array of WSABUF structures. Each
WSABUF structure contains a pointer to a buffer and
the length of the buffer.

dwBufferCount - The number of WSABUF structures in the lpBuffers
array.

lpNumberOfBytesSent - A pointer to the number of bytes sent by this call.

dwFlags - Flags.

lpTo - An optional pointer to the address of the target
socket.

iTolen - The size of the address in lpTo.

lpOverlapped - A pointer to a WSAOVERLAPPED structure.

lpCompletionRoutine - A pointer to the completion routine called when the
send operation has been completed.

lpThreadId - A pointer to a thread ID structure to be used by the
provider in a subsequent call to WPUQueueApc().

lpErrno - A pointer to the error code.

Return Value:

If no error occurs and the receive operation has completed immediately,
WSPSendTo() returns the number of bytes received. If the connection has
been closed,it returns 0. Note that in this case the completion routine,
if specified, will have already been queued. Otherwise, a value of
SOCKET_ERROR is returned, and a specific error code is available in
lpErrno. The error code WSA_IO_PENDING indicates that the overlapped
operation has been successfully initiated and that completion will be
indicated at a later time. Any other error code indicates that no
overlapped operation was initiated and no completion indication will occur.

--*/


{
INT ReturnValue;
PDSOCKET Socket;
PDPROVIDER Provider;
SOCKET ProviderSocket;
LPWSABUF InternalBuffers;
DWORD InternalBufferCount;


if (PREAPINOTIFY(( DTCODE_WSPSendTo,
&ReturnValue,
gLibraryName,
&s,
&lpBuffers,
&lpNumberOfBytesSent,
&dwFlags,
&lpTo,
&iTolen,
&lpOverlapped,
&lpCompletionRoutine,
&lpThreadId,
&lpErrno)) ) {
return(ReturnValue);
}

//
// Get our DSOCKET object
//
ReturnValue = gUpCallTable.lpWPUQuerySocketHandleContext(
s,
(DWORD*)&Socket,
lpErrno);
if (SOCKET_ERROR != ReturnValue){
// Get Internal buffers to send down to the lower provider.
ReturnValue = gBufferManager->AllocBuffer(
lpBuffers,
dwBufferCount,
&InternalBuffers,
&InternalBufferCount);

if (NO_ERROR == ReturnValue){
// Copy the user buffers
ReturnValue = gBufferManager->CopyBuffer(
lpBuffers,
dwBufferCount,
0,
0xFFFFFFFF,// Max bytes to copy
InternalBuffers,
InternalBufferCount,
0);
} //if

if (NO_ERROR == ReturnValue){
//Is this a overlapped operation.
if (lpOverlapped){
if (lpCompletionRoutine
|| (lpOverlapped->hEvent==NULL)
|| ResetEvent ((HANDLE)((DWORD)lpOverlapped->hEvent&0xFFFFFFFE))) {
PDWORKERTHREAD Thread = GetWorkerThread ();
if (Thread!=NULL) {
// Setup the user overlapped struct
lpOverlapped->Internal = WSS_OPERATION_IN_PROGRESS;
lpOverlapped->InternalHigh = 0;
ReturnValue = Thread->QueueOverlappedSendTo(
Socket,
InternalBuffers,
InternalBufferCount,
lpNumberOfBytesSent,
dwFlags,
lpTo,
iTolen,
lpOverlapped,
lpCompletionRoutine,
lpThreadId,
lpErrno);
}
else {
ReturnValue = SOCKET_ERROR;
*lpErrno = WSAENOBUFS;
}
}
else {
ReturnValue = SOCKET_ERROR;
*lpErrno = WSA_INVALID_PARAMETER;
}
} //if
else{
Provider = Socket->GetDProvider();
ProviderSocket = Socket->GetProviderSocket();

SetBlockingProvider (Provider);
ReturnValue = Provider->WSPSendTo(
ProviderSocket,
lpBuffers,
dwBufferCount,
lpNumberOfBytesSent,
dwFlags,
lpTo,
iTolen,
lpOverlapped,
lpCompletionRoutine,
lpThreadId,
lpErrno);
SetBlockingProvider (NULL);
gBufferManager->FreeBuffer (InternalBuffers, InternalBufferCount);
} //else
} //if
} //if

POSTAPINOTIFY(( DTCODE_WSPSendTo,
&ReturnValue,
gLibraryName,
&s,
&lpBuffers,
&lpNumberOfBytesSent,
&dwFlags,
&lpTo,
&iTolen,
&lpOverlapped,
&lpCompletionRoutine,
&lpThreadId,
&lpErrno));

return(ReturnValue);
}


INT
WSPAPI
WSPSetSockOpt(
IN SOCKET s,
IN INT level,
IN INT optname,
IN const char FAR *optval,
IN INT optlen,
OUT INT FAR *lpErrno
)
/*++
Routine Description:

Set a socket option.

Arguments:

s - A descriptor identifying a socket.

level - The level at which the option is defined; the supported levels
include SOL_SOCKET. (See annex for more protocol-specific
levels.)

optname - The socket option for which the value is to be set.

optval - A pointer to the buffer in which the value for the requested
option is supplied.

optlen - The size of the optval buffer.

lpErrno - A pointer to the error code.

Return Value:

If no error occurs, WSPSetSockOpt() returns 0. Otherwise, a value of
SOCKET_ERROR is returned, and a specific error code is available in
lpErrno.

--*/
{
INT ReturnValue;
PDSOCKET Socket;
PDPROVIDER Provider;
SOCKET ProviderSocket;


if (PREAPINOTIFY(( DTCODE_WSPSetSockOpt,
&ReturnValue,
gLibraryName,
&s,
&level,
&optname,
&optval,
&optlen,
&lpErrno)) ) {
return(ReturnValue);
}

//
// Get our DSOCKET object
//
ReturnValue = gUpCallTable.lpWPUQuerySocketHandleContext(
s,
(DWORD*)&Socket,
lpErrno);
if (SOCKET_ERROR != ReturnValue){
Provider = Socket->GetDProvider();
ProviderSocket = Socket->GetProviderSocket();

ReturnValue = Provider->WSPSetSockOpt(
ProviderSocket,
level,
optname,
optval,
optlen,
lpErrno);
} //if

POSTAPINOTIFY(( DTCODE_WSPSetSockOpt,
&ReturnValue,
gLibraryName,
&s,
&level,
&optname,
&optval,
&optlen,
&lpErrno));

return(ReturnValue);

}



INT
WSPAPI
WSPShutdown(
IN SOCKET s,
IN INT how,
OUT INT FAR *lpErrno
)
/*++
Routine Description:

Disable sends and/or receives on a socket.

Arguments:

s - A descriptor identifying a socket.

how - A flag that describes what types of operation will no longer be
allowed.

lpErrno - A pointer to the error code.

Return Value:

If no error occurs, WSPShutdown() returns 0. Otherwise, a value of
SOCKET_ERROR is returned, and a specific error code is available in
lpErrno.

--*/
{
INT ReturnValue;
PDSOCKET Socket;
PDPROVIDER Provider;
SOCKET ProviderSocket;


if (PREAPINOTIFY(( DTCODE_WSPShutdown,
&ReturnValue,
gLibraryName,
&s,
&how,
&lpErrno)) ) {
return(ReturnValue);
}

//
// Get our DSOCKET object
//
ReturnValue = gUpCallTable.lpWPUQuerySocketHandleContext(
s,
(DWORD*)&Socket,
lpErrno);
if (SOCKET_ERROR != ReturnValue){
Provider = Socket->GetDProvider();
ProviderSocket = Socket->GetProviderSocket();
DEBUGF( DBG_TRACE,
("Shutdown socket %X\n",s));

ReturnValue = Provider->WSPShutdown(
ProviderSocket,
how,
lpErrno);
} //if

POSTAPINOTIFY(( DTCODE_WSPShutdown,
&ReturnValue,
gLibraryName,
&s,
&how,
&lpErrno));

return(ReturnValue);
}



SOCKET
WSPAPI
WSPSocket(
IN int af,
IN int type,
IN int protocol,
IN LPWSAPROTOCOL_INFOW lpProtocolInfo,
IN GROUP g,
IN DWORD dwFlags,
OUT INT FAR *lpErrno
)
/*++
Routine Description:

Initialize internal data and prepare sockets for usage. Must be called
before any other socket routine.

Arguments:

lpProtocolInfo - Supplies a pointer to a WSAPROTOCOL_INFOA struct that
defines the characteristics of the socket to be created.

g - Supplies the identifier of the socket group which the new
socket is to join.

dwFlags - Supplies the socket attribute specification.

lpErrno - Returns the error code

Return Value:

WSPSocket() returns zero if successful. Otherwise it returns an error code
as outlined in the SPI.

--*/
{
INT ReturnValue;
INT NextProviderSocket;
PDPROVIDER Provider;
PDSOCKET Socket;
DWORDThisProviderCatalogEntryId;
PPROTO_CATALOG_ITEMBaseProviderCatalogEntry;

// Debug/Trace stuff
if (PREAPINOTIFY(( DTCODE_WSPSocket,
&ReturnValue,
gLibraryName,
&af,
&type,
&protocol,
&lpProtocolInfo,
&g,
&dwFlags,
&lpErrno)) ) {
return(ReturnValue);
}


//
// Get the catlog entry for the next provider in the chain
//
ReturnValue = gProviderCatalog->FindNextProviderInChain(
lpProtocolInfo,
&Provider,
&BaseProviderCatalogEntry);

if (NO_ERROR==ReturnValue) {
WSAPROTOCOL_INFOWProtocolInfo;
LPWSAPROTOCOL_INFOWlpPassedInfo;

// If next provider is base, get it its own protocol info
if (BaseProviderCatalogEntry) {
ProtocolInfo = *BaseProviderCatalogEntry->GetProtocolInfo();
// Carefully restore reserved field.
ProtocolInfo.dwProviderReserved = lpProtocolInfo->dwProviderReserved;
lpPassedInfo = &ProtocolInfo;
}
else
lpPassedInfo = lpProtocolInfo;

ReturnValue = Provider->WSPSocket(
af,
type,
protocol,
lpPassedInfo,
g,
dwFlags,
lpErrno);

if (ReturnValue != INVALID_SOCKET){
NextProviderSocket = ReturnValue;

//
// Create our socket object
//

Socket = new DSOCKET;
if (Socket){
ThisProviderCatalogEntryId =
gProviderCatalog->GetLocalProvider()->GetProtocolInfo()->dwCatalogEntryId;

ReturnValue = gUpCallTable.lpWPUCreateSocketHandle(
ThisProviderCatalogEntryId,
(DWORD) Socket,
lpErrno);
DEBUGF( DBG_TRACE,
("Socket Returning Socket %X\n", ReturnValue));

if (INVALID_SOCKET != ReturnValue){
Socket->Initialize(
Provider,
NextProviderSocket,
lpProtocolInfo->dwCatalogEntryId,
ReturnValue);

} //if
else{
delete(Socket);
} //else
} //if
} //if
else{
*lpErrno = ReturnValue;
ReturnValue = INVALID_SOCKET;
} //else
} //if
else{
*lpErrno = ReturnValue;
ReturnValue = INVALID_SOCKET;
} //else

// Debug/Trace stuff
POSTAPINOTIFY(( DTCODE_WSPSocket,
&ReturnValue,
gLibraryName,
&af,
&type,
&protocol,
&lpProtocolInfo,
&g,
&dwFlags,
&lpErrno));

return(ReturnValue);
}




INT
WSPAPI
WSPStringToAddress(
IN LPWSTR AddressString,
IN INT AddressFamily,
IN LPWSAPROTOCOL_INFOW lpProtocolInfo,
OUT LPSOCKADDR lpAddress,
IN OUT LPINT lpAddressLength,
IN OUT LPINT lpErrno )
/*++

Routine Description:

WSPStringToAddress() converts a human-readable string to a socket address
structure (SOCKADDR) suitable for pass to Windows Sockets routines which
take such a structure. If the caller wishes the translation to be done by
a particular provider, it should supply the corresponding WSAPROTOCOL_INFO
struct in the lpProtocolInfo parameter.

Arguments:

AddressString - points to the zero-terminated human-readable string to
convert.

AddressFamily - the address family to which the string belongs.

lpProtocolInfo - (optional) the WSAPROTOCOL_INFO struct for a particular
provider.

Address - a buffer which is filled with a single SOCKADDR structure.

lpAddressLength - The length of the Address buffer. Returns the size of
the resultant SOCKADDR structure.

Return Value:

The return value is 0 if the operation was successful. Otherwise the value
SOCKET_ERROR is returned.

--*/
{
INT ReturnValue;
PDPROVIDER Provider;
PPROTO_CATALOG_ITEMBaseProviderCatalogEntry;

if (PREAPINOTIFY(( DTCODE_WSPAddressToString,
&ReturnValue,
gLibraryName,
&AddressString,
&AddressFamily,
&lpProtocolInfo,
&lpAddress,
&lpAddressLength,
&lpErrno)) ){
return(ReturnValue);
} //if

//
// Get the catlog entry for the next provider in the chain
//
ReturnValue = gProviderCatalog->FindNextProviderInChain(
lpProtocolInfo,
&Provider,
&BaseProviderCatalogEntry);

if (NO_ERROR == ReturnValue){
ReturnValue = Provider->WSPStringToAddress(
AddressString,
AddressFamily,
BaseProviderCatalogEntry
? BaseProviderCatalogEntry->GetProtocolInfo()
: lpProtocolInfo,
lpAddress,
lpAddressLength,
lpErrno);
} //if

POSTAPINOTIFY(( DTCODE_WSPAddressToString,
&ReturnValue,
gLibraryName,
&AddressString,
&AddressFamily,
&lpProtocolInfo,
&lpAddress,
&lpAddressLength,
&lpErrno));

return(ReturnValue);

}



int
WSPAPI
WSPStartup(
WORD wVersion,
LPWSPDATA lpWSPData,
LPWSAPROTOCOL_INFOW lpProtocolInfo,
WSPUPCALLTABLE UpcallTable,
LPWSPPROC_TABLE lpProcTable )
/*++

Routine Description:

Initiate use of a WinSock service provider by a client.

Arguments:

wVersionRequested - The highest version of WinSock SPI support that the
caller can use. The high order byte specifies the
minor version (revision) number; the low-order byte
specifies the major version number.

lpWSPData - A pointer to the WSPDATA data structure that is to receive
details of the WinSock service provider.

lpProtocolInfo - A pointer to a WSAPROTOCOL_INFO struct that defines the
characteristics of the desired protocol. This is
especially useful when a single provider DLL is capable of
instantiating multiple different service providers.

UpcallTableThe WinSock 2 DLLs upcall dispatch table.

lpProcTable - A pointer to the table of SPI function pointers.



Return Value:


--*/
{
HMODULEhWS2_32;
INTReturnCode;

EnterCriticalSection(&gInitCriticalSection);

ReturnCode = NO_ERROR;

// Save the WinSock2 upcall table
gUpCallTable = UpcallTable;

if (gStartupCount == 0){
ReturnCode = WSAVERNOTSUPPORTED;
// This is the first time that WSPStartup() has been called so lets get
// ourselves ready to do bussiness

// First check for new exported function
hWS2_32 = GetModuleHandle (TEXT("ws2_32.dll"));
if (hWS2_32!=NULL) {
lpWPUCompleteOverlappedRequest =
(LPWPUCOMPLETEOVERLAPPEDREQUEST)
GetProcAddress (hWS2_32, "WPUCompleteOverlappedRequest");


if (lpWPUCompleteOverlappedRequest!=NULL) {
ReturnCode = WSASYSNOTREADY;


// Initialize the sockets
DSOCKET::DSocketClassInitialize ();

//
// Init the provider catalog
//
gProviderCatalog = new DCATALOG;
if (gProviderCatalog){
ReturnCode = gProviderCatalog->Initialize();
} //if

//
// Init the buffer manager
//
if (NO_ERROR == ReturnCode){
gBufferManager = new DBUFFERMANAGER;
if (gBufferManager){
ReturnCode = gBufferManager->Initialize();
// If we succeded incremant the startup count
if (NO_ERROR == ReturnCode){
gStartupCount++;
} //if
} //if
} //if
} //if
} // if
} // if
LeaveCriticalSection(&gInitCriticalSection);

if (ReturnCode==NO_ERROR) {
//
// Fill in the clients proceedure table with our entry points.
//

lpProcTable->lpWSPAccept = WSPAccept;
lpProcTable->lpWSPAddressToString = WSPAddressToString;
lpProcTable->lpWSPAsyncSelect = WSPAsyncSelect;
lpProcTable->lpWSPBind = WSPBind;
lpProcTable->lpWSPCancelBlockingCall = WSPCancelBlockingCall;
lpProcTable->lpWSPCleanup = WSPCleanup;
lpProcTable->lpWSPCloseSocket = WSPCloseSocket;
lpProcTable->lpWSPConnect = WSPConnect;
lpProcTable->lpWSPDuplicateSocket = WSPDuplicateSocket;
lpProcTable->lpWSPEnumNetworkEvents = WSPEnumNetworkEvents;
lpProcTable->lpWSPEventSelect = WSPEventSelect;
lpProcTable->lpWSPGetOverlappedResult = WSPGetOverlappedResult;
lpProcTable->lpWSPGetPeerName = WSPGetPeerName;
lpProcTable->lpWSPGetSockName = WSPGetSockName;
lpProcTable->lpWSPGetSockOpt = WSPGetSockOpt;
lpProcTable->lpWSPGetQOSByName = WSPGetQOSByName;
lpProcTable->lpWSPIoctl = WSPIoctl;
lpProcTable->lpWSPJoinLeaf = WSPJoinLeaf;
lpProcTable->lpWSPListen = WSPListen;
lpProcTable->lpWSPRecv = WSPRecv;
lpProcTable->lpWSPRecvDisconnect = WSPRecvDisconnect;
lpProcTable->lpWSPRecvFrom = WSPRecvFrom;
lpProcTable->lpWSPSelect = WSPSelect;
lpProcTable->lpWSPSend = WSPSend;
lpProcTable->lpWSPSendDisconnect = WSPSendDisconnect;
lpProcTable->lpWSPSendTo = WSPSendTo;
lpProcTable->lpWSPSetSockOpt = WSPSetSockOpt;
lpProcTable->lpWSPShutdown = WSPShutdown;
lpProcTable->lpWSPSocket = WSPSocket;
lpProcTable->lpWSPStringToAddress = WSPStringToAddress;

}

// Set the version info
lpWSPData->wVersion = MAKEWORD(2,2);
lpWSPData->wHighVersion = MAKEWORD(2,2);

return(ReturnCode);
}


BOOL
PASCAL FAR
WSPTransmitFile (
IN SOCKET hSocket,
IN HANDLE hFile,
IN DWORD nNumberOfBytesToWrite,
IN DWORD nNumberOfBytesPerSend,
IN LPOVERLAPPED lpOverlapped,
IN LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers,
IN DWORD dwReserved
) {
PDSOCKETSocket;
INTErrno, ReturnValue;
PDPROVIDERProvider;
SOCKETProviderSocket;
//
// Get our DSOCKET object
//
ReturnValue = gUpCallTable.lpWPUQuerySocketHandleContext(
hSocket,
(DWORD*)&Socket,
&Errno);

if (SOCKET_ERROR != ReturnValue){
if (lpOverlapped) {
if ((lpOverlapped->hEvent==NULL)
|| ResetEvent ((HANDLE)((DWORD)lpOverlapped->hEvent&0xFFFFFFFE))) {
PDWORKERTHREAD Thread = GetWorkerThread ();
if (Thread!=NULL) {
// Setup the user overlapped struct
lpOverlapped->Internal = WSS_OPERATION_IN_PROGRESS;
lpOverlapped->InternalHigh = 0;
ReturnValue = Thread->QueueOverlappedTransmitFile(
Socket,
hFile,
nNumberOfBytesToWrite,
nNumberOfBytesPerSend,
lpOverlapped,
lpTransmitBuffers,
dwReserved,
&Errno);
}
else {
ReturnValue = SOCKET_ERROR;
Errno = WSAENOBUFS;
}
}
else {
ReturnValue = SOCKET_ERROR;
Errno = WSA_INVALID_PARAMETER;
}
}
else {
Provider = Socket->GetDProvider ();
ProviderSocket = Socket->GetProviderSocket ();
ReturnValue = Provider->TransmitFile (
ProviderSocket,
hFile,
nNumberOfBytesToWrite,
nNumberOfBytesPerSend,
lpOverlapped,
lpTransmitBuffers,
dwReserved,
&Errno);
}
}
if (ReturnValue==NO_ERROR)
return TRUE;
else {
SetLastError (Errno);
return FALSE;

} 
}