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.
1062 lines
29 KiB
1062 lines
29 KiB
/*++
|
|
|
|
Copyright (c) 1992-1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
helper.c
|
|
|
|
Abstract:
|
|
|
|
This module contains routines for interacting and handling helper
|
|
DLLs in the winsock DLL.
|
|
|
|
Author:
|
|
|
|
David Treadwell (davidtr) 25-Jul-1992
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#define UNICODE
|
|
|
|
#include "winsockp.h"
|
|
|
|
#include <ctype.h>
|
|
#include <stdarg.h>
|
|
#include <wincon.h>
|
|
|
|
#undef RegOpenKey
|
|
#undef RegOpenKeyEx
|
|
#undef RegQueryValue
|
|
#undef RegQueryValueEx
|
|
|
|
|
|
VOID
|
|
SockFreeHelperDlls (
|
|
VOID
|
|
)
|
|
{
|
|
|
|
PLIST_ENTRY listEntry;
|
|
PWINSOCK_HELPER_DLL_INFO helperDll;
|
|
|
|
//
|
|
// Note that we assume that no other threads are operating while
|
|
// we perform this operation.
|
|
//
|
|
|
|
while ( !IsListEmpty( &SockHelperDllListHead ) ) {
|
|
|
|
listEntry = RemoveHeadList( &SockHelperDllListHead );
|
|
helperDll = CONTAINING_RECORD(
|
|
listEntry,
|
|
WINSOCK_HELPER_DLL_INFO,
|
|
HelperDllListEntry
|
|
);
|
|
|
|
FreeLibrary( helperDll->DllHandle );
|
|
FREE_HEAP( helperDll->Mapping );
|
|
FREE_HEAP( helperDll );
|
|
}
|
|
|
|
return;
|
|
|
|
} // SockFreeHelperDlls
|
|
|
|
|
|
INT
|
|
SockGetTdiName (
|
|
IN PINT AddressFamily,
|
|
IN PINT SocketType,
|
|
IN PINT Protocol,
|
|
IN GROUP Group,
|
|
IN DWORD Flags,
|
|
OUT PUNICODE_STRING TransportDeviceName,
|
|
OUT PVOID *HelperDllSocketContext,
|
|
OUT PWINSOCK_HELPER_DLL_INFO *HelperDll,
|
|
OUT PDWORD NotificationEvents
|
|
)
|
|
{
|
|
PLIST_ENTRY listEntry;
|
|
PWINSOCK_HELPER_DLL_INFO helperDll;
|
|
INT error;
|
|
BOOLEAN addressFamilyFound = FALSE;
|
|
BOOLEAN socketTypeFound = FALSE;
|
|
BOOLEAN protocolFound = FALSE;
|
|
BOOLEAN invalidProtocolMatch = FALSE;
|
|
PWSTR transportList;
|
|
PWSTR currentTransport;
|
|
PWINSOCK_MAPPING mapping;
|
|
|
|
//
|
|
// Acquire the global sockets lock and search the list of helper
|
|
// DLLs for one which supports this combination of address family,
|
|
// socket type, and protocol.
|
|
//
|
|
|
|
SockAcquireGlobalLockExclusive( );
|
|
|
|
for ( listEntry = SockHelperDllListHead.Flink;
|
|
listEntry != &SockHelperDllListHead;
|
|
listEntry = listEntry->Flink ) {
|
|
|
|
|
|
helperDll = CONTAINING_RECORD(
|
|
listEntry,
|
|
WINSOCK_HELPER_DLL_INFO,
|
|
HelperDllListEntry
|
|
);
|
|
|
|
IF_DEBUG(HELPER_DLL) {
|
|
WS_PRINT(( "SockGetTdiName: examining DLL at %lx for AF %ld, "
|
|
"ST %ld, Proto %ld\n", helperDll, AddressFamily,
|
|
SocketType, Protocol ));
|
|
}
|
|
|
|
//
|
|
// Check to see whether the DLL supports the socket we're
|
|
// opening.
|
|
//
|
|
if ( SockIsTripleInMapping(
|
|
helperDll->Mapping,
|
|
*AddressFamily,
|
|
&addressFamilyFound,
|
|
*SocketType,
|
|
&socketTypeFound,
|
|
*Protocol,
|
|
&protocolFound,
|
|
&invalidProtocolMatch ) ) {
|
|
|
|
//
|
|
// Found a match. Try to use this DLL.
|
|
//
|
|
|
|
if( helperDll->WSHOpenSocket2 == NULL ) {
|
|
|
|
//
|
|
// This helper doesn't support the new WinSock 2
|
|
// WSHOpenSocket2 entrypoint. If the application is
|
|
// creating a "normal" socket, then just call through
|
|
// to the old WinSock 1 WSHOpenSocket entrypoint.
|
|
// Otherwise, fail the call.
|
|
//
|
|
|
|
if( ( Flags & ALL_MULTIPOINT_FLAGS ) == 0 ) {
|
|
|
|
error = helperDll->WSHOpenSocket(
|
|
AddressFamily,
|
|
SocketType,
|
|
Protocol,
|
|
TransportDeviceName,
|
|
HelperDllSocketContext,
|
|
NotificationEvents
|
|
);
|
|
|
|
} else {
|
|
|
|
error = WSAEINVAL;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
error = helperDll->WSHOpenSocket2(
|
|
AddressFamily,
|
|
SocketType,
|
|
Protocol,
|
|
Group,
|
|
Flags,
|
|
TransportDeviceName,
|
|
HelperDllSocketContext,
|
|
NotificationEvents
|
|
);
|
|
|
|
}
|
|
|
|
if ( error == NO_ERROR ) {
|
|
|
|
IF_DEBUG(HELPER_DLL) {
|
|
WS_PRINT(( "WSHOpenSocket by DLL at %lx succeeded, "
|
|
"context = %lx\n", helperDll,
|
|
*HelperDllSocketContext ));
|
|
}
|
|
|
|
//
|
|
// The DLL accepted the socket. Return a pointer to the
|
|
// helper DLL info.
|
|
//
|
|
|
|
SockReleaseGlobalLock( );
|
|
|
|
*HelperDll = helperDll;
|
|
return NO_ERROR;
|
|
}
|
|
|
|
if ( (*SocketType == SOCK_RAW) &&
|
|
(TransportDeviceName->Buffer != NULL)
|
|
)
|
|
{
|
|
RtlFreeHeap( RtlProcessHeap(), 0, TransportDeviceName->Buffer );
|
|
TransportDeviceName->Buffer = NULL;
|
|
}
|
|
|
|
//
|
|
// The open failed. Continue searching for a matching DLL.
|
|
//
|
|
|
|
IF_DEBUG(HELPER_DLL) {
|
|
WS_PRINT(( "WSHOpenSocket by DLL %lx failed: %ld\n",
|
|
helperDll, error ));
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// We don't have any loaded DLLs that can accept this socket.
|
|
// Attempt to find a DLL in the registry that can handle the
|
|
// specified triple. First get the REG_MULTI_SZ that contains the
|
|
// list of transports that have winsock support.
|
|
//
|
|
error = SockLoadTransportList( &transportList );
|
|
if ( error != NO_ERROR ) {
|
|
SockReleaseGlobalLock( );
|
|
return error;
|
|
}
|
|
|
|
//
|
|
// Loop through the transports looking for one which will support
|
|
// the socket we're opening.
|
|
//
|
|
|
|
for ( currentTransport = transportList;
|
|
*currentTransport != UNICODE_NULL;
|
|
currentTransport += wcslen( currentTransport ) + 1 ) {
|
|
|
|
//
|
|
// Load the list of triples supported by this transport.
|
|
//
|
|
|
|
error = SockLoadTransportMapping( currentTransport, &mapping );
|
|
if ( error != NO_ERROR ) {
|
|
WS_PRINT((
|
|
"SockLoadTransportMapping( %ws ) failed: %ld\n",
|
|
currentTransport,
|
|
error
|
|
));
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Determine whether the triple of the socket we're opening is
|
|
// in this transport's mapping.
|
|
//
|
|
|
|
if ( SockIsTripleInMapping(
|
|
mapping,
|
|
*AddressFamily,
|
|
&addressFamilyFound,
|
|
*SocketType,
|
|
&socketTypeFound,
|
|
*Protocol,
|
|
&protocolFound,
|
|
&invalidProtocolMatch ) ) {
|
|
|
|
//
|
|
// The triple is supported. Load the helper DLL for the
|
|
// transport.
|
|
//
|
|
|
|
error = SockLoadHelperDll( currentTransport, mapping, &helperDll );
|
|
|
|
//
|
|
// If we couldn't load the DLL, continue looking for a helper
|
|
// DLL that will support this triple.
|
|
//
|
|
|
|
if ( error == NO_ERROR ) {
|
|
|
|
//
|
|
// We successfully loaded a helper DLL that claims to
|
|
// support this socket's triple. Get the TDI device
|
|
// name for the triple.
|
|
//
|
|
|
|
error = helperDll->WSHOpenSocket(
|
|
AddressFamily,
|
|
SocketType,
|
|
Protocol,
|
|
TransportDeviceName,
|
|
HelperDllSocketContext,
|
|
NotificationEvents
|
|
);
|
|
|
|
if ( error == NO_ERROR ) {
|
|
|
|
IF_DEBUG(HELPER_DLL) {
|
|
WS_PRINT(( "WSHOpenSocket by DLL at %lx succeeded, "
|
|
"context = %lx\n", helperDll,
|
|
*HelperDllSocketContext ));
|
|
}
|
|
|
|
//
|
|
// The DLL accepted the socket. Free resources and
|
|
// return a pointer to the helper DLL info.
|
|
//
|
|
|
|
SockReleaseGlobalLock( );
|
|
FREE_HEAP( transportList );
|
|
|
|
*HelperDll = helperDll;
|
|
return NO_ERROR;
|
|
}
|
|
|
|
//
|
|
// The open failed. Continue searching for a matching DLL.
|
|
//
|
|
|
|
IF_DEBUG(HELPER_DLL) {
|
|
WS_PRINT(( "WSHOpenSocket by DLL %lx failed: %ld\n",
|
|
helperDll, error ));
|
|
}
|
|
|
|
if ( (*SocketType == SOCK_RAW) &&
|
|
(TransportDeviceName->Buffer != NULL)
|
|
)
|
|
{
|
|
RtlFreeHeap(
|
|
RtlProcessHeap(),
|
|
0,
|
|
TransportDeviceName->Buffer
|
|
);
|
|
TransportDeviceName->Buffer = NULL;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
}
|
|
|
|
//
|
|
// This transport does not support the socket we're opening.
|
|
// Free the memory that held the mapping and try the next
|
|
// transport in the list.
|
|
//
|
|
|
|
FREE_HEAP( mapping );
|
|
}
|
|
|
|
SockReleaseGlobalLock( );
|
|
|
|
//
|
|
// We didn't find any matches. Return an error based on the matches that
|
|
// did occur.
|
|
//
|
|
|
|
if ( invalidProtocolMatch ) {
|
|
return WSAEPROTOTYPE;
|
|
}
|
|
|
|
if ( !addressFamilyFound ) {
|
|
return WSAEAFNOSUPPORT;
|
|
}
|
|
|
|
if ( !socketTypeFound ) {
|
|
return WSAESOCKTNOSUPPORT;
|
|
}
|
|
|
|
if ( !protocolFound ) {
|
|
return WSAEPROTONOSUPPORT;
|
|
}
|
|
|
|
//
|
|
// All the individual numbers were found, it is just the particular
|
|
// combination that was invalid.
|
|
//
|
|
|
|
return WSAEINVAL;
|
|
|
|
} // SockGetTdiName
|
|
|
|
|
|
INT
|
|
SockLoadTransportMapping (
|
|
IN PWSTR TransportName,
|
|
OUT PWINSOCK_MAPPING *Mapping
|
|
)
|
|
{
|
|
PWSTR winsockKeyName;
|
|
HKEY winsockKey;
|
|
INT error;
|
|
ULONG mappingLength;
|
|
ULONG type;
|
|
|
|
//
|
|
// Allocate space to hold the winsock key name for the transport
|
|
// we're accessing.
|
|
//
|
|
|
|
winsockKeyName = ALLOCATE_HEAP( DOS_MAX_PATH_LENGTH*sizeof(WCHAR) );
|
|
if ( winsockKeyName == NULL ) {
|
|
// IF_DEBUG(HELPER_DLL)
|
|
{
|
|
WS_PRINT(( "SockLoadTransportMapping: ALLOCATE_HEAP(1) failed: %ld\n",
|
|
GetLastError() ));
|
|
}
|
|
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
//
|
|
// Build the name of the transport's winsock key.
|
|
//
|
|
|
|
wcscpy( winsockKeyName, L"System\\CurrentControlSet\\Services\\" );
|
|
wcscat( winsockKeyName, TransportName );
|
|
wcscat( winsockKeyName, L"\\Parameters\\Winsock" );
|
|
|
|
//
|
|
// Open the transport's winsock key. This key holds all necessary
|
|
// information about winsock should support the transport.
|
|
//
|
|
|
|
error = RegOpenKeyExW(
|
|
HKEY_LOCAL_MACHINE,
|
|
winsockKeyName,
|
|
0,
|
|
KEY_READ,
|
|
&winsockKey
|
|
);
|
|
FREE_HEAP( winsockKeyName );
|
|
if ( error != NO_ERROR ) {
|
|
// IF_DEBUG(HELPER_DLL)
|
|
{
|
|
WS_PRINT(( "SockLoadTransportMapping: RegOpenKeyExW failed: %ld\n", error ));
|
|
}
|
|
return error;
|
|
}
|
|
|
|
//
|
|
// Determine the length of the mapping.
|
|
//
|
|
|
|
mappingLength = 0;
|
|
|
|
error = RegQueryValueExW(
|
|
winsockKey,
|
|
L"Mapping",
|
|
NULL,
|
|
&type,
|
|
NULL,
|
|
&mappingLength
|
|
);
|
|
if ( error != ERROR_MORE_DATA && error != NO_ERROR ) {
|
|
// IF_DEBUG(HELPER_DLL)
|
|
{
|
|
WS_PRINT(( "SockLoadTransportMapping: RegQueryValueEx(1) failed: %ld\n",
|
|
error ));
|
|
}
|
|
RegCloseKey( winsockKey );
|
|
return error;
|
|
}
|
|
|
|
WS_ASSERT( mappingLength >= sizeof(WINSOCK_MAPPING) );
|
|
//WS_ASSERT( type == REG_BINARY );
|
|
|
|
//
|
|
// Allocate enough memory to hold the mapping.
|
|
//
|
|
|
|
*Mapping = ALLOCATE_HEAP( mappingLength );
|
|
if ( *Mapping == NULL ) {
|
|
// IF_DEBUG(HELPER_DLL)
|
|
{
|
|
WS_PRINT(( "SockLoadTransportMapping: ALLOCATE_HEAP(2) failed: %ld\n",
|
|
GetLastError() ));
|
|
}
|
|
|
|
RegCloseKey( winsockKey );
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
//
|
|
// Get the mapping from the registry.
|
|
//
|
|
|
|
error = RegQueryValueExW(
|
|
winsockKey,
|
|
L"Mapping",
|
|
NULL,
|
|
&type,
|
|
(PVOID)*Mapping,
|
|
&mappingLength
|
|
);
|
|
if ( error != NO_ERROR ) {
|
|
// IF_DEBUG(HELPER_DLL)
|
|
{
|
|
WS_PRINT(( "SockLoadTransportMapping: RegQueryValueEx(2) failed: %ld\n",
|
|
error ));
|
|
}
|
|
RegCloseKey( winsockKey );
|
|
return error;
|
|
}
|
|
|
|
//
|
|
// It worked, return.
|
|
//
|
|
|
|
RegCloseKey( winsockKey );
|
|
|
|
return NO_ERROR;
|
|
|
|
} // SockLoadTransportMapping
|
|
|
|
|
|
BOOL
|
|
SockIsTripleInMapping (
|
|
IN PWINSOCK_MAPPING Mapping,
|
|
IN INT AddressFamily,
|
|
OUT PBOOLEAN AddressFamilyFound,
|
|
IN INT SocketType,
|
|
OUT PBOOLEAN SocketTypeFound,
|
|
IN INT Protocol,
|
|
OUT PBOOLEAN ProtocolFound,
|
|
OUT PBOOLEAN InvalidProtocolMatch
|
|
)
|
|
{
|
|
ULONG i;
|
|
BOOLEAN addressFamilyFound = FALSE;
|
|
BOOLEAN socketTypeFound = FALSE;
|
|
BOOLEAN protocolFound = FALSE;
|
|
|
|
//
|
|
// Loop through the mapping attempting to find an exact match of
|
|
// the triple.
|
|
//
|
|
|
|
for ( i = 0; i < Mapping->Rows; i++ ) {
|
|
//
|
|
// Remember if any of the individual elements were found.
|
|
//
|
|
|
|
if ( (INT)Mapping->Mapping[i].AddressFamily == AddressFamily ) {
|
|
addressFamilyFound = TRUE;
|
|
}
|
|
|
|
if ( (INT)Mapping->Mapping[i].SocketType == SocketType ) {
|
|
socketTypeFound = TRUE;
|
|
}
|
|
|
|
//
|
|
// Special hack for AF_NETBIOS: the protocol does not have to
|
|
// match. This allows for support of multiple lanas.
|
|
//
|
|
// Same hack for SOCK_RAW - any protocol will do.
|
|
//
|
|
|
|
if ( (INT)Mapping->Mapping[i].Protocol == Protocol ||
|
|
AddressFamily == AF_NETBIOS || SocketType == SOCK_RAW
|
|
)
|
|
{
|
|
protocolFound = TRUE;
|
|
}
|
|
|
|
if ( addressFamilyFound && socketTypeFound && !protocolFound ) {
|
|
*InvalidProtocolMatch = TRUE;
|
|
}
|
|
|
|
//
|
|
// Check for a full match.
|
|
//
|
|
|
|
if ( addressFamilyFound && socketTypeFound && protocolFound ) {
|
|
|
|
//
|
|
// The triple matched. Return.
|
|
//
|
|
|
|
*AddressFamilyFound = TRUE;
|
|
*SocketTypeFound = TRUE;
|
|
*ProtocolFound = TRUE;
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// No triple matched completely.
|
|
//
|
|
|
|
if ( addressFamilyFound ) {
|
|
*AddressFamilyFound = TRUE;
|
|
}
|
|
|
|
if ( socketTypeFound ) {
|
|
*SocketTypeFound = TRUE;
|
|
}
|
|
|
|
if ( protocolFound ) {
|
|
*ProtocolFound = TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
} // SockIsTripleInMapping
|
|
|
|
|
|
INT
|
|
SockLoadHelperDll (
|
|
IN PWSTR TransportName,
|
|
IN PWINSOCK_MAPPING Mapping,
|
|
OUT PWINSOCK_HELPER_DLL_INFO *HelperDll
|
|
)
|
|
{
|
|
PWINSOCK_HELPER_DLL_INFO helperDll;
|
|
PWSTR helperDllName;
|
|
PWSTR helperDllExpandedName;
|
|
DWORD helperDllExpandedNameLength;
|
|
PWSTR winsockKeyName;
|
|
HKEY winsockKey;
|
|
ULONG entryLength;
|
|
ULONG type;
|
|
INT error;
|
|
|
|
//
|
|
// Allocate some memory to cache information about the helper DLL,
|
|
// the helper DLL's name, and the name of the transport's winsock
|
|
// key.
|
|
//
|
|
|
|
helperDll = ALLOCATE_HEAP( sizeof(*helperDll) );
|
|
if ( helperDll == NULL ) {
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
helperDllName = ALLOCATE_HEAP( DOS_MAX_PATH_LENGTH*sizeof(WCHAR) );
|
|
if ( helperDllName == NULL ) {
|
|
FREE_HEAP( helperDll );
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
helperDllExpandedName = ALLOCATE_HEAP( DOS_MAX_PATH_LENGTH*sizeof(WCHAR) );
|
|
if ( helperDllExpandedName == NULL ) {
|
|
FREE_HEAP( helperDll );
|
|
FREE_HEAP( helperDllName );
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
winsockKeyName = ALLOCATE_HEAP( DOS_MAX_PATH_LENGTH*sizeof(WCHAR) );
|
|
if ( winsockKeyName == NULL ) {
|
|
FREE_HEAP( helperDll );
|
|
FREE_HEAP( helperDllName );
|
|
FREE_HEAP( helperDllExpandedName );
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
//
|
|
// Build the name of the transport's winsock key.
|
|
//
|
|
|
|
wcscpy( winsockKeyName, L"System\\CurrentControlSet\\Services\\" );
|
|
wcscat( winsockKeyName, TransportName );
|
|
wcscat( winsockKeyName, L"\\Parameters\\Winsock" );
|
|
|
|
//
|
|
// Open the transport's winsock key. This key holds all necessary
|
|
// information about winsock should support the transport.
|
|
//
|
|
|
|
error = RegOpenKeyExW(
|
|
HKEY_LOCAL_MACHINE,
|
|
winsockKeyName,
|
|
0,
|
|
KEY_READ,
|
|
&winsockKey
|
|
);
|
|
FREE_HEAP( winsockKeyName );
|
|
if ( error != NO_ERROR ) {
|
|
IF_DEBUG(HELPER_DLL) {
|
|
WS_PRINT(( "SockLoadHelperDll: RegOpenKeyExW failed: %ld\n", error ));
|
|
}
|
|
FREE_HEAP( helperDll );
|
|
FREE_HEAP( helperDllName );
|
|
FREE_HEAP( helperDllExpandedName );
|
|
return error;
|
|
}
|
|
|
|
//
|
|
// Read the minimum and maximum sockaddr lengths from the registry.
|
|
//
|
|
|
|
entryLength = sizeof(helperDll->MaxSockaddrLength);
|
|
|
|
error = RegQueryValueExW(
|
|
winsockKey,
|
|
L"MinSockaddrLength",
|
|
NULL,
|
|
&type,
|
|
(PVOID)&helperDll->MinSockaddrLength,
|
|
&entryLength
|
|
);
|
|
if ( error != NO_ERROR ) {
|
|
IF_DEBUG(HELPER_DLL) {
|
|
WS_PRINT(( "SockLoadHelperDll: RegQueryValueExW(min) failed: %ld\n",
|
|
error ));
|
|
}
|
|
FREE_HEAP( helperDll );
|
|
FREE_HEAP( helperDllName );
|
|
FREE_HEAP( helperDllExpandedName );
|
|
RegCloseKey( winsockKey );
|
|
return error;
|
|
}
|
|
|
|
WS_ASSERT( entryLength == sizeof(helperDll->MaxSockaddrLength) );
|
|
WS_ASSERT( type == REG_DWORD );
|
|
|
|
entryLength = sizeof(helperDll->MaxSockaddrLength);
|
|
|
|
error = RegQueryValueExW(
|
|
winsockKey,
|
|
L"MaxSockaddrLength",
|
|
NULL,
|
|
&type,
|
|
(PVOID)&helperDll->MaxSockaddrLength,
|
|
&entryLength
|
|
);
|
|
if ( error != NO_ERROR ) {
|
|
IF_DEBUG(HELPER_DLL) {
|
|
WS_PRINT(( "SockLoadHelperDll: RegQueryValueExW(max) failed: %ld\n",
|
|
error ));
|
|
}
|
|
FREE_HEAP( helperDll );
|
|
FREE_HEAP( helperDllName );
|
|
FREE_HEAP( helperDllExpandedName );
|
|
RegCloseKey( winsockKey );
|
|
return error;
|
|
}
|
|
|
|
WS_ASSERT( entryLength == sizeof(helperDll->MaxSockaddrLength) );
|
|
WS_ASSERT( type == REG_DWORD );
|
|
|
|
helperDll->MinTdiAddressLength = helperDll->MinSockaddrLength + 6;
|
|
helperDll->MaxTdiAddressLength = helperDll->MaxSockaddrLength + 6;
|
|
|
|
//
|
|
// Get the name of the helper DLL that this transport uses.
|
|
//
|
|
|
|
entryLength = DOS_MAX_PATH_LENGTH*sizeof(WCHAR);
|
|
|
|
error = RegQueryValueExW(
|
|
winsockKey,
|
|
L"HelperDllName",
|
|
NULL,
|
|
&type,
|
|
(PVOID)helperDllName,
|
|
&entryLength
|
|
);
|
|
if ( error != NO_ERROR ) {
|
|
IF_DEBUG(HELPER_DLL) {
|
|
WS_PRINT(( "SockLoadHelperDll: RegQueryValueExW failed: %ld\n",
|
|
error ));
|
|
}
|
|
FREE_HEAP( helperDll );
|
|
FREE_HEAP( helperDllName );
|
|
FREE_HEAP( helperDllExpandedName );
|
|
RegCloseKey( winsockKey );
|
|
return error;
|
|
}
|
|
WS_ASSERT( type == REG_EXPAND_SZ );
|
|
|
|
//
|
|
// Expand the name of the DLL, converting environment variables to
|
|
// their corresponding strings.
|
|
//
|
|
|
|
helperDllExpandedNameLength = ExpandEnvironmentStringsW(
|
|
helperDllName,
|
|
helperDllExpandedName,
|
|
DOS_MAX_PATH_LENGTH*sizeof(WCHAR)
|
|
);
|
|
WS_ASSERT( helperDllExpandedNameLength <= DOS_MAX_PATH_LENGTH*sizeof(WCHAR) );
|
|
FREE_HEAP( helperDllName );
|
|
|
|
//
|
|
// Load the helper DLL so that we can get at it's entry points.
|
|
//
|
|
|
|
IF_DEBUG(HELPER_DLL) {
|
|
WS_PRINT(( "SockLoadHelperDll: loading helper DLL %ws\n",
|
|
helperDllExpandedName ));
|
|
}
|
|
|
|
helperDll->DllHandle = LoadLibraryW( helperDllExpandedName );
|
|
FREE_HEAP( helperDllExpandedName );
|
|
if ( helperDll->DllHandle == NULL ) {
|
|
IF_DEBUG(HELPER_DLL) {
|
|
WS_PRINT(( "SockLoadHelperDll: LoadLibrary failed: %ld\n",
|
|
GetLastError( ) ));
|
|
}
|
|
FREE_HEAP( helperDll );
|
|
RegCloseKey( winsockKey );
|
|
return GetLastError( );;
|
|
}
|
|
|
|
RegCloseKey( winsockKey );
|
|
|
|
//
|
|
// Get the addresses of the entry points for the relevant helper DLL
|
|
// routines.
|
|
//
|
|
|
|
helperDll->WSHOpenSocket =
|
|
(PWSH_OPEN_SOCKET)GetProcAddress( helperDll->DllHandle, "WSHOpenSocket" );
|
|
helperDll->WSHOpenSocket2 =
|
|
(PWSH_OPEN_SOCKET2)GetProcAddress( helperDll->DllHandle, "WSHOpenSocket2" );
|
|
if ( helperDll->WSHOpenSocket == NULL && helperDll->WSHOpenSocket2 == NULL ) {
|
|
IF_DEBUG(HELPER_DLL) {
|
|
WS_PRINT(( "SockLoadHelperDll: GetProcAddress for "
|
|
"WSHOpenSocket failed: %ld\n", GetLastError( ) ));
|
|
}
|
|
FreeLibrary( helperDll->DllHandle );
|
|
FREE_HEAP( helperDll );
|
|
return GetLastError( );;
|
|
}
|
|
|
|
helperDll->WSHJoinLeaf =
|
|
(PWSH_JOIN_LEAF)GetProcAddress( helperDll->DllHandle, "WSHJoinLeaf" );
|
|
if ( helperDll->WSHJoinLeaf == NULL ) {
|
|
IF_DEBUG(HELPER_DLL) {
|
|
WS_PRINT(( "SockLoadHelperDll: GetProcAddress for "
|
|
"WSHJoinLeaf failed: %ld (continuing)\n", GetLastError( ) ));
|
|
}
|
|
|
|
//
|
|
// It is OK if WSHJoinLeaf() is not present--it just
|
|
// means that this helper DLL does not support multipoint.
|
|
//
|
|
}
|
|
|
|
helperDll->WSHNotify =
|
|
(PWSH_NOTIFY)GetProcAddress( helperDll->DllHandle, "WSHNotify" );
|
|
if ( helperDll->WSHNotify == NULL ) {
|
|
IF_DEBUG(HELPER_DLL) {
|
|
WS_PRINT(( "SockLoadHelperDll: GetProcAddress for "
|
|
"WSHNotify failed: %ld\n", GetLastError( ) ));
|
|
}
|
|
FreeLibrary( helperDll->DllHandle );
|
|
FREE_HEAP( helperDll );
|
|
return GetLastError( );;
|
|
}
|
|
|
|
helperDll->WSHGetSocketInformation =
|
|
(PWSH_GET_SOCKET_INFORMATION)GetProcAddress( helperDll->DllHandle, "WSHGetSocketInformation" );
|
|
if ( helperDll->WSHGetSocketInformation == NULL ) {
|
|
IF_DEBUG(HELPER_DLL) {
|
|
WS_PRINT(( "SockLoadHelperDll: GetProcAddress for "
|
|
"WSHGetSocketInformation failed: %ld\n", GetLastError( ) ));
|
|
}
|
|
FreeLibrary( helperDll->DllHandle );
|
|
FREE_HEAP( helperDll );
|
|
return GetLastError( );;
|
|
}
|
|
|
|
helperDll->WSHSetSocketInformation =
|
|
(PWSH_SET_SOCKET_INFORMATION)GetProcAddress( helperDll->DllHandle, "WSHSetSocketInformation" );
|
|
if ( helperDll->WSHSetSocketInformation == NULL ) {
|
|
IF_DEBUG(HELPER_DLL) {
|
|
WS_PRINT(( "SockLoadHelperDll: GetProcAddress for "
|
|
"WSHSetSocketInformation failed: %ld\n", GetLastError( ) ));
|
|
}
|
|
FreeLibrary( helperDll->DllHandle );
|
|
FREE_HEAP( helperDll );
|
|
return GetLastError( );;
|
|
}
|
|
|
|
helperDll->WSHGetSockaddrType =
|
|
(PWSH_GET_SOCKADDR_TYPE)GetProcAddress( helperDll->DllHandle, "WSHGetSockaddrType" );
|
|
if ( helperDll->WSHGetSockaddrType == NULL ) {
|
|
IF_DEBUG(HELPER_DLL) {
|
|
WS_PRINT(( "SockLoadHelperDll: GetProcAddress for "
|
|
"WSHGetSockaddrType failed: %ld\n", GetLastError( ) ));
|
|
}
|
|
FreeLibrary( helperDll->DllHandle );
|
|
FREE_HEAP( helperDll );
|
|
return GetLastError( );;
|
|
}
|
|
|
|
helperDll->WSHGetWildcardSockaddr =
|
|
(PWSH_GET_WILDCARD_SOCKADDR)GetProcAddress( helperDll->DllHandle, "WSHGetWildcardSockaddr" );
|
|
if ( helperDll->WSHGetWildcardSockaddr == NULL ) {
|
|
IF_DEBUG(HELPER_DLL) {
|
|
WS_PRINT(( "SockLoadHelperDll: GetProcAddress for "
|
|
"WSHGetWildcardAddress failed: %ld (continuing)\n", GetLastError( ) ));
|
|
}
|
|
|
|
//
|
|
// It is OK if WSHGetWildcardSockaddr() is not present--it just
|
|
// means that this helper DLL does not support autobind.
|
|
//
|
|
}
|
|
|
|
helperDll->WSHGetBroadcastSockaddr =
|
|
(PWSH_GET_BROADCAST_SOCKADDR)GetProcAddress( helperDll->DllHandle, "WSHGetBroadcastSockaddr" );
|
|
if ( helperDll->WSHGetBroadcastSockaddr == NULL ) {
|
|
IF_DEBUG(HELPER_DLL) {
|
|
WS_PRINT(( "SockLoadHelperDll: GetProcAddress for "
|
|
"WSHGetBroadcastAddress failed: %ld (continuing)\n", GetLastError( ) ));
|
|
}
|
|
|
|
//
|
|
// It is OK if WSHGetBroadcastSockaddr() is not present--it just
|
|
// means that SIO_GET_BROADCAST_ADDRESS will fail on sockets managed
|
|
// by this helper DLL.
|
|
//
|
|
}
|
|
|
|
helperDll->WSHAddressToString =
|
|
(PWSH_ADDRESS_TO_STRING)GetProcAddress( helperDll->DllHandle, "WSHAddressToString" );
|
|
if ( helperDll->WSHAddressToString == NULL ) {
|
|
IF_DEBUG(HELPER_DLL) {
|
|
WS_PRINT(( "SockLoadHelperDll: GetProcAddress for "
|
|
"WSHAddressToString failed: %ld (continuing)\n", GetLastError( ) ));
|
|
}
|
|
|
|
//
|
|
// It is OK if WSHAddressToString() is not present--it just
|
|
// means that this helper DLL does not support address conversions.
|
|
//
|
|
}
|
|
|
|
helperDll->WSHStringToAddress =
|
|
(PWSH_STRING_TO_ADDRESS)GetProcAddress( helperDll->DllHandle, "WSHStringToAddress" );
|
|
if ( helperDll->WSHStringToAddress == NULL ) {
|
|
IF_DEBUG(HELPER_DLL) {
|
|
WS_PRINT(( "SockLoadHelperDll: GetProcAddress for "
|
|
"WSHStringToAddress failed: %ld (continuing)\n", GetLastError( ) ));
|
|
}
|
|
|
|
//
|
|
// It is OK if WSHStringToAddress() is not present--it just
|
|
// means that this helper DLL does not support address conversions.
|
|
//
|
|
}
|
|
|
|
helperDll->WSHIoctl =
|
|
(PWSH_IOCTL)GetProcAddress( helperDll->DllHandle, "WSHIoctl" );
|
|
|
|
if( helperDll->WSHIoctl == NULL ) {
|
|
|
|
//
|
|
// It is OK if WSHIoctl is not present -- it just means that
|
|
// this helper DLL does not support nonstandard/extended
|
|
// IOCTL codes.
|
|
//
|
|
|
|
}
|
|
|
|
//
|
|
// Save a pointer to the mapping structure for use on future socket
|
|
// opens.
|
|
//
|
|
|
|
helperDll->Mapping = Mapping;
|
|
|
|
//
|
|
// The load of the helper DLL was successful. Place the caches
|
|
// information about the DLL in the process's global list. This
|
|
// list allows us to use the same helper DLL on future socket()
|
|
// calls without accessing the registry.
|
|
//
|
|
|
|
SockAcquireGlobalLockExclusive( );
|
|
InsertHeadList( &SockHelperDllListHead, &helperDll->HelperDllListEntry );
|
|
SockReleaseGlobalLock( );
|
|
|
|
*HelperDll = helperDll;
|
|
|
|
return NO_ERROR;
|
|
|
|
} // SockLoadHelperDll
|
|
|
|
|
|
INT
|
|
SockNotifyHelperDll (
|
|
IN PSOCKET_INFORMATION Socket,
|
|
IN DWORD Event
|
|
)
|
|
{
|
|
INT error;
|
|
|
|
if ( (Socket->HelperDllNotificationEvents & Event) == 0 ) {
|
|
|
|
//
|
|
// The helper DLL does not care about this state transition.
|
|
// Just return.
|
|
//
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
if( Socket->HelperDllContext == NULL ) {
|
|
|
|
//
|
|
// There is no context associated with the socket, so just return.
|
|
//
|
|
|
|
return NO_ERROR;
|
|
|
|
}
|
|
|
|
//
|
|
// Get the TDI handles for the socket.
|
|
//
|
|
|
|
error = SockGetTdiHandles( Socket );
|
|
if ( error != NO_ERROR ) {
|
|
return error;
|
|
}
|
|
|
|
// !!! If we're terminating, don't do the notification. This is
|
|
// a hack because we don't have reference counts on helper DLL
|
|
// info structures. Post-beta, add helper DLL refcnts.
|
|
|
|
if ( SockTerminating ) {
|
|
return NO_ERROR;
|
|
}
|
|
|
|
//
|
|
// Call the help DLL's notification routine.
|
|
//
|
|
|
|
return Socket->HelperDll->WSHNotify(
|
|
Socket->HelperDllContext,
|
|
Socket->Handle,
|
|
Socket->TdiAddressHandle,
|
|
Socket->TdiConnectionHandle,
|
|
Event
|
|
);
|
|
|
|
} // SockNotifyHelperDll
|
|
|
|
BOOL
|
|
SockDefaultValidateAddressForConstrainedGroup(
|
|
IN PSOCKADDR Sockaddr1,
|
|
IN PSOCKADDR Sockaddr2,
|
|
IN INT SockaddrLength
|
|
)
|
|
{
|
|
|
|
//
|
|
// Just about the only thing we can do in a protocol indepenent manner
|
|
// is to blindly byte-compare the addresses.
|
|
//
|
|
|
|
return RtlEqualMemory(
|
|
Sockaddr1,
|
|
Sockaddr2,
|
|
SockaddrLength
|
|
);
|
|
|
|
} // SockDefaultValidateAddressForConstrainedGroup
|
|
|