Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

638 lines
13 KiB

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
eventsel.c
Abstract:
This module contains support for the WSAEventSelect() and
WSAEnumNetworkEvents() WinSock APIs.
Author:
Keith Moore (keithmo) 5-Aug-1995
Revision History:
--*/
#include "winsockp.h"
//
// Data to make the mapping of poll events to FD_* events simpler
// in WSAEnumNetworkEvents(). Note that FD_CONNECT and FD_CLOSE
// are not in this list. They must be handled specially.
//
typedef struct _POLL_MAPPING {
ULONG PollEventBit;
LONG NetworkEventBit;
} POLL_MAPPING, *PPOLL_MAPPING;
POLL_MAPPING PollEventMapping[] =
{
{ AFD_POLL_RECEIVE_BIT, FD_READ_BIT },
{ AFD_POLL_SEND_BIT, FD_WRITE_BIT },
{ AFD_POLL_RECEIVE_EXPEDITED_BIT, FD_OOB_BIT },
{ AFD_POLL_ACCEPT_BIT, FD_ACCEPT_BIT },
{ AFD_POLL_QOS_BIT, FD_QOS_BIT },
{ AFD_POLL_GROUP_QOS_BIT, FD_GROUP_QOS_BIT }
};
#define NUM_POLL_MAPPINGS (sizeof(PollEventMapping) / sizeof(PollEventMapping[0]))
int
WSPAPI
WSPEventSelect (
SOCKET Handle,
WSAEVENT hEventObject,
long lNetworkEvents,
LPINT lpErrno
)
/*++
Routine Description:
Does that event select thang. CKMBUGBUG
Arguments:
Handle - A descriptor identifying the socket for which event
notification is required.
hEventObject - A handle identifying the event object which should
be signalled when a network event occurs.
lEvent - A bitmask which specifies a combination of network events
in which the application is interested.
Return Value:
The return value is 0 if the application's declaration of interest
in the network event set was successful. Otherwise the value
SOCKET_ERROR is returned, and a specific error number may be
retrieved by calling WSAGetLastError().
--*/
{
PSOCKET_INFORMATION socket;
int err;
BOOLEAN blocking;
WS_ENTER( "WSAEventSelect", (PVOID)Handle, (PVOID)hEventObject, (PVOID)lNetworkEvents, NULL );
WS_ASSERT( lpErrno != NULL );
err = SockEnterApi( TRUE, TRUE, FALSE );
if( err != NO_ERROR ) {
WS_EXIT( "WSPEventSelect", SOCKET_ERROR, TRUE );
*lpErrno = err;
return SOCKET_ERROR;
}
//
// Initialize locals so that we know how to clean up on exit.
//
socket = NULL;
//
// Find a pointer to the socket structure corresponding to the
// passed-in handle.
//
socket = SockFindAndReferenceSocket( Handle, TRUE );
if ( socket == NULL ) {
err = WSAENOTSOCK;
goto exit;
}
//
// Set the socket to nonblocking.
//
blocking = TRUE;
err = SockSetInformation(
socket,
AFD_NONBLOCKING_MODE,
&blocking,
NULL,
NULL
);
if ( err != NO_ERROR ) {
goto exit;
}
socket->NonBlocking = TRUE;
//
// If there's a WSAAsyncSelect active on this socket, deactivate it.
//
if( socket->AsyncSelectlEvent ) {
err = SockAsyncSelectHelper(
socket,
NULL,
0,
0
);
if( err != NO_ERROR ) {
goto exit;
}
}
//
// Make sure that only valid bits are specified in lEvent.
//
// !!! should we also make sure that the bits make sense for the
// state of the socket, i.e. don't allow FD_ACCEPT on a
// connected socket?
//
if ( (lNetworkEvents & ~FD_ALL_EVENTS) != 0 ) {
err = WSAEINVAL;
goto exit;
}
//
// Let the helper do the dirty work.
//
err = SockEventSelectHelper(
socket,
hEventObject,
lNetworkEvents
);
exit:
if ( socket != NULL ) {
SockDereferenceSocket( socket );
}
if ( err != NO_ERROR) {
IF_DEBUG(EVENT_SELECT) {
WS_PRINT(( "WSAEventSelect failed: %ld\n", err ));
}
WS_EXIT( "WSAEventSelect", SOCKET_ERROR, TRUE );
*lpErrno = err;
return SOCKET_ERROR;
}
IF_DEBUG(EVENT_SELECT) {
WS_PRINT(( "WSAEventSelect successfully posted request, "
"socket = %lx\n", socket ));
}
WS_EXIT( "WSAEventSelect", NO_ERROR, FALSE );
return NO_ERROR;
} // WSPEventSelect
int
SockEventSelectHelper(
PSOCKET_INFORMATION Socket,
WSAEVENT hEventObject,
long lNetworkEvents
)
/*++
Routine Description:
x
Arguments:
x
Return Value:
x
--*/
{
AFD_EVENT_SELECT_INFO eventInfo;
IO_STATUS_BLOCK ioStatusBlock;
NTSTATUS status;
//
// Acquire the lock that protects this socket. We hold this lock
// throughout this routine to synchronize against other callers
// performing operations on the socket we're using.
//
SockAcquireSocketLockExclusive( Socket );
//
// Initialize the AFD_EVENT_SELECT_INFO structure.
//
eventInfo.Event = hEventObject;
eventInfo.PollEvents = 0;
if( lNetworkEvents & FD_READ ) {
eventInfo.PollEvents |= AFD_POLL_RECEIVE;
}
if( lNetworkEvents & FD_WRITE ) {
eventInfo.PollEvents |= AFD_POLL_SEND;
}
if( lNetworkEvents & FD_OOB ) {
eventInfo.PollEvents |= AFD_POLL_RECEIVE_EXPEDITED;
}
if( lNetworkEvents & FD_ACCEPT ) {
eventInfo.PollEvents |= AFD_POLL_ACCEPT;
}
if( lNetworkEvents & FD_CONNECT ) {
eventInfo.PollEvents |= AFD_POLL_CONNECT | AFD_POLL_CONNECT_FAIL;
}
if( lNetworkEvents & FD_CLOSE ) {
eventInfo.PollEvents |= AFD_POLL_DISCONNECT | AFD_POLL_ABORT;
}
if( lNetworkEvents & FD_QOS ) {
eventInfo.PollEvents |= AFD_POLL_QOS;
}
if( lNetworkEvents & FD_GROUP_QOS ) {
eventInfo.PollEvents |= AFD_POLL_GROUP_QOS;
}
//
// Send the IOCTL to AFD. AFD will reference the event object and
// store the poll events in its internal endpoint structure.
//
status = NtDeviceIoControlFile(
(HANDLE)Socket->Handle,
SockThreadEvent,
NULL, // APC Routine
NULL, // APC Context
&ioStatusBlock,
IOCTL_AFD_EVENT_SELECT,
&eventInfo,
sizeof(eventInfo),
NULL,
0
);
if( status == STATUS_PENDING ) {
SockWaitForSingleObject(
SockThreadEvent,
Socket->Handle,
SOCK_NEVER_CALL_BLOCKING_HOOK,
SOCK_NO_TIMEOUT
);
status = ioStatusBlock.Status;
}
if( !NT_SUCCESS(status) ) {
SockReleaseSocketLock( Socket );
return SockNtStatusToSocketError( status );
}
//
// Store the event object handle and network event mask in the socket.
//
Socket->EventSelectEventObject = hEventObject;
Socket->EventSelectlNetworkEvents = lNetworkEvents;
//
// Release the socket lock & return.
//
SockReleaseSocketLock( Socket );
return NO_ERROR;
} // SockEventSelectHelper
int
WSPAPI
WSPEnumNetworkEvents (
SOCKET Handle,
WSAEVENT hEventObject,
LPWSANETWORKEVENTS lpNetworkEvents,
LPINT lpErrno
)
/*++
Routine Description:
Does that enum network events thang. CKMBUGBUG
Arguments:
Handle - A descriptor identifying the socket.
hEventObject - An optional handle identifying an associated event
object to be reset.
lpNetworkEvents - Points to a WSANETWORKEVENTS structure which records
an occurred network event and the associated error code.
Return Value:
The return value is 0 if the application's declaration of interest
in the network event set was successful. Otherwise the value
SOCKET_ERROR is returned, and a specific error number may be
retrieved by calling WSAGetLastError().
--*/
{
PSOCKET_INFORMATION socket;
INT err;
BOOLEAN blocking;
AFD_ENUM_NETWORK_EVENTS_INFO eventInfo;
IO_STATUS_BLOCK ioStatusBlock;
NTSTATUS status;
NTSTATUS eventStatus;
INT i;
PPOLL_MAPPING pollMapping;
WS_ENTER( "WSAEnumNetworkEvents", (PVOID)Handle, (PVOID)hEventObject, (PVOID)lpNetworkEvents, NULL );
WS_ASSERT( lpErrno != NULL );
err = SockEnterApi( TRUE, TRUE, FALSE );
if( err != NO_ERROR ) {
WS_EXIT( "WSPEnumNetworkEvents", SOCKET_ERROR, TRUE );
*lpErrno = err;
return SOCKET_ERROR;
}
//
// Initialize locals so that we know how to clean up on exit.
//
socket = NULL;
//
// Validate the parameters.
//
if( lpNetworkEvents == NULL ) {
err = WSAEINVAL;
goto exit;
}
//
// Zero the WSANETWORKEVENTS structure.
//
RtlZeroMemory(
lpNetworkEvents,
sizeof(*lpNetworkEvents)
);
//
// Find a pointer to the socket structure corresponding to the
// passed-in handle.
//
socket = SockFindAndReferenceSocket( Handle, TRUE );
if ( socket == NULL ) {
err = WSAENOTSOCK;
goto exit;
}
//
// Acquire the lock that protects this socket. We hold this lock
// throughout this routine to synchronize against other callers
// performing operations on the socket we're using.
//
SockAcquireSocketLockExclusive( socket );
//
// Initialize the AFD_ENUM_NETWORK_EVENTS_INFO structure.
//
eventInfo.Event = hEventObject;
//
// Send the IOCTL to AFD. AFD will update the structure with
// information on network events that have occurred. AFD will
// then reset the event object (if specified).
//
status = NtDeviceIoControlFile(
(HANDLE)Handle,
SockThreadEvent,
NULL, // APC Routine
NULL, // APC Context
&ioStatusBlock,
IOCTL_AFD_ENUM_NETWORK_EVENTS,
&eventInfo,
sizeof(eventInfo),
&eventInfo,
sizeof(eventInfo)
);
if( status == STATUS_PENDING ) {
SockWaitForSingleObject(
SockThreadEvent,
socket->Handle,
SOCK_NEVER_CALL_BLOCKING_HOOK,
SOCK_NO_TIMEOUT
);
status = ioStatusBlock.Status;
}
if( !NT_SUCCESS(status) ) {
err = SockNtStatusToSocketError( status );
goto exit;
}
//
// Interpret the results.
//
pollMapping = PollEventMapping;
for( i = 0 ; i < NUM_POLL_MAPPINGS ; i++ ) {
if( eventInfo.PollEvents & ( 1 << pollMapping->PollEventBit ) ) {
lpNetworkEvents->lNetworkEvents |=
( 1 << pollMapping->NetworkEventBit );
eventStatus = eventInfo.EventStatus[pollMapping->PollEventBit];
if( !NT_SUCCESS(eventStatus) ) {
lpNetworkEvents->iErrorCode[pollMapping->NetworkEventBit] =
SockNtStatusToSocketError( eventStatus );
}
}
pollMapping++;
}
if( eventInfo.PollEvents & AFD_POLL_CONNECT ) {
lpNetworkEvents->lNetworkEvents |= FD_CONNECT;
eventStatus = eventInfo.EventStatus[AFD_POLL_CONNECT_BIT];
if( !NT_SUCCESS(eventStatus ) ) {
lpNetworkEvents->iErrorCode[FD_CONNECT_BIT] =
SockNtStatusToSocketError( eventStatus );
}
} else if (eventInfo.PollEvents & AFD_POLL_CONNECT_FAIL ) {
lpNetworkEvents->lNetworkEvents |= FD_CONNECT;
eventStatus = eventInfo.EventStatus[AFD_POLL_CONNECT_FAIL_BIT];
if( !NT_SUCCESS(eventStatus ) ) {
lpNetworkEvents->iErrorCode[FD_CONNECT_BIT] =
SockNtStatusToSocketError( eventStatus );
}
}
if( eventInfo.PollEvents & AFD_POLL_ABORT ) {
lpNetworkEvents->lNetworkEvents |= FD_CLOSE;
eventStatus = eventInfo.EventStatus[AFD_POLL_ABORT_BIT];
if( !NT_SUCCESS(eventStatus ) ) {
lpNetworkEvents->iErrorCode[FD_CLOSE_BIT] =
SockNtStatusToSocketError( eventStatus );
}
} else if( eventInfo.PollEvents & AFD_POLL_DISCONNECT ) {
lpNetworkEvents->lNetworkEvents |= FD_CLOSE;
eventStatus = eventInfo.EventStatus[AFD_POLL_DISCONNECT_BIT];
if( !NT_SUCCESS(eventStatus ) ) {
lpNetworkEvents->iErrorCode[FD_CLOSE_BIT] =
SockNtStatusToSocketError( eventStatus );
}
}
exit:
if ( socket != NULL ) {
SockReleaseSocketLock( socket );
SockDereferenceSocket( socket );
}
if ( err != NO_ERROR) {
IF_DEBUG(EVENT_SELECT) {
WS_PRINT(( "WSAEnumNetworkEvents failed: %ld\n", err ));
}
WS_EXIT( "WSAEnumNetworkEvents", SOCKET_ERROR, TRUE );
*lpErrno = err;
return SOCKET_ERROR;
}
IF_DEBUG(EVENT_SELECT) {
WS_PRINT(( "WSAEnumNetworkEvents successfully posted request, "
"socket = %lx\n", socket ));
}
WS_EXIT( "WSAEnumNetworkEvents", NO_ERROR, FALSE );
return NO_ERROR;
} // WSPEnumNetworkEvents