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.
1169 lines
29 KiB
1169 lines
29 KiB
/*++
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
WshAtalk.c
|
|
|
|
Abstract:
|
|
|
|
This module contains necessary routines for the Appletalk Windows Sockets
|
|
Helper DLL. This DLL provides the transport-specific support necessary
|
|
for the Windows Sockets DLL to use Appletalk as a transport.
|
|
|
|
Author:
|
|
|
|
David Treadwell (davidtr) 19-Jul-1992 - TCP/IP version
|
|
Nikhil Kamkolkar (nikhilk) 17-Nov- 1992 - Appletalk version
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
|
|
#include <windef.h>
|
|
#include <winbase.h>
|
|
#include <tdi.h>
|
|
|
|
#include <winsock.h>
|
|
#include <wsahelp.h>
|
|
|
|
//
|
|
// MappingTriple structures and associated data for Appletalk
|
|
//
|
|
|
|
#include "wshatalk.h"
|
|
#include "wshdata.h"
|
|
|
|
|
|
|
|
//
|
|
// Forward declarations of internal routines.
|
|
//
|
|
|
|
BOOLEAN
|
|
IsTripleInList (
|
|
IN PMAPPING_TRIPLE List,
|
|
IN ULONG ListLength,
|
|
IN INT AddressFamily,
|
|
IN INT SocketType,
|
|
IN INT Protocol
|
|
);
|
|
|
|
//
|
|
// The socket context structure for this DLL. Each open Appletalk socket
|
|
// will have one of these context structures, which is used to maintain
|
|
// information about the socket.
|
|
//
|
|
|
|
typedef struct _WSHATALK_SOCKET_CONTEXT {
|
|
INT AddressFamily;
|
|
INT SocketType;
|
|
INT Protocol;
|
|
} WSHATALK_SOCKET_CONTEXT, *PWSHATALK_SOCKET_CONTEXT;
|
|
|
|
|
|
INT
|
|
WSHGetSockaddrType (
|
|
IN PSOCKADDR Sockaddr,
|
|
IN DWORD SockaddrLength,
|
|
OUT PSOCKADDR_INFO SockaddrInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine parses a sockaddr to determine the type of the
|
|
machine address and endpoint address portions of the sockaddr.
|
|
This is called by the winsock DLL whenever it needs to interpret
|
|
a sockaddr.
|
|
|
|
Arguments:
|
|
|
|
Sockaddr - a pointer to the sockaddr structure to evaluate.
|
|
|
|
SockaddrLength - the number of bytes in the sockaddr structure.
|
|
|
|
SockaddrInfo - a pointer to a structure that will receive information
|
|
about the specified sockaddr.
|
|
|
|
|
|
Return Value:
|
|
|
|
INT - a winsock error code indicating the status of the operation, or
|
|
NO_ERROR if the operation succeeded.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
UNALIGNED SOCKADDR_AT *sockaddr = (PSOCKADDR_AT)Sockaddr;
|
|
|
|
#if DBG
|
|
DbgPrint("In WSHGetSockAddrType\n");
|
|
#endif
|
|
|
|
//
|
|
// Make sure that the address family is correct.
|
|
//
|
|
|
|
if ( sockaddr->sat_family != AF_APPLETALK ) {
|
|
return WSAEAFNOSUPPORT;
|
|
}
|
|
|
|
//
|
|
// Make sure that the length is correct.
|
|
//
|
|
|
|
if ( SockaddrLength < sizeof(SOCKADDR_AT) ) {
|
|
return WSAEFAULT;
|
|
}
|
|
|
|
//
|
|
// The address passed the tests, looks like a good address.
|
|
// Determine the type of the address portion of the sockaddr.
|
|
//
|
|
|
|
if ( sockaddr->sat_socket == ATADDR_ANY ) {
|
|
SockaddrInfo->AddressInfo = SockaddrAddressInfoWildcard;
|
|
} else if ( sockaddr->sat_node == ATADDR_BROADCAST ) {
|
|
SockaddrInfo->AddressInfo = SockaddrAddressInfoBroadcast;
|
|
} else {
|
|
SockaddrInfo->AddressInfo = SockaddrAddressInfoNormal;
|
|
}
|
|
|
|
//
|
|
// Determine the type of the port (endpoint) in the sockaddr.
|
|
// BUGBUG: Include reserved sockets here?
|
|
//
|
|
|
|
if ( sockaddr->sat_socket == 0 ) {
|
|
SockaddrInfo->EndpointInfo = SockaddrEndpointInfoWildcard;
|
|
} else {
|
|
SockaddrInfo->EndpointInfo = SockaddrEndpointInfoNormal;
|
|
}
|
|
|
|
return NO_ERROR;
|
|
|
|
} // WSHGetSockaddrType
|
|
|
|
|
|
INT
|
|
WSHGetSocketInformation (
|
|
IN PVOID HelperDllSocketContext,
|
|
IN SOCKET SocketHandle,
|
|
IN HANDLE TdiAddressObjectHandle,
|
|
IN HANDLE TdiConnectionObjectHandle,
|
|
IN INT Level,
|
|
IN INT OptionName,
|
|
OUT PCHAR OptionValue,
|
|
OUT PINT OptionLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine retrieves information about a socket for those socket
|
|
options supported in this helper DLL. The options supported here
|
|
are SO_LOOKUPNAME/SO_LOOKUPZONES.
|
|
This routine is called by the winsock DLL when a level/option name
|
|
combination is passed to getsockopt() that the winsock DLL does not
|
|
understand.
|
|
|
|
Arguments:
|
|
|
|
HelperDllSocketContext - the context pointer returned from
|
|
WSHOpenSocket().
|
|
|
|
SocketHandle - the handle of the socket for which we're getting
|
|
information.
|
|
|
|
TdiAddressObjectHandle - the TDI address object of the socket, if
|
|
any. If the socket is not yet bound to an address, then
|
|
it does not have a TDI address object and this parameter
|
|
will be NULL.
|
|
|
|
TdiConnectionObjectHandle - the TDI connection object of the socket,
|
|
if any. If the socket is not yet connected, then it does not
|
|
have a TDI connection object and this parameter will be NULL.
|
|
|
|
Level - the level parameter passed to getsockopt().
|
|
|
|
OptionName - the optname parameter passed to getsockopt().
|
|
|
|
OptionValue - the optval parameter passed to getsockopt().
|
|
|
|
OptionLength - the optlen parameter passed to getsockopt().
|
|
|
|
Return Value:
|
|
|
|
INT - a winsock error code indicating the status of the operation, or
|
|
NO_ERROR if the operation succeeded.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
INT error, i;
|
|
ULONG tdiActionLength;
|
|
IO_STATUS_BLOCK ioStatusBlock;
|
|
HANDLE eventHandle;
|
|
PTDI_ACTION_HEADER tdiAction;
|
|
|
|
UNREFERENCED_PARAMETER( SocketHandle );
|
|
UNREFERENCED_PARAMETER( TdiConnectionObjectHandle );
|
|
|
|
#if DBG
|
|
DbgPrint("In WSHGetSocketInformation\n");
|
|
#endif
|
|
|
|
//
|
|
// The only level we support here is SOL_SOCKET.
|
|
//
|
|
|
|
if ( Level != SOL_SOCKET ) {
|
|
return WSAEINVAL;
|
|
}
|
|
|
|
//
|
|
// Fill in the result based on the option name.
|
|
// We support SO_LOOKUPNAME/SO_LOOKUPZONES only
|
|
// For a PAP protocol socket, we also support SO_GETSERVERSTATUS
|
|
//
|
|
// BUGBUG: These are currently only defined in wshdata.h. Must be moved into some
|
|
// common header file.
|
|
//
|
|
|
|
switch ( OptionName ) {
|
|
|
|
case SO_LOOKUPNAME:
|
|
|
|
if (( TdiAddressObjectHandle == NULL) ||
|
|
(*OptionLength <= sizeof(WSH_LOOKUPNAME))) {
|
|
|
|
return(WSAEINVAL);
|
|
}
|
|
|
|
tdiActionLength = sizeof(NBP_LOOKUP_ACTION) + *OptionLength -
|
|
sizeof(WSH_LOOKUPNAME);
|
|
break;
|
|
|
|
case SO_LOOKUPZONES:
|
|
|
|
if (( TdiAddressObjectHandle == NULL) ||
|
|
(*OptionLength <= sizeof(WSH_LOOKUPZONES))) {
|
|
|
|
return(WSAEINVAL);
|
|
}
|
|
|
|
tdiActionLength = sizeof(ZIP_GETZONELIST_ACTION) + *OptionLength -
|
|
sizeof(WSH_LOOKUPZONES);
|
|
break;
|
|
|
|
case SO_GETSERVERSTATUS:
|
|
|
|
if (( TdiConnectionObjectHandle == NULL ) ||
|
|
( *OptionLength <= 0 )) {
|
|
|
|
return(WSAEINVAL);
|
|
}
|
|
|
|
tdiActionLength = sizeof(PAP_GETSTATUSJOB_ACTION) + *OptionLength;
|
|
|
|
default:
|
|
|
|
return WSAENOPROTOOPT;
|
|
}
|
|
|
|
|
|
tdiAction = RtlAllocateHeap( RtlProcessHeap( ), 0, tdiActionLength );
|
|
if ( tdiAction == NULL ) {
|
|
return WSAENOBUFS;
|
|
}
|
|
|
|
tdiAction->TransportId = MATK;
|
|
|
|
status = NtCreateEvent(
|
|
&eventHandle,
|
|
EVENT_ALL_ACCESS,
|
|
NULL,
|
|
SynchronizationEvent,
|
|
FALSE
|
|
);
|
|
|
|
if ( !NT_SUCCESS(status) ) {
|
|
RtlFreeHeap( RtlProcessHeap( ), 0, tdiAction );
|
|
return WSAEINVAL;
|
|
}
|
|
|
|
switch ( OptionName ) {
|
|
|
|
case SO_LOOKUPNAME:
|
|
|
|
{
|
|
PNBP_LOOKUP_ACTION nbpAction;
|
|
|
|
nbpAction = (PNBP_LOOKUP_ACTION)tdiAction;
|
|
nbpAction->ActionHeader.ActionCode = COMMON_ACTION_NBPLOOKUP;
|
|
|
|
//
|
|
// Copy the nbp name for lookup in the proper place
|
|
//
|
|
|
|
RtlMoveMemory(
|
|
(PCHAR)&nbpAction->Params.LookupName,
|
|
(PCHAR)(&((PWSH_LOOKUPNAME)OptionValue)->LookupName),
|
|
sizeof(((PWSH_LOOKUPNAME)OptionValue)->LookupName)
|
|
);
|
|
}
|
|
|
|
break;
|
|
|
|
case SO_LOOKUPZONES:
|
|
|
|
{
|
|
PZIP_GETZONELIST_ACTION zipAction;
|
|
|
|
zipAction = (PZIP_GETZONELIST_ACTION)tdiAction;
|
|
zipAction->ActionHeader.ActionCode = COMMON_ACTION_ZIPGETZONELIST;
|
|
|
|
//
|
|
// No parameters need to be passed
|
|
//
|
|
}
|
|
|
|
break;
|
|
|
|
case SO_GETSERVERSTATUS:
|
|
|
|
{
|
|
PPAP_GETSTATUSJOB_ACTION papAction;
|
|
|
|
papAction = (PPAP_GETSTATUSJOB_ACTION)tdiAction;
|
|
papAction->ActionHeader.ActionCode = ACTION_PAPGETSTATUSJOB;
|
|
|
|
//
|
|
// No parameters need to be passed
|
|
//
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
//
|
|
// Should have returned in the first switch statement
|
|
//
|
|
|
|
return WSAENOPROTOOPT;
|
|
}
|
|
|
|
status = NtDeviceIoControlFile(
|
|
TdiAddressObjectHandle,
|
|
eventHandle,
|
|
NULL,
|
|
NULL,
|
|
&ioStatusBlock,
|
|
IOCTL_TDI_ACTION,
|
|
NULL, // Input buffer
|
|
0, // Length of input buffer
|
|
tdiAction,
|
|
tdiActionLength
|
|
);
|
|
|
|
if ( status == STATUS_PENDING ) {
|
|
status = NtWaitForSingleObject( eventHandle, FALSE, NULL );
|
|
ASSERT( NT_SUCCESS(status) );
|
|
status = ioStatusBlock.Status;
|
|
}
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
error = NO_ERROR;
|
|
} else if (status == STATUS_BUFFER_OVERFLOW) {
|
|
error = WSAENOBUFS;
|
|
} else
|
|
error = WSAEINVAL;
|
|
|
|
if (error != WSAEINVAL) {
|
|
switch ( OptionName ) {
|
|
|
|
case SO_LOOKUPNAME:
|
|
|
|
//
|
|
// We are guaranteed by checks in the beginning atleast one byte
|
|
// following the buffer
|
|
//
|
|
|
|
{
|
|
PNBP_LOOKUP_ACTION nbpAction;
|
|
PCHAR beginTdiBuffer = (PCHAR)tdiAction+sizeof(NBP_LOOKUP_ACTION);
|
|
PCHAR beginUserBuffer = (PCHAR)OptionValue+sizeof(WSH_LOOKUPNAME);
|
|
INT copySize = *OptionLength - sizeof(WSH_LOOKUPNAME);
|
|
|
|
nbpAction = (PNBP_LOOKUP_ACTION)tdiAction;
|
|
((PWSH_LOOKUPNAME)OptionValue)->NoTuples =
|
|
nbpAction->Params.NoTuplesRead;
|
|
|
|
for (i = 0; i < copySize; i++) {
|
|
*beginUserBuffer++ = *beginTdiBuffer++;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case SO_LOOKUPZONES:
|
|
|
|
//
|
|
// We are guaranteed by checks in the beginning atleast one byte
|
|
// following the buffer
|
|
//
|
|
|
|
{
|
|
PZIP_GETZONELIST_ACTION zipAction;
|
|
PCHAR beginTdiBuffer = (PCHAR)tdiAction+
|
|
sizeof(ZIP_GETZONELIST_ACTION);
|
|
PCHAR beginUserBuffer = (PCHAR)OptionValue+sizeof(WSH_LOOKUPZONES);
|
|
INT copySize = *OptionLength - sizeof(WSH_LOOKUPZONES);
|
|
|
|
zipAction = (PZIP_GETZONELIST_ACTION)tdiAction;
|
|
((PWSH_LOOKUPZONES)OptionValue)->NoZones=
|
|
zipAction->Params.ZonesAvailable;
|
|
|
|
for (i = 0; i < copySize; i++) {
|
|
*beginUserBuffer++ = *beginTdiBuffer++;
|
|
}
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return WSAENOPROTOOPT;
|
|
}
|
|
}
|
|
|
|
return error;
|
|
|
|
} // WSHGetSocketInformation
|
|
|
|
|
|
INT
|
|
WSHSetSocketInformation (
|
|
IN PVOID HelperDllSocketContext,
|
|
IN SOCKET SocketHandle,
|
|
IN HANDLE TdiAddressObjectHandle,
|
|
IN HANDLE TdiConnectionObjectHandle,
|
|
IN INT Level,
|
|
IN INT OptionName,
|
|
IN PCHAR OptionValue,
|
|
IN INT OptionLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets information about a socket for those socket
|
|
options supported in this helper DLL. The options supported here
|
|
are SO_REGISTERNAME/SO_DEREGISTERNAME. This routine is called by the
|
|
winsock DLL when a level/option name combination is passed to
|
|
setsockopt() that the winsock DLL does not understand.
|
|
|
|
Arguments:
|
|
|
|
HelperDllSocketContext - the context pointer returned from
|
|
WSHOpenSocket().
|
|
|
|
SocketHandle - the handle of the socket for which we're getting
|
|
information.
|
|
|
|
TdiAddressObjectHandle - the TDI address object of the socket, if
|
|
any. If the socket is not yet bound to an address, then
|
|
it does not have a TDI address object and this parameter
|
|
will be NULL.
|
|
|
|
TdiConnectionObjectHandle - the TDI connection object of the socket,
|
|
if any. If the socket is not yet connected, then it does not
|
|
have a TDI connection object and this parameter will be NULL.
|
|
|
|
Level - the level parameter passed to setsockopt().
|
|
|
|
OptionName - the optname parameter passed to setsockopt().
|
|
|
|
OptionValue - the optval parameter passed to setsockopt().
|
|
|
|
OptionLength - the optlen parameter passed to setsockopt().
|
|
|
|
Return Value:
|
|
|
|
INT - a winsock error code indicating the status of the operation, or
|
|
NO_ERROR if the operation succeeded.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
ULONG tdiActionLength;
|
|
IO_STATUS_BLOCK ioStatusBlock;
|
|
HANDLE eventHandle;
|
|
PTDI_ACTION_HEADER tdiAction;
|
|
|
|
|
|
UNREFERENCED_PARAMETER( SocketHandle );
|
|
UNREFERENCED_PARAMETER( TdiConnectionObjectHandle );
|
|
|
|
#if DBG
|
|
DbgPrint("In WSHSetSocketInfo\n");
|
|
#endif
|
|
|
|
//
|
|
// The only level we support here is SOL_SOCKET.
|
|
//
|
|
|
|
if ( Level != SOL_SOCKET ) {
|
|
return WSAEINVAL;
|
|
}
|
|
|
|
//
|
|
// Fill in the result based on the option name.
|
|
// We support SO_REGISTERNAME/SO_DEREGISTERNAME only
|
|
//
|
|
// BUGBUG: These are currently only defined in wshdata.h. Must be moved into some
|
|
// common header file.
|
|
//
|
|
|
|
status = NtCreateEvent(
|
|
&eventHandle,
|
|
EVENT_ALL_ACCESS,
|
|
NULL,
|
|
SynchronizationEvent,
|
|
FALSE
|
|
);
|
|
|
|
if ( !NT_SUCCESS(status) ) {
|
|
return WSAEINVAL;
|
|
}
|
|
|
|
switch ( OptionName ) {
|
|
|
|
case SO_REGISTERNAME:
|
|
|
|
|
|
{
|
|
PNBP_REGDEREG_ACTION nbpAction;
|
|
|
|
if (( TdiAddressObjectHandle == NULL) ||
|
|
(OptionLength != sizeof(WSH_REGISTERNAME))) {
|
|
|
|
return(WSAEINVAL);
|
|
}
|
|
|
|
tdiActionLength = sizeof(NBP_REGDEREG_ACTION);
|
|
tdiAction = RtlAllocateHeap( RtlProcessHeap( ), 0, tdiActionLength );
|
|
if ( tdiAction == NULL ) {
|
|
return WSAENOBUFS;
|
|
}
|
|
|
|
tdiAction->TransportId = MATK;
|
|
tdiAction->ActionCode = COMMON_ACTION_NBPREGISTER;
|
|
nbpAction = (PNBP_REGDEREG_ACTION)tdiAction;
|
|
|
|
//
|
|
// Copy the nbp name to the proper place
|
|
//
|
|
|
|
RtlMoveMemory(
|
|
(PCHAR)&nbpAction->Params.RegisterName,
|
|
OptionValue,
|
|
OptionLength
|
|
);
|
|
}
|
|
|
|
break;
|
|
|
|
case SO_DEREGISTERNAME:
|
|
|
|
{
|
|
PNBP_REGDEREG_ACTION nbpAction;
|
|
|
|
if (( TdiAddressObjectHandle == NULL) ||
|
|
(OptionLength != sizeof(WSH_DEREGISTERNAME))) {
|
|
|
|
return(WSAEINVAL);
|
|
}
|
|
|
|
tdiActionLength = sizeof(NBP_REGDEREG_ACTION);
|
|
tdiAction = RtlAllocateHeap( RtlProcessHeap( ), 0, tdiActionLength );
|
|
if ( tdiAction == NULL ) {
|
|
return WSAENOBUFS;
|
|
}
|
|
|
|
tdiAction->TransportId = MATK;
|
|
tdiAction->ActionCode = COMMON_ACTION_NBPREMOVE;
|
|
nbpAction = (PNBP_REGDEREG_ACTION)tdiAction;
|
|
|
|
//
|
|
// Copy the nbp name to the proper place
|
|
//
|
|
|
|
RtlMoveMemory(
|
|
(PCHAR)&nbpAction->Params.RegisteredName,
|
|
OptionValue,
|
|
OptionLength
|
|
);
|
|
}
|
|
|
|
break;
|
|
|
|
case SO_SETSERVERSTATUS:
|
|
|
|
{
|
|
PPAP_SETSTATUS_ACTION papAction;
|
|
|
|
if (( TdiAddressObjectHandle == NULL) ||
|
|
(OptionLength < 0)) {
|
|
|
|
return(WSAEINVAL);
|
|
}
|
|
|
|
tdiActionLength = sizeof(PAP_SETSTATUS_ACTION) + OptionLength;
|
|
tdiAction = RtlAllocateHeap( RtlProcessHeap( ), 0, tdiActionLength );
|
|
if ( tdiAction == NULL ) {
|
|
return WSAENOBUFS;
|
|
}
|
|
|
|
tdiAction->TransportId = MATK;
|
|
tdiAction->ActionCode = ACTION_PAPSETSTATUS;
|
|
|
|
//
|
|
// Copy the passed status into our buffer
|
|
//
|
|
|
|
if (OptionLength > 0) {
|
|
RtlMoveMemory(
|
|
(PCHAR)&papAction + sizeof(PAP_SETSTATUS_ACTION),
|
|
OptionValue,
|
|
OptionLength
|
|
);
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
return WSAENOPROTOOPT;
|
|
}
|
|
|
|
status = NtDeviceIoControlFile(
|
|
TdiAddressObjectHandle,
|
|
eventHandle,
|
|
NULL,
|
|
NULL,
|
|
&ioStatusBlock,
|
|
IOCTL_TDI_ACTION,
|
|
NULL, // Input buffer
|
|
0, // Length of input buffer
|
|
tdiAction,
|
|
tdiActionLength
|
|
);
|
|
|
|
if ( status == STATUS_PENDING ) {
|
|
status = NtWaitForSingleObject( eventHandle, FALSE, NULL );
|
|
ASSERT( NT_SUCCESS(status) );
|
|
status = ioStatusBlock.Status;
|
|
}
|
|
|
|
if ( !NT_SUCCESS(status) ) {
|
|
|
|
#if DBG
|
|
DbgPrint( "TDI action failed: %LC\n", status );
|
|
#endif
|
|
|
|
// !!! return failure!
|
|
}
|
|
|
|
return NO_ERROR;
|
|
|
|
} // WSHSetSocketInformation
|
|
|
|
|
|
DWORD
|
|
WSHGetWinsockMapping (
|
|
OUT PWINSOCK_MAPPING Mapping,
|
|
IN DWORD MappingLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns the list of address family/socket type/protocol triples
|
|
supported by this helper DLL.
|
|
|
|
Arguments:
|
|
|
|
Mapping - receives a pointer to a WINSOCK_MAPPING structure that
|
|
describes the triples supported here.
|
|
|
|
MappingLength - the length, in bytes, of the passed-in Mapping buffer.
|
|
|
|
Return Value:
|
|
|
|
DWORD - the length, in bytes, of a WINSOCK_MAPPING structure for this
|
|
helper DLL. If the passed-in buffer is too small, the return
|
|
value will indicate the size of a buffer needed to contain
|
|
the WINSOCK_MAPPING structure.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD mappingLength;
|
|
ULONG offset;
|
|
|
|
#if DBG
|
|
DbgPrint("In WSHGetWinsockMapping\n");
|
|
#endif
|
|
|
|
mappingLength = sizeof(WINSOCK_MAPPING) - sizeof(MAPPING_TRIPLE) +
|
|
sizeof(AdspStreamMappingTriples) +
|
|
sizeof(AdspMsgMappingTriples) +
|
|
sizeof(PapMsgMappingTriples) +
|
|
sizeof(DdpMappingTriples);
|
|
|
|
//
|
|
// If the passed-in buffer is too small, return the length needed
|
|
// now without writing to the buffer. The caller should allocate
|
|
// enough memory and call this routine again.
|
|
//
|
|
|
|
if ( mappingLength > MappingLength ) {
|
|
return mappingLength;
|
|
}
|
|
|
|
//
|
|
// Fill in the output mapping buffer with the list of triples
|
|
// supported in this helper DLL.
|
|
//
|
|
|
|
Mapping->Rows =
|
|
sizeof(AdspStreamMappingTriples) / sizeof(AdspStreamMappingTriples[0]) +
|
|
sizeof(AdspMsgMappingTriples) / sizeof(AdspMsgMappingTriples[0]) +
|
|
sizeof(PapMsgMappingTriples) / sizeof(PapMsgMappingTriples[0]) +
|
|
sizeof(DdpMappingTriples) / sizeof(DdpMappingTriples[0][0]);
|
|
|
|
Mapping->Columns = sizeof(MAPPING_TRIPLE) / sizeof(DWORD);
|
|
|
|
offset = 0;
|
|
RtlMoveMemory(
|
|
Mapping->Mapping,
|
|
AdspStreamMappingTriples,
|
|
sizeof(AdspStreamMappingTriples)
|
|
);
|
|
|
|
offset += sizeof(AdspStreamMappingTriples);
|
|
RtlMoveMemory(
|
|
(PCHAR)Mapping->Mapping + offset,
|
|
AdspMsgMappingTriples,
|
|
sizeof(AdspMsgMappingTriples)
|
|
);
|
|
|
|
offset += sizeof(AdspMsgMappingTriples);
|
|
RtlMoveMemory(
|
|
(PCHAR)Mapping->Mapping + offset,
|
|
PapMsgMappingTriples,
|
|
sizeof(PapMsgMappingTriples)
|
|
);
|
|
|
|
offset += sizeof(PapMsgMappingTriples);
|
|
RtlMoveMemory(
|
|
(PCHAR)Mapping->Mapping + offset,
|
|
DdpMappingTriples,
|
|
sizeof(DdpMappingTriples)
|
|
);
|
|
|
|
//
|
|
// Return the number of bytes we wrote.
|
|
//
|
|
#if DBG
|
|
DbgPrint("Mapping Length = %d\n", mappingLength);
|
|
#endif
|
|
|
|
return mappingLength;
|
|
|
|
} // WSHGetWinsockMapping
|
|
|
|
|
|
INT
|
|
WSHOpenSocket (
|
|
IN OUT PINT AddressFamily,
|
|
IN OUT PINT SocketType,
|
|
IN OUT PINT Protocol,
|
|
OUT PUNICODE_STRING TransportDeviceName,
|
|
OUT PVOID *HelperDllSocketContext,
|
|
OUT PDWORD NotificationEvents
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Does the necessary work for this helper DLL to open a socket and is
|
|
called by the winsock DLL in the socket() routine. This routine
|
|
verifies that the specified triple is valid, determines the NT
|
|
device name of the TDI provider that will support that triple,
|
|
allocates space to hold the socket's context block, and
|
|
canonicalizes the triple.
|
|
|
|
Arguments:
|
|
|
|
AddressFamily - on input, the address family specified in the
|
|
socket() call. On output, the canonicalized value for the
|
|
address family.
|
|
|
|
SocketType - on input, the socket type specified in the socket()
|
|
call. On output, the canonicalized value for the socket type.
|
|
|
|
Protocol - on input, the protocol specified in the socket() call.
|
|
On output, the canonicalized value for the protocol.
|
|
|
|
TransportDeviceName - receives the name of the TDI provider that
|
|
will support the specified triple.
|
|
|
|
HelperDllSocketContext - receives a context pointer that the winsock
|
|
DLL will return to this helper DLL on future calls involving
|
|
this socket.
|
|
|
|
NotificationEvents - receives a bitmask of those state transitions
|
|
this helper DLL should be notified on.
|
|
|
|
Return Value:
|
|
|
|
INT - a winsock error code indicating the status of the operation, or
|
|
NO_ERROR if the operation succeeded.
|
|
|
|
--*/
|
|
|
|
{
|
|
PWSHATALK_SOCKET_CONTEXT context;
|
|
INT i;
|
|
|
|
#if DBG
|
|
DbgPrint("In WSHOpenSocket\n");
|
|
#endif
|
|
|
|
|
|
//
|
|
// Determine whether this is to be a TCP or UDP socket.
|
|
//
|
|
|
|
if ( IsTripleInList(
|
|
AdspStreamMappingTriples,
|
|
sizeof(AdspStreamMappingTriples) / sizeof(AdspStreamMappingTriples[0]),
|
|
*AddressFamily,
|
|
*SocketType,
|
|
*Protocol ) ) {
|
|
|
|
//
|
|
// Return the canonical form of a TCP socket triple.
|
|
//
|
|
|
|
*AddressFamily = AdspStreamMappingTriples[0].AddressFamily;
|
|
*SocketType = AdspStreamMappingTriples[0].SocketType;
|
|
*Protocol = AdspStreamMappingTriples[0].Protocol;
|
|
|
|
//
|
|
// Indicate the name of the TDI device that will service
|
|
// SOCK_STREAM sockets in the internet address family.
|
|
//
|
|
|
|
RtlInitUnicodeString( TransportDeviceName, WSH_ATALK_ADSPSTREAM );
|
|
|
|
} else if ( IsTripleInList(
|
|
AdspMsgMappingTriples,
|
|
sizeof(AdspMsgMappingTriples) / sizeof(AdspMsgMappingTriples[0]),
|
|
*AddressFamily,
|
|
*SocketType,
|
|
*Protocol ) ) {
|
|
|
|
//
|
|
// Return the canonical form of a RDM socket triple.
|
|
//
|
|
|
|
*AddressFamily = AdspMsgMappingTriples[0].AddressFamily;
|
|
*SocketType = AdspMsgMappingTriples[0].SocketType;
|
|
*Protocol = AdspMsgMappingTriples[0].Protocol;
|
|
|
|
//
|
|
// Indicate the name of the TDI device that will service
|
|
// SOCK_RDM sockets in the internet address family.
|
|
//
|
|
|
|
RtlInitUnicodeString( TransportDeviceName, WSH_ATALK_ADSPRDM );
|
|
|
|
} else if ( IsTripleInList(
|
|
PapMsgMappingTriples,
|
|
sizeof(PapMsgMappingTriples) / sizeof(PapMsgMappingTriples[0]),
|
|
*AddressFamily,
|
|
*SocketType,
|
|
*Protocol ) ) {
|
|
|
|
//
|
|
// Return the canonical form of a RDM socket triple.
|
|
//
|
|
|
|
*AddressFamily = PapMsgMappingTriples[0].AddressFamily;
|
|
*SocketType = PapMsgMappingTriples[0].SocketType;
|
|
*Protocol = PapMsgMappingTriples[0].Protocol;
|
|
|
|
//
|
|
// Indicate the name of the TDI device that will service
|
|
// SOCK_RDM sockets in the appletalk address family.
|
|
//
|
|
|
|
RtlInitUnicodeString( TransportDeviceName, WSH_ATALK_PAPRDM );
|
|
|
|
} else {
|
|
|
|
BOOLEAN tripleFound = FALSE;
|
|
|
|
//
|
|
// Check the DDP triples
|
|
//
|
|
|
|
for (i = 0; i < DDPPROTO_MAX+3; i++) {
|
|
|
|
if ( IsTripleInList(
|
|
DdpMappingTriples[i],
|
|
sizeof(DdpMappingTriples[i]) /
|
|
sizeof(DdpMappingTriples[i][0]),
|
|
*AddressFamily,
|
|
*SocketType,
|
|
*Protocol ) ) {
|
|
|
|
tripleFound = TRUE;
|
|
|
|
//
|
|
// Return the canonical form of a DGRAM socket triple.
|
|
//
|
|
|
|
*AddressFamily = DdpMappingTriples[i][0].AddressFamily;
|
|
*SocketType = DdpMappingTriples[i][0].SocketType;
|
|
*Protocol = DdpMappingTriples[i][0].Protocol;
|
|
|
|
//
|
|
// Indicate the name of the TDI device that will service
|
|
// SOCK_DGRAM sockets in the appletalk address family.
|
|
//
|
|
|
|
RtlInitUnicodeString( TransportDeviceName,
|
|
WSH_ATALK_DGRAMDDP[*Protocol] );
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// This should never happen if the registry information about this
|
|
// helper DLL is correct. If somehow this did happen, just return
|
|
// an error.
|
|
//
|
|
|
|
if (!tripleFound) {
|
|
return WSAEINVAL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Allocate context for this socket. The Windows Sockets DLL will
|
|
// return this value to us when it asks us to get/set socket options.
|
|
//
|
|
|
|
context = RtlAllocateHeap( RtlProcessHeap( ), 0, sizeof(*context) );
|
|
if ( context == NULL ) {
|
|
return WSAENOBUFS;
|
|
}
|
|
|
|
//
|
|
// Initialize the context for the socket.
|
|
//
|
|
|
|
context->AddressFamily = *AddressFamily;
|
|
context->SocketType = *SocketType;
|
|
context->Protocol = *Protocol;
|
|
|
|
//
|
|
// Tell the Windows Sockets DLL which state transitions we're
|
|
// interested in being notified of.
|
|
//
|
|
|
|
*NotificationEvents = WSH_NOTIFY_CONNECT | WSH_NOTIFY_CLOSE;
|
|
|
|
//
|
|
// Everything worked, return success.
|
|
//
|
|
|
|
*HelperDllSocketContext = context;
|
|
return NO_ERROR;
|
|
|
|
} // WSHOpenSocket
|
|
|
|
|
|
INT
|
|
WSHNotify (
|
|
IN PVOID HelperDllSocketContext,
|
|
IN SOCKET SocketHandle,
|
|
IN HANDLE TdiAddressObjectHandle,
|
|
IN HANDLE TdiConnectionObjectHandle,
|
|
IN DWORD NotifyEvent
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by the winsock DLL after a state transition
|
|
of the socket. Only state transitions returned in the
|
|
NotificationEvents parameter of WSHOpenSocket() are notified here.
|
|
This routine allows a winsock helper DLL to track the state of
|
|
socket and perform necessary actions corresponding to state
|
|
transitions.
|
|
|
|
Arguments:
|
|
|
|
HelperDllSocketContext - the context pointer given to the winsock
|
|
DLL by WSHOpenSocket().
|
|
|
|
SocketHandle - the handle for the socket.
|
|
|
|
TdiAddressObjectHandle - the TDI address object of the socket, if
|
|
any. If the socket is not yet bound to an address, then
|
|
it does not have a TDI address object and this parameter
|
|
will be NULL.
|
|
|
|
TdiConnectionObjectHandle - the TDI connection object of the socket,
|
|
if any. If the socket is not yet connected, then it does not
|
|
have a TDI connection object and this parameter will be NULL.
|
|
|
|
NotifyEvent - indicates the state transition for which we're being
|
|
called.
|
|
|
|
Return Value:
|
|
|
|
INT - a winsock error code indicating the status of the operation, or
|
|
NO_ERROR if the operation succeeded.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PWSHATALK_SOCKET_CONTEXT context = HelperDllSocketContext;
|
|
|
|
//
|
|
// We should only be called after a connect() completes or when the
|
|
// socket is being closed.
|
|
//
|
|
|
|
if ( NotifyEvent == WSH_NOTIFY_CONNECT ) {
|
|
|
|
//
|
|
// Just for debugging right now
|
|
//
|
|
|
|
#if DBG
|
|
DbgPrint("Connect completed, notify called!\n");
|
|
#endif
|
|
|
|
} else if ( NotifyEvent == WSH_NOTIFY_CLOSE ) {
|
|
|
|
//
|
|
// Just free the socket context.
|
|
//
|
|
|
|
#if DBG
|
|
DbgPrint("Close notify called!\n");
|
|
#endif
|
|
|
|
RtlFreeHeap( RtlProcessHeap( ), 0, HelperDllSocketContext );
|
|
|
|
} else {
|
|
|
|
return WSAEINVAL;
|
|
}
|
|
|
|
return NO_ERROR;
|
|
|
|
} // WSHNotify
|
|
|
|
|
|
|
|
BOOLEAN
|
|
IsTripleInList (
|
|
IN PMAPPING_TRIPLE List,
|
|
IN ULONG ListLength,
|
|
IN INT AddressFamily,
|
|
IN INT SocketType,
|
|
IN INT Protocol
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determines whether the specified triple has an exact match in the
|
|
list of triples.
|
|
|
|
Arguments:
|
|
|
|
List - a list of triples (address family/socket type/protocol) to
|
|
search.
|
|
|
|
ListLength - the number of triples in the list.
|
|
|
|
AddressFamily - the address family to look for in the list.
|
|
|
|
SocketType - the socket type to look for in the list.
|
|
|
|
Protocol - the protocol to look for in the list.
|
|
|
|
Return Value:
|
|
|
|
BOOLEAN - TRUE if the triple was found in the list, false if not.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG i;
|
|
|
|
//
|
|
// Walk through the list searching for an exact match.
|
|
//
|
|
|
|
for ( i = 0; i < ListLength; i++ ) {
|
|
|
|
//
|
|
// If all three elements of the triple match, return indicating
|
|
// that the triple did exist in the list.
|
|
//
|
|
|
|
if ( AddressFamily == List[i].AddressFamily &&
|
|
SocketType == List[i].SocketType &&
|
|
Protocol == List[i].Protocol ) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// The triple was not found in the list.
|
|
//
|
|
|
|
return FALSE;
|
|
|
|
} // IsTripleInList
|