mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
513 lines
16 KiB
513 lines
16 KiB
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
startup.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the startup code for the Winsock 2 to
|
|
Winsock 1.1 Mapper Service Provider.
|
|
|
|
The following routines are exported by this module:
|
|
|
|
WSPStartup()
|
|
WSPCleanup()
|
|
|
|
Author:
|
|
|
|
Keith Moore (keithmo) 29-May-1996
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
//
|
|
// Our version number.
|
|
//
|
|
|
|
#define SPI_VERSION MAKEWORD( 2, 2 )
|
|
|
|
|
|
|
|
INT
|
|
WSPAPI
|
|
WSPStartup(
|
|
IN WORD wVersionRequested,
|
|
OUT LPWSPDATA lpWSPData,
|
|
IN LPWSAPROTOCOL_INFOW lpProtocolInfo,
|
|
IN WSPUPCALLTABLE UpcallTable,
|
|
OUT LPWSPPROC_TABLE lpProcTable
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine MUST be the first WinSock SPI function called by a WinSock
|
|
SPI client on a per-process basis. It allows the client to specify the
|
|
version of WinSock SPI required and to provide its upcall dispatch table.
|
|
All upcalls, i.e., functions prefixed with WPU, made by the WinSock
|
|
service provider are invoked via the client's upcall dispatch table.
|
|
This routine also allows the client to retrieve details of the specific
|
|
WinSock service provider implementation. The WinSock SPI client may only
|
|
issue further WinSock SPI functions after a successful WSPStartup()
|
|
invocation. A table of pointers to the rest of the SPI functions is
|
|
retrieved via the lpProcTable parameter.
|
|
|
|
In order to support future versions of the WinSock SPI and the WinSock 2
|
|
DLL which may have functionality differences from the current WinSock SPI,
|
|
a negotiation takes place in WSPStartup(). The caller of WSPStartup()
|
|
(either the WinSock 2 DLL or a layered protocol) and the WinSock service
|
|
provider indicate to each other the highest version that they can support,
|
|
and each confirms that the other's highest version is acceptable. Upon
|
|
entry to WSPStartup(), the WinSock service provider examines the version
|
|
requested by the client. If this version is equal to or higher than the
|
|
lowest version supported by the service provider, the call succeeds and
|
|
the service provider returns in wHighVersion the highest version it
|
|
supports and in wVersion the minimum of its high version and
|
|
wVersionRequested. The WinSock service provider then assumes that the
|
|
WinSock SPI client will use wVersion. If the wVersion field of the WSPDATA
|
|
structure is unacceptable to the caller, it should call WSPCleanup() and
|
|
either search for another WinSock service provider or fail to initialize.
|
|
|
|
This negotiation allows both a WinSock service provider and a WinSock SPI
|
|
client to support a range of WinSock versions. A client can successfully
|
|
utilize a WinSock service provider if there is any overlap in the version
|
|
ranges. The following chart gives examples of how WSPStartup() works in
|
|
conjunction with different WinSock DLL and WinSock service provider (SP)
|
|
versions:
|
|
|
|
DLL SP wVersion- wVersion wHigh- End
|
|
Version Version Requested Version Result
|
|
~~~~~~~ ~~~~~~~ ~~~~~~~~~ ~~~~~~~~ ~~~~~~~ ~~~~~~
|
|
1.1 1.1 1.1 1.1 1.1 use 1.1
|
|
1.0 1.1 1.0 1.1 1.0 1.0 use 1.0
|
|
1.0 1.0 1.1 1.0 1.0 1.1 use 1.0
|
|
1.1 1.0 1.1 1.1 1.1 1.1 use 1.1
|
|
1.1 1.0 1.1 1.0 1.0 DLL fails
|
|
1.0 1.1 1.0 --- --- WSAVERNOTSUPPORTED
|
|
1.0 1.1 1.0 1.1 1.1 1.1 1.1 use 1.1
|
|
1.1 2.0 1.1 2.0 1.1 1.1 use 1.1
|
|
2.0 2.0 2.0 2.0 2.0 use 2.0
|
|
|
|
The following code fragment demonstrates how a WinSock SPI client which
|
|
supports only version 2.0 of WinSock SPI makes a WSPStartup() call:
|
|
|
|
WORD wVersionRequested;
|
|
WSPDATA WSPData;
|
|
|
|
int err;
|
|
|
|
WSPUPCALLTABLE upcallTable =
|
|
{
|
|
// initialize upcallTable with function pointers
|
|
};
|
|
|
|
LPWSPPROC_TABLE lpProcTable =
|
|
{
|
|
// allocate memory for the ProcTable
|
|
};
|
|
|
|
wVersionRequested = MAKEWORD( 2, 0 );
|
|
|
|
err = WSPStartup( wVersionRequested, &WSPData,
|
|
lpProtocolBuffer, upcallTable, lpProcTable );
|
|
if ( err != 0 ) {
|
|
// Tell the user that we couldn't find a useable
|
|
// WinSock service provider.
|
|
return;
|
|
}
|
|
|
|
// Confirm that the WinSock service provider supports 2.0.
|
|
// Note that if the service provider supports versions
|
|
// greater than 2.0 in addition to 2.0, it will still
|
|
// return 2.0 in wVersion since that is the version we
|
|
// requested.
|
|
|
|
if ( LOBYTE( WSPData.wVersion ) != 2 ||
|
|
HIBYTE( WSPData.wVersion ) != 0 ) {
|
|
// Tell the user that we couldn't find a useable
|
|
// WinSock service provider.
|
|
WSPCleanup( );
|
|
return;
|
|
}
|
|
|
|
// The WinSock service provider is acceptable. Proceed.
|
|
|
|
And this code fragment demonstrates how a WinSock service provider which
|
|
supports only version 2.0 performs the WSPStartup() negotiation:
|
|
|
|
// Make sure that the version requested is >= 2.0.
|
|
// The low byte is the major version and the high
|
|
// byte is the minor version.
|
|
|
|
if ( LOBYTE( wVersionRequested ) < 2) {
|
|
return WSAVERNOTSUPPORTED;
|
|
}
|
|
|
|
// Since we only support 2.0, set both wVersion and
|
|
// wHighVersion to 2.0.
|
|
|
|
lpWSPData->wVersion = MAKEWORD( 2, 0 );
|
|
lpWSPData->wHighVersion = MAKEWORD( 2, 0 );
|
|
|
|
Once the WinSock SPI client has made a successful WSPStartup() call, it
|
|
may proceed to make other WinSock SPI calls as needed. When it has
|
|
finished using the services of the WinSock service provider, the client
|
|
must call WSPCleanup() in order to allow the WinSock service provider to
|
|
free any resources allocated for the client.
|
|
|
|
Details of how WinSock service provider information is encoded in the
|
|
WSPData structure is as follows:
|
|
|
|
typedef struct WSPData {
|
|
WORD wVersion;
|
|
WORD wHighVersion;
|
|
char szDescription[WSPDESCRIPTION_LEN+1];
|
|
} WSPDATA, FAR * LPWSPDATA;
|
|
|
|
The members of this structure are:
|
|
|
|
wVersion- The version of the WinSock SPI specification that the
|
|
WinSock service provider expects the caller to use.
|
|
|
|
wHighVersion - The highest version of the WinSock SPI specification
|
|
that this service provider can support (also encoded as above).
|
|
Normally this will be the same as wVersion.
|
|
|
|
szDescription - A null-terminated ASCII string into which the
|
|
WinSock provider copies a description of itself. The text
|
|
(up to 256 characters in length) may contain any characters
|
|
except control and formatting characters: the most likely use
|
|
that a SPI client will put this to is to display it (possibly
|
|
truncated) in a status message.
|
|
|
|
A WinSock SPI client may call WSPStartup() more than once if it needs to
|
|
obtain the WSPData structure information more than once. On each such
|
|
call the client may specify any version number supported by the provider.
|
|
|
|
There must be one WSPCleanup() call corresponding to every successful
|
|
WSPStartup() call to allow third-party DLLs to make use of a WinSock
|
|
provider. This means, for example, that if WSPStartup() is called three
|
|
times, the corresponding call to WSPCleanup() must occur three times.
|
|
The first two calls to WSPCleanup() do nothing except decrement an
|
|
internal counter; the final WSPCleanup() call does all necessary resource
|
|
deallocation.
|
|
|
|
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_INFOW 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..
|
|
|
|
UpcallTable - The WinSock 2 DLL's upcall dispatch table.
|
|
|
|
lpProcTable - A pointer to the table of SPI function pointers.
|
|
|
|
Return Value:
|
|
|
|
WSPStartup() returns zero if successful. Otherwise it returns an error
|
|
code.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
SOCK_ENTER( "WSPStartup", (PVOID)wVersionRequested, lpWSPData, (PVOID)&UpcallTable, NULL );
|
|
|
|
SOCK_ASSERT( lpWSPData != NULL );
|
|
|
|
err = SockEnterApi( FALSE, TRUE );
|
|
|
|
if( err != NO_ERROR ) {
|
|
|
|
SOCK_EXIT( "WSPStartup", err, TRUE );
|
|
return err;
|
|
|
|
}
|
|
|
|
//
|
|
// Check the version number.
|
|
//
|
|
|
|
if ( SockWspStartupCount == 0 &&
|
|
wVersionRequested != SPI_VERSION ) {
|
|
|
|
SOCK_EXIT( "WSPStartup", WSAVERNOTSUPPORTED, TRUE );
|
|
return WSAVERNOTSUPPORTED;
|
|
|
|
}
|
|
|
|
//
|
|
// Remember that the app has called WSPStartup.
|
|
//
|
|
|
|
InterlockedIncrement( &SockWspStartupCount );
|
|
|
|
//
|
|
// Fill in the WSPData structure.
|
|
//
|
|
|
|
lpWSPData->wVersion = SPI_VERSION;
|
|
lpWSPData->wHighVersion = SPI_VERSION;
|
|
|
|
wcscpy(
|
|
lpWSPData->szDescription,
|
|
L"Microsoft Windows Sockets 2 to 1.1 Mapper."
|
|
);
|
|
|
|
//
|
|
// Save the upcall table.
|
|
//
|
|
|
|
SockUpcallTable = UpcallTable;
|
|
|
|
//
|
|
// Return our proc table to the DLL.
|
|
//
|
|
|
|
*lpProcTable = SockProcTable;
|
|
|
|
//
|
|
// Cleanup & exit.
|
|
//
|
|
|
|
SockTerminating = FALSE;
|
|
|
|
SOCK_EXIT( "WSPStartup", NO_ERROR, FALSE );
|
|
return NO_ERROR;
|
|
|
|
} // WSPStartup
|
|
|
|
|
|
|
|
INT
|
|
WSPAPI
|
|
WSPCleanup(
|
|
OUT LPINT lpErrno
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The WinSock 2 SPI client is required to perform a successful WSPStartup()
|
|
call before it can use WinSock service providers. When it has completed
|
|
the use of WinSock service providers, the SPI client will call
|
|
WSPCleanup() to deregister itself from a WinSock service provider and
|
|
allow the service provider to free any resources allocated on behalf of
|
|
the WinSock 2 client. It is permissible for SPI clients to make more than
|
|
one WSPStartup() call. For each WSPStartup() call a corresponding
|
|
WSPCleanup() call will also be issued. Only the final WSPCleanup() for
|
|
the service provider does the actual cleanup; the preceding calls simply
|
|
decrement an internal reference count in the WinSock service provider.
|
|
|
|
When the internal reference count reaches zero and actual cleanup
|
|
operations commence, any pending blocking or asynchronous calls issued by
|
|
any thread in this process are canceled without posting any notification
|
|
messages or signaling any event objects. Any pending overlapped send and
|
|
receive operations (WSPSend()/WSPSendTo()/WSPRecv()/WSPRecvFrom() with an
|
|
overlapped socket) issued by any thread in this process are also canceled
|
|
without setting the event object or invoking the completion routine, if
|
|
specified. In this case, the pending overlapped operations fail with the
|
|
error status WSA_OPERATION_ABORTED. Any sockets open when WSPCleanup() is
|
|
called are reset and automatically deallocated as if WSPClosesocket() was
|
|
called; sockets which have been closed with WSPCloseSocket() but which
|
|
still have pending data to be sent are not affected--the pending data is
|
|
still sent.
|
|
|
|
This routine should not return until the service provider DLL is
|
|
prepared to be unloaded from memory. In particular, any data remaining
|
|
to be transmitted must either already have been sent or be queued for
|
|
transmission by portions of the transport stack that will not be unloaded
|
|
from memory along with the service provider's DLL.
|
|
|
|
A WinSock service provider must be prepared to deal with a process which
|
|
terminates without invoking WSPCleanup() - for example, as a result of an
|
|
error. A WinSock service provider must ensure that WSPCleanup() leaves
|
|
things in a state in which the WinSock 2 DLL can immediately invoke
|
|
WSPStartup() to re-establish WinSock usage.
|
|
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PSOCKET_INFORMATION socketInfo;
|
|
LINGER lingerInfo;
|
|
PLIST_ENTRY listEntry;
|
|
LONG startupCount;
|
|
INT err;
|
|
|
|
SOCK_ENTER( "WSPCleanup", NULL, NULL, NULL, NULL );
|
|
|
|
SOCK_ASSERT( lpErrno != NULL );
|
|
|
|
err = SockEnterApi( TRUE, FALSE );
|
|
|
|
if( err != NO_ERROR ) {
|
|
|
|
SOCK_EXIT( "WSPCleanup", SOCKET_ERROR, TRUE );
|
|
*lpErrno = err;
|
|
return SOCKET_ERROR;
|
|
|
|
}
|
|
|
|
//
|
|
// Decrement the reference count.
|
|
//
|
|
|
|
startupCount = InterlockedDecrement( &SockWspStartupCount );
|
|
|
|
//
|
|
// If the count of calls to WSPStartup() is not 0, we shouldn't do
|
|
// cleanup yet. Just return.
|
|
//
|
|
|
|
if( startupCount != 0 ) {
|
|
|
|
IF_DEBUG(MISC) {
|
|
|
|
SOCK_PRINT(( "Leaving WSPCleanup().\n" ));
|
|
|
|
}
|
|
|
|
SOCK_EXIT( "WSPCleanup", NO_ERROR, FALSE );
|
|
return NO_ERROR;
|
|
|
|
}
|
|
|
|
//
|
|
// Indicate that the DLL is no longer initialized. This will
|
|
// result in all open sockets being abortively disconnected.
|
|
//
|
|
|
|
SockTerminating = TRUE;;
|
|
|
|
//
|
|
// Close each open socket. We loop looking for open sockets until
|
|
// all sockets are either off the list of in the closing state.
|
|
//
|
|
|
|
SockAcquireGlobalLock();
|
|
|
|
for( listEntry = SockGlobalSocketListHead.Flink ;
|
|
listEntry != &SockGlobalSocketListHead ; ) {
|
|
|
|
SOCKET socketHandle;
|
|
int errTmp;
|
|
|
|
socketInfo = CONTAINING_RECORD(
|
|
listEntry,
|
|
SOCKET_INFORMATION,
|
|
SocketListEntry
|
|
);
|
|
|
|
//
|
|
// If this socket is about to close, go on to the next socket.
|
|
//
|
|
|
|
if( socketInfo->State == SocketStateClosing ) {
|
|
|
|
listEntry = listEntry->Flink;
|
|
continue;
|
|
|
|
}
|
|
|
|
//
|
|
// Pull the handle into a local in case another thread closes
|
|
// this socket just as we are trying to close it.
|
|
//
|
|
|
|
socketHandle = socketInfo->WS2Handle;
|
|
|
|
//
|
|
// Release the global lock so that we don't cause a deadlock
|
|
// from out-of-order lock acquisitions.
|
|
//
|
|
|
|
SockReleaseGlobalLock();
|
|
|
|
//
|
|
// Set each socket to linger for 0 seconds. This will cause
|
|
// the connection to reset, if appropriate, when we close the
|
|
// socket. If the setsockopt() fails, press on regardless.
|
|
//
|
|
|
|
lingerInfo.l_onoff = 1;
|
|
lingerInfo.l_linger = 0;
|
|
|
|
WSPSetSockOpt(
|
|
socketHandle,
|
|
SOL_SOCKET,
|
|
SO_LINGER,
|
|
(char *)&lingerInfo,
|
|
sizeof(lingerInfo),
|
|
&errTmp
|
|
);
|
|
|
|
//
|
|
// Perform the actual close of the socket.
|
|
//
|
|
|
|
WSPCloseSocket( socketHandle, &errTmp );
|
|
|
|
SockAcquireGlobalLock();
|
|
|
|
//
|
|
// Restart the search from the beginning of the list. We cannot
|
|
// use listEntry->Flink because the socket that is pointed to by
|
|
// listEntry may have been freed.
|
|
//
|
|
|
|
listEntry = SockGlobalSocketListHead.Flink;
|
|
|
|
}
|
|
|
|
SockReleaseGlobalLock();
|
|
|
|
//
|
|
// Free hooker info structures.
|
|
//
|
|
|
|
SockFreeAllHookers();
|
|
|
|
IF_DEBUG(MISC) {
|
|
|
|
SOCK_PRINT(( "Leaving WSPCleanup().\n" ));
|
|
|
|
}
|
|
|
|
SOCK_EXIT( "WSPCleanup", NO_ERROR, FALSE );
|
|
return NO_ERROR;
|
|
|
|
} // WSPCleanup
|
|
|