📄 select.c
字号:
/* $Id: select.c 21689 2006-04-21 17:45:51Z tretiakov $
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: drivers/net/afd/afd/select.c
* PURPOSE: Ancillary functions driver
* PROGRAMMER: Art Yerkes (ayerkes@speakeasy.net)
* UPDATE HISTORY:
* 20040708 Created
*/
#include "afd.h"
#include "tdi_proto.h"
#include "tdiconn.h"
#include "debug.h"
static VOID PrintEvents( ULONG Events ) {
#if DBG
char *events_list[] = { "AFD_EVENT_RECEIVE",
"AFD_EVENT_OOB_RECEIVE",
"AFD_EVENT_SEND",
"AFD_EVENT_DISCONNECT",
"AFD_EVENT_ABORT",
"AFD_EVENT_CLOSE",
"AFD_EVENT_CONNECT",
"AFD_EVENT_ACCEPT",
"AFD_EVENT_CONNECT_FAIL",
"AFD_EVENT_QOS",
"AFD_EVENT_GROUP_QOS",
NULL };
int i;
for( i = 0; events_list[i]; i++ )
if( Events & (1 << i) ) AFD_DbgPrint(MID_TRACE,("%s ", events_list[i] ));
#endif
}
static VOID CopyBackStatus( PAFD_HANDLE HandleArray,
UINT HandleCount ) {
UINT i;
for( i = 0; i < HandleCount; i++ ) {
HandleArray[i].Events = HandleArray[i].Status;
HandleArray[i].Status = 0;
}
}
static VOID ZeroEvents( PAFD_HANDLE HandleArray,
UINT HandleCount ) {
UINT i;
for( i = 0; i < HandleCount; i++ )
HandleArray[i].Status = 0;
}
/* you must pass either Poll OR Irp */
static VOID SignalSocket(
PAFD_ACTIVE_POLL Poll OPTIONAL,
PIRP _Irp OPTIONAL,
PAFD_POLL_INFO PollReq,
NTSTATUS Status
)
{
UINT i;
PIRP Irp = _Irp ? _Irp : Poll->Irp;
AFD_DbgPrint(MID_TRACE,("Called (Status %x)\n", Status));
if (Poll)
{
KeCancelTimer( &Poll->Timer );
RemoveEntryList( &Poll->ListEntry );
ExFreePool( Poll );
}
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information =
FIELD_OFFSET(AFD_POLL_INFO, Handles) + sizeof(AFD_HANDLE) * PollReq->HandleCount;
CopyBackStatus( PollReq->Handles,
PollReq->HandleCount );
for( i = 0; i < PollReq->HandleCount; i++ ) {
AFD_DbgPrint
(MAX_TRACE,
("Handle(%x): Got %x,%x\n",
PollReq->Handles[i].Handle,
PollReq->Handles[i].Events,
PollReq->Handles[i].Status));
}
UnlockHandles( AFD_HANDLES(PollReq), PollReq->HandleCount );
AFD_DbgPrint(MID_TRACE,("Completing\n"));
IoCompleteRequest( Irp, IO_NETWORK_INCREMENT );
AFD_DbgPrint(MID_TRACE,("Done\n"));
}
static VOID SelectTimeout( PKDPC Dpc,
PVOID DeferredContext,
PVOID SystemArgument1,
PVOID SystemArgument2 ) {
PAFD_ACTIVE_POLL Poll = DeferredContext;
PAFD_POLL_INFO PollReq;
PIRP Irp;
KIRQL OldIrql;
PAFD_DEVICE_EXTENSION DeviceExt;
AFD_DbgPrint(MID_TRACE,("Called\n"));
Irp = Poll->Irp;
DeviceExt = Poll->DeviceExt;
PollReq = Irp->AssociatedIrp.SystemBuffer;
ZeroEvents( PollReq->Handles, PollReq->HandleCount );
KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
SignalSocket( Poll, NULL, PollReq, STATUS_TIMEOUT );
KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
AFD_DbgPrint(MID_TRACE,("Timeout\n"));
}
VOID KillSelectsForFCB( PAFD_DEVICE_EXTENSION DeviceExt,
PFILE_OBJECT FileObject,
BOOLEAN OnlyExclusive ) {
KIRQL OldIrql;
PLIST_ENTRY ListEntry;
PAFD_ACTIVE_POLL Poll;
PIRP Irp;
PAFD_POLL_INFO PollReq;
PAFD_HANDLE HandleArray;
UINT i;
AFD_DbgPrint(MID_TRACE,("Killing selects that refer to %x\n", FileObject));
KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
ListEntry = DeviceExt->Polls.Flink;
while ( ListEntry != &DeviceExt->Polls ) {
Poll = CONTAINING_RECORD(ListEntry, AFD_ACTIVE_POLL, ListEntry);
ListEntry = ListEntry->Flink;
Irp = Poll->Irp;
PollReq = Irp->AssociatedIrp.SystemBuffer;
HandleArray = AFD_HANDLES(PollReq);
for( i = 0; i < PollReq->HandleCount; i++ ) {
AFD_DbgPrint(MAX_TRACE,("Req: %x, This %x\n",
HandleArray[i].Handle, FileObject));
if( (PVOID)HandleArray[i].Handle == FileObject &&
(!OnlyExclusive || (OnlyExclusive && Poll->Exclusive)) ) {
ZeroEvents( PollReq->Handles, PollReq->HandleCount );
SignalSocket( Poll, NULL, PollReq, STATUS_SUCCESS );
}
}
}
KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
AFD_DbgPrint(MID_TRACE,("Done\n"));
}
NTSTATUS STDCALL
AfdSelect( PDEVICE_OBJECT DeviceObject, PIRP Irp,
PIO_STACK_LOCATION IrpSp ) {
NTSTATUS Status = STATUS_NO_MEMORY;
PAFD_FCB FCB;
PFILE_OBJECT FileObject;
PAFD_POLL_INFO PollReq = Irp->AssociatedIrp.SystemBuffer;
PAFD_DEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension;
UINT CopySize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
UINT AllocSize =
CopySize + sizeof(AFD_ACTIVE_POLL) - sizeof(AFD_POLL_INFO);
KIRQL OldIrql;
UINT i, Signalled = 0;
ULONG Exclusive = PollReq->Exclusive;
AFD_DbgPrint(MID_TRACE,("Called (HandleCount %d Timeout %d)\n",
PollReq->HandleCount,
(INT)(PollReq->Timeout.QuadPart)));
SET_AFD_HANDLES(PollReq,
LockHandles( PollReq->Handles, PollReq->HandleCount ));
if( !AFD_HANDLES(PollReq) ) {
Irp->IoStatus.Status = STATUS_NO_MEMORY;
Irp->IoStatus.Information = 0;
IoCompleteRequest( Irp, IO_NETWORK_INCREMENT );
return Irp->IoStatus.Status;
}
if( Exclusive ) {
for( i = 0; i < PollReq->HandleCount; i++ ) {
if( !AFD_HANDLES(PollReq)[i].Handle ) continue;
KillSelectsForFCB( DeviceExt,
(PFILE_OBJECT)AFD_HANDLES(PollReq)[i].Handle,
TRUE );
}
}
ZeroEvents( PollReq->Handles,
PollReq->HandleCount );
KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
for( i = 0; i < PollReq->HandleCount; i++ ) {
if( !AFD_HANDLES(PollReq)[i].Handle ) continue;
FileObject = (PFILE_OBJECT)AFD_HANDLES(PollReq)[i].Handle;
FCB = FileObject->FsContext;
if( (FCB->PollState & AFD_EVENT_CLOSE) ||
(PollReq->Handles[i].Status & AFD_EVENT_CLOSE) ) {
AFD_HANDLES(PollReq)[i].Handle = 0;
PollReq->Handles[i].Events = 0;
PollReq->Handles[i].Status = AFD_EVENT_CLOSE;
Signalled++;
} else {
AFD_DbgPrint(MID_TRACE, ("AFD: Select Events: "));
PrintEvents( PollReq->Handles[i].Events );
AFD_DbgPrint(MID_TRACE,("\n"));
PollReq->Handles[i].Status =
PollReq->Handles[i].Events & FCB->PollState;
if( PollReq->Handles[i].Status ) {
AFD_DbgPrint(MID_TRACE,("Signalling %x with %x\n",
FCB, FCB->PollState));
Signalled++;
}
}
}
if( Signalled ) {
Status = STATUS_SUCCESS;
Irp->IoStatus.Status = Status;
SignalSocket( NULL, Irp, PollReq, Status );
} else {
PAFD_ACTIVE_POLL Poll = NULL;
Poll = ExAllocatePool( NonPagedPool, AllocSize );
if (Poll){
Poll->Irp = Irp;
Poll->DeviceExt = DeviceExt;
Poll->Exclusive = Exclusive;
KeInitializeTimerEx( &Poll->Timer, NotificationTimer );
KeInitializeDpc( (PRKDPC)&Poll->TimeoutDpc,
(PKDEFERRED_ROUTINE)SelectTimeout,
Poll );
InsertTailList( &DeviceExt->Polls, &Poll->ListEntry );
KeSetTimer( &Poll->Timer, PollReq->Timeout, &Poll->TimeoutDpc );
Status = STATUS_PENDING;
IoMarkIrpPending( Irp );
} else {
AFD_DbgPrint(MAX_TRACE, ("FIXME: do something with the IRP!\n"));
Status = STATUS_NO_MEMORY;
}
}
KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
AFD_DbgPrint(MID_TRACE,("Returning %x\n", Status));
return Status;
}
NTSTATUS STDCALL
AfdEventSelect( PDEVICE_OBJECT DeviceObject, PIRP Irp,
PIO_STACK_LOCATION IrpSp ) {
PFILE_OBJECT FileObject = IrpSp->FileObject;
NTSTATUS Status = STATUS_NO_MEMORY;
PAFD_EVENT_SELECT_INFO EventSelectInfo =
(PAFD_EVENT_SELECT_INFO)LockRequest( Irp, IrpSp );
PAFD_FCB FCB = FileObject->FsContext;
AFD_DbgPrint(MID_TRACE,("Called (Event %x Triggers %x)\n",
EventSelectInfo->EventObject,
EventSelectInfo->Events));
if( !SocketAcquireStateLock( FCB ) ) {
UnlockRequest( Irp, IrpSp );
return LostSocket( Irp, FALSE );
}
FCB->EventSelectTriggers = FCB->EventsFired = 0;
if( FCB->EventSelect ) ObDereferenceObject( FCB->EventSelect );
FCB->EventSelect = NULL;
if( EventSelectInfo->EventObject && EventSelectInfo->Events ) {
Status = ObReferenceObjectByHandle( (PVOID)EventSelectInfo->
EventObject,
FILE_ALL_ACCESS,
NULL,
KernelMode,
(PVOID *)&FCB->EventSelect,
NULL );
if( !NT_SUCCESS(Status) )
FCB->EventSelect = NULL;
else
FCB->EventSelectTriggers = EventSelectInfo->Events;
} else /* Work done, cancelling select */
Status = STATUS_SUCCESS;
AFD_DbgPrint(MID_TRACE,("Returning %x\n", Status));
return UnlockAndMaybeComplete( FCB, STATUS_SUCCESS, Irp,
0, NULL, TRUE );
}
NTSTATUS STDCALL
AfdEnumEvents( PDEVICE_OBJECT DeviceObject, PIRP Irp,
PIO_STACK_LOCATION IrpSp ) {
PFILE_OBJECT FileObject = IrpSp->FileObject;
PAFD_ENUM_NETWORK_EVENTS_INFO EnumReq =
(PAFD_ENUM_NETWORK_EVENTS_INFO)LockRequest( Irp, IrpSp );
PAFD_FCB FCB = FileObject->FsContext;
AFD_DbgPrint(MID_TRACE,("Called (FCB %x)\n", FCB));
if( !SocketAcquireStateLock( FCB ) ) {
UnlockRequest( Irp, IrpSp );
return LostSocket( Irp, FALSE );
}
EnumReq->PollEvents = FCB->PollState;
RtlZeroMemory( EnumReq->EventStatus, sizeof(EnumReq->EventStatus) );
return UnlockAndMaybeComplete( FCB, STATUS_SUCCESS, Irp,
0, NULL, TRUE );
}
/* * * NOTE ALWAYS CALLED AT DISPATCH_LEVEL * * */
static BOOLEAN UpdatePollWithFCB( PAFD_ACTIVE_POLL Poll, PFILE_OBJECT FileObject ) {
UINT i;
PAFD_FCB FCB;
UINT Signalled = 0;
PAFD_POLL_INFO PollReq = Poll->Irp->AssociatedIrp.SystemBuffer;
ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
for( i = 0; i < PollReq->HandleCount; i++ ) {
if( !AFD_HANDLES(PollReq)[i].Handle ) continue;
FileObject = (PFILE_OBJECT)AFD_HANDLES(PollReq)[i].Handle;
FCB = FileObject->FsContext;
if( (FCB->PollState & AFD_EVENT_CLOSE) ||
(PollReq->Handles[i].Status & AFD_EVENT_CLOSE) ) {
AFD_HANDLES(PollReq)[i].Handle = 0;
PollReq->Handles[i].Events = 0;
PollReq->Handles[i].Status = AFD_EVENT_CLOSE;
Signalled++;
} else {
PollReq->Handles[i].Status =
PollReq->Handles[i].Events & FCB->PollState;
if( PollReq->Handles[i].Status ) {
AFD_DbgPrint(MID_TRACE,("Signalling %x with %x\n",
FCB, FCB->PollState));
Signalled++;
}
}
}
return Signalled ? 1 : 0;
}
VOID PollReeval( PAFD_DEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject ) {
PAFD_ACTIVE_POLL Poll = NULL;
PLIST_ENTRY ThePollEnt = NULL;
PAFD_FCB FCB;
KIRQL OldIrql;
PAFD_POLL_INFO PollReq;
PKEVENT EventSelect = NULL;
AFD_DbgPrint(MID_TRACE,("Called: DeviceExt %x FileObject %x\n",
DeviceExt, FileObject));
KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
/* Take care of any event select signalling */
FCB = (PAFD_FCB)FileObject->FsContext;
/* Not sure if i can do this at DISPATCH_LEVEL ... try it at passive */
AFD_DbgPrint(MID_TRACE,("Current State: %x, Events Fired: %x, "
"Select Triggers %x\n",
FCB->PollState, FCB->EventsFired,
FCB->EventSelectTriggers));
if( FCB->PollState & ~FCB->EventsFired & FCB->EventSelectTriggers ) {
FCB->EventsFired |= FCB->PollState;
EventSelect = FCB->EventSelect;
}
if( !FCB ) {
KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
return;
}
/* Now signal normal select irps */
ThePollEnt = DeviceExt->Polls.Flink;
while( ThePollEnt != &DeviceExt->Polls ) {
Poll = CONTAINING_RECORD( ThePollEnt, AFD_ACTIVE_POLL, ListEntry );
PollReq = Poll->Irp->AssociatedIrp.SystemBuffer;
AFD_DbgPrint(MID_TRACE,("Checking poll %x\n", Poll));
if( UpdatePollWithFCB( Poll, FileObject ) ) {
ThePollEnt = ThePollEnt->Flink;
AFD_DbgPrint(MID_TRACE,("Signalling socket\n"));
SignalSocket( Poll, NULL, PollReq, STATUS_SUCCESS );
} else
ThePollEnt = ThePollEnt->Flink;
}
KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
AFD_DbgPrint(MID_TRACE,("Setting event %x\n", EventSelect));
if( EventSelect ) KeSetEvent( EventSelect, IO_NETWORK_INCREMENT, FALSE );
AFD_DbgPrint(MID_TRACE,("Leaving\n"));
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -