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.
296 lines
9.9 KiB
296 lines
9.9 KiB
/*++
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
spi.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the necessary "glue" for plugging into the
|
|
WinSock 2.0 Service Provider Interface.
|
|
|
|
Author:
|
|
|
|
Keith Moore (keithmo) 6-Oct-1995
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "winsockp.h"
|
|
|
|
|
|
//
|
|
// 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;
|
|
|
|
WS_ENTER( "WSPStartup", (PVOID)wVersionRequested, lpWSPData, (PVOID)&UpcallTable, NULL );
|
|
|
|
WS_ASSERT( lpWSPData != NULL );
|
|
|
|
err = SockEnterApi( FALSE, TRUE, FALSE );
|
|
|
|
if( err != NO_ERROR ) {
|
|
|
|
WS_EXIT( "WSPStartup", err, TRUE );
|
|
return err;
|
|
|
|
}
|
|
|
|
//
|
|
// Check the version number.
|
|
//
|
|
|
|
if ( SockWspStartupCount == 0 &&
|
|
wVersionRequested != SPI_VERSION ) {
|
|
|
|
WS_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 Version 2."
|
|
);
|
|
|
|
//
|
|
// Save the upcall table.
|
|
//
|
|
// !!! SPECBUGBUG: The upcall table should be passed by reference,
|
|
// *not* by value!
|
|
//
|
|
|
|
SockUpcallTableHack = UpcallTable;
|
|
SockUpcallTable = &SockUpcallTableHack;
|
|
|
|
//
|
|
// Return our proc table to the DLL.
|
|
//
|
|
|
|
*lpProcTable = SockProcTable;
|
|
|
|
//
|
|
// Cleanup & exit.
|
|
//
|
|
|
|
SockTerminating = FALSE;
|
|
|
|
WS_EXIT( "WSPStartup", NO_ERROR, FALSE );
|
|
return NO_ERROR;
|
|
|
|
} // WSPStartup
|
|
|