|
|
/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
eventsel.c
Abstract:
This module contains routines for supporting the WinSock 2.0 WSAEventSelect() and WSAEnumNetworkEvents() APIs.
Author:
Keith Moore (keithmo) 02-Aug-1995
Revision History:
--*/
#include "afdp.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, AfdEventSelect )
#pragma alloc_text( PAGE, AfdEnumNetworkEvents )
#endif
NTSTATUS AfdEventSelect ( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp )
/*++
Routine Description:
Associates an event object with the socket such that the event object will be signalled when any of the specified network events becomes active.
Arguments:
Irp - Pointer to I/O request packet.
IrpSp - pointer to the IO stack location to use for this request.
Return Value:
NTSTATUS -- Indicates whether the APC was successfully queued.
--*/
{
NTSTATUS status; PAFD_ENDPOINT endpoint; PAFD_EVENT_SELECT_INFO eventInfo; KIRQL oldIrql; PKEVENT eventObject; ULONG eventMask;
PAGED_CODE( );
//
// Validate the parameters.
//
eventInfo = Irp->AssociatedIrp.SystemBuffer;
if( eventInfo == NULL || IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(*eventInfo) || ( eventInfo->Event == NULL ^ eventInfo->PollEvents == 0 ) ) {
return STATUS_INVALID_PARAMETER;
}
//
// Reference the target event object.
//
eventObject = NULL;
if( eventInfo->Event != NULL ) {
status = AfdReferenceEventObjectByHandle( eventInfo->Event, Irp->RequestorMode, (PVOID *)&eventObject );
if( !NT_SUCCESS(status) ) {
return status;
}
ASSERT( eventObject != NULL );
}
//
// Grab the endpoint from the socket handle.
//
endpoint = IrpSp->FileObject->FsContext; ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
//
// Acquire the spinlock protecting the endpoint.
//
AfdAcquireSpinLock( &endpoint->SpinLock, &oldIrql );
//
// If this endpoint has an active EventSelect, dereference the
// associated event object.
//
if( endpoint->EventObject != NULL ) {
ObDereferenceObject( endpoint->EventObject );
}
//
// Fill in the info.
//
endpoint->EventObject = eventObject; endpoint->EventsEnabled = eventInfo->PollEvents;
if( endpoint->State == AfdEndpointStateListening ) {
endpoint->EventsDisabled = AFD_DISABLED_LISTENING_POLL_EVENTS;
} else {
endpoint->EventsDisabled = 0;
}
IF_DEBUG(EVENT_SELECT) { KdPrint(( "AfdEventSelect:\n" ));
KdPrint(( " Endpoint %08lX\n", endpoint ));
KdPrint(( " EventObject %08lX\n", eventObject ));
KdPrint(( " EventsEnabled %08lX\n", endpoint->EventsEnabled ));
KdPrint(( " EventsDisabled %08lX\n", endpoint->EventsDisabled ));
KdPrint(( " EventsActive %08lX\n", endpoint->EventsActive )); }
//
// While we've got the spinlock held, determine if any conditions
// are met, and if so, signal the event object.
//
eventMask = endpoint->EventsActive & endpoint->EventsEnabled & ~endpoint->EventsDisabled;
if( eventMask != 0 && eventObject != NULL ) {
IF_DEBUG(EVENT_SELECT) { KdPrint(( "AfdEventSelect: Setting event %08lX\n", eventObject )); }
KeSetEvent( eventObject, AfdPriorityBoost, FALSE );
}
//
// Release the spin lock and return.
//
AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql );
return STATUS_SUCCESS;
} // AfdEventSelect
NTSTATUS AfdEnumNetworkEvents ( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp )
/*++
Routine Description:
Retrieves event select information from the socket.
Arguments:
Irp - Pointer to I/O request packet.
IrpSp - pointer to the IO stack location to use for this request.
Return Value:
NTSTATUS -- Indicates whether the APC was successfully queued.
--*/
{
NTSTATUS status; PAFD_ENDPOINT endpoint; PAFD_ENUM_NETWORK_EVENTS_INFO eventInfo; KIRQL oldIrql; PKEVENT eventObject; ULONG pollEvents;
PAGED_CODE( );
//
// Validate the parameters.
//
eventInfo = Irp->AssociatedIrp.SystemBuffer;
if( eventInfo == NULL || IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(*eventInfo) || IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(*eventInfo) ) {
return STATUS_INVALID_PARAMETER;
}
//
// Reference the target event object.
//
eventObject = NULL;
if( eventInfo->Event != NULL ) {
status = AfdReferenceEventObjectByHandle( eventInfo->Event, Irp->RequestorMode, (PVOID *)&eventObject );
if( !NT_SUCCESS(status) ) {
return status;
}
ASSERT( eventObject != NULL );
}
//
// Grab the endpoint from the socket handle.
//
endpoint = IrpSp->FileObject->FsContext; ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
//
// Acquire the spinlock protecting the endpoint.
//
AfdAcquireSpinLock( &endpoint->SpinLock, &oldIrql );
IF_DEBUG(EVENT_SELECT) { KdPrint(( "AfdEnumNetworkEvents:\n" ));
KdPrint(( " Endpoint %08lX\n", endpoint ));
KdPrint(( " EventObject %08lX\n", eventObject ));
KdPrint(( " EventsEnabled %08lX\n", endpoint->EventsEnabled ));
KdPrint(( " EventsDisabled %08lX\n", endpoint->EventsDisabled ));
KdPrint(( " EventsActive %08lX\n", endpoint->EventsActive )); }
//
// Copy the data to the user's structure.
//
pollEvents = endpoint->EventsActive & endpoint->EventsEnabled & ~endpoint->EventsDisabled; eventInfo->PollEvents = pollEvents;
RtlCopyMemory( eventInfo->EventStatus, endpoint->EventStatus, sizeof(endpoint->EventStatus) );
//
// If there was an event object handle passed in with this
// request, reset and dereference it.
//
if( eventObject != NULL ) {
IF_DEBUG(EVENT_SELECT) { KdPrint(( "AfdEnumNetworkEvents: Resetting event %08lX\n", eventObject )); }
KeResetEvent( eventObject ); ObDereferenceObject( eventObject );
}
//
// Release the spin lock and return.
//
AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql );
//
// Before returning, tell the I/O subsystem how may bytes to copy
// to the user's output buffer.
//
Irp->IoStatus.Information = sizeof(*eventInfo);
return STATUS_SUCCESS;
} // AfdEnumNetworkEvents
VOID AfdIndicateEventSelectEvent ( IN PAFD_ENDPOINT Endpoint, IN ULONG PollEventBit, IN NTSTATUS Status ) { ULONG event; ULONG oldEventsActive;
//
// Sanity check.
//
ASSERT( IS_AFD_ENDPOINT_TYPE( Endpoint ) ); ASSERT( PollEventBit < AFD_NUM_POLL_EVENTS ); ASSERT( KeGetCurrentIrql() >= DISPATCH_LEVEL );
//
// Calculate the actual event bit.
//
event = 1 << PollEventBit;
oldEventsActive = Endpoint->EventsActive; Endpoint->EventsActive |= event; Endpoint->EventStatus[PollEventBit] = Status;
IF_DEBUG(EVENT_SELECT) { KdPrint(( "AfdIndicateEventSelectEvent:\n" ));
KdPrint(( " Endpoint %08lX\n", Endpoint ));
KdPrint(( " EventObject %08lX\n", Endpoint->EventObject ));
KdPrint(( " EventsEnabled %08lX\n", Endpoint->EventsEnabled ));
KdPrint(( " EventsDisabled %08lX\n", Endpoint->EventsDisabled ));
KdPrint(( " EventsActive %08lX\n", Endpoint->EventsActive ));
KdPrint(( " Indicated Event %08lX\n", event )); }
//
// Only signal the endpoint's event object if the current event
// is enabled, AND the current event was not already active, AND
// there is an event object associated with this endpoint.
//
event &= Endpoint->EventsEnabled & ~Endpoint->EventsDisabled & ~oldEventsActive;
if( event != 0 && Endpoint->EventObject != NULL ) {
IF_DEBUG(EVENT_SELECT) { KdPrint(( "AfdIndicateEventSelectEvent: Setting event %08lX\n", Endpoint->EventObject )); }
KeSetEvent( Endpoint->EventObject, AfdPriorityBoost, FALSE );
}
} // AfdIndicateEventSelectEvent
|