WindowsXP-SP1/inetsrv/iis/svcs/infocomm/spuddrv/sendrecv.c

357 lines
8.9 KiB
C
Raw Permalink Normal View History

2001-01-01 00:00:00 +01:00
/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
sendrecv.c
Abstract:
This module contains the SPUDSendAndRecv service.
Author:
John Ballard (jballard) 21-Oct-1996
Revision History:
Keith Moore (keithmo) 04-Feb-1998
Cleanup, added much needed comments.
--*/
#include "spudp.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, SPUDSendAndRecv )
#endif
//
// Public functions.
//
NTSTATUS
SPUDSendAndRecv(
HANDLE hSocket,
struct _AFD_SEND_INFO *sendInfo,
struct _AFD_RECV_INFO *recvInfo,
PSPUD_REQ_CONTEXT reqContext
)
/*++
Routine Description:
Batch send & receive request.
Arguments:
hSocket - The target socket for the request.
sendInfo - Information describing the send.
recvInfo - Information describing the receive.
reqContext - The user-mode context for the request.
Return Value:
NTSTATUS - Completion status.
--*/
{
NTSTATUS status;
PFILE_OBJECT fileObject;
IO_STATUS_BLOCK localIoStatus;
PIRP irp;
PIO_STACK_LOCATION irpSp;
PSPUD_AFD_REQ_CONTEXT SpudReqContext;
PVOID completionPort;
//
// Sanity check.
//
PAGED_CODE();
status = SPUD_ENTER_SERVICE( "SPUDSendAndRecv", TRUE );
if( !NT_SUCCESS(status) ) {
return status;
}
BumpCount( CtrSendAndRecv );
//
// SPUD doesn't support kernel-mode callers. In fact, we don't
// even build the "system stubs" necessary to invoke SPUD from
// kernel-mode.
//
ASSERT( ExGetPreviousMode() == UserMode );
try {
//
// Make sure we can write to reqContext
//
ProbeForWrite(
reqContext,
sizeof(SPUD_REQ_CONTEXT),
sizeof(ULONG)
);
//
// Make initial status invalid
//
reqContext->IoStatus1.Status = 0xffffffff;
reqContext->IoStatus1.Information = 0;
reqContext->IoStatus2.Status = 0xffffffff;
reqContext->IoStatus2.Information = 0;
reqContext->ReqType = SendAndRecv;
reqContext->KernelReqInfo = SPUD_INVALID_REQ_HANDLE;
//
// Make sure the buffer looks good
//
ProbeForRead(
recvInfo,
sizeof(*recvInfo),
sizeof(ULONG)
);
if( recvInfo->BufferCount < 1 ) {
ExRaiseStatus( STATUS_INVALID_PARAMETER );
}
ProbeForRead(
recvInfo->BufferArray,
sizeof(*recvInfo->BufferArray),
sizeof(ULONG)
);
ProbeForRead(
recvInfo->BufferArray->buf,
recvInfo->BufferArray->len,
sizeof(UCHAR)
);
} except( EXCEPTION_EXECUTE_HANDLER ) {
status = GetExceptionCode();
SPUD_LEAVE_SERVICE( "SPUDSendAndRecv", status, FALSE );
return status;
}
//
// Reference the socket handle
//
status = ObReferenceObjectByHandle(
hSocket,
0L,
*IoFileObjectType,
UserMode,
(PVOID *)&fileObject,
NULL
);
if( !NT_SUCCESS(status) ) {
SPUD_LEAVE_SERVICE( "SPUDSendAndRecv", status, FALSE );
return status;
}
TRACE_OB_REFERENCE( fileObject );
//
// If we haven't already cached the Device Object and FastIoControl
// pointers, then do so now.
//
if( !SpudAfdDeviceObject ) {
status = SpudGetAfdDeviceObject( fileObject );
if( !NT_SUCCESS(status) ) {
TRACE_OB_DEREFERENCE( fileObject );
ObDereferenceObject( fileObject );
status = STATUS_INVALID_DEVICE_REQUEST;
SPUD_LEAVE_SERVICE( "SPUDSendAndRecv", status, FALSE );
return status;
}
}
//
// Reference the completion port.
//
completionPort = SpudReferenceCompletionPort();
if( completionPort == NULL ) {
TRACE_OB_DEREFERENCE( fileObject );
ObDereferenceObject( fileObject );
status = STATUS_INVALID_DEVICE_REQUEST;
SPUD_LEAVE_SERVICE( "SPUDSendAndRecv", status, FALSE );
return status;
}
//
// Let's check to see if fast io will work
//
if( SpudAfdFastIoDeviceControl(
fileObject,
TRUE,
(PVOID)sendInfo,
sizeof(AFD_SEND_INFO),
NULL,
0,
IOCTL_AFD_SEND,
&localIoStatus,
SpudAfdDeviceObject
)) {
BumpCount( CtrSendRecvFastSend );
//
// Lets remember the completion status for this operation
//
try {
reqContext->IoStatus1 = localIoStatus;
} except( EXCEPTION_EXECUTE_HANDLER) {
localIoStatus.Status = GetExceptionCode();
localIoStatus.Information = 0;
}
if( localIoStatus.Status == STATUS_SUCCESS ) {
localIoStatus.Status = SpudAfdRecvFastReq(
fileObject,
recvInfo,
reqContext
);
}
//
// If everything completed without pending then we can queue
// a completion packet to the port now.
//
// Note that we must not queue a completion packet if the
// request is failing in-line.
//
if( localIoStatus.Status != STATUS_PENDING ) {
if( NT_SUCCESS(localIoStatus.Status) ) {
localIoStatus.Status = IoSetIoCompletion(
SpudCompletionPort, // IoCompletion
reqContext, // KeyContext
NULL, // ApcContext
STATUS_SUCCESS, // IoStatus
0xFFFFFFFF, // IoStatusInformation
TRUE // Quota
);
}
TRACE_OB_DEREFERENCE( fileObject );
ObDereferenceObject( fileObject );
}
//
// At this point, we know the fast-path send has completed
// in-line and the receive either completed in-line or has pended.
// Since it is the receive code's responsibility to add any necessary
// references to the completion port (and since we know the send
// has not pended) we can remove the reference we added above.
//
SPUD_LEAVE_SERVICE( "SPUDSendAndRecv", localIoStatus.Status, TRUE );
return localIoStatus.Status;
}
BumpCount( CtrSendRecvSlowSend );
//
// It looks like we will have to it the hard way.
// We will now build an IRP for AFD.
//
KeClearEvent( &fileObject->Event );
//
// Allocate and initialize the IRP.
//
irp = IoAllocateIrp( SpudAfdDeviceObject->StackSize, TRUE );
if( !irp ) {
TRACE_OB_DEREFERENCE( fileObject );
ObDereferenceObject( fileObject );
status = STATUS_INSUFFICIENT_RESOURCES;
SPUD_LEAVE_SERVICE( "SPUDSendAndRecv", status, TRUE );
return status;
}
status = SpudAllocateRequestContext(
&SpudReqContext,
reqContext,
recvInfo,
irp,
NULL
);
if( !NT_SUCCESS(status) ) {
TRACE_OB_DEREFERENCE( fileObject );
ObDereferenceObject( fileObject );
IoFreeIrp( irp );
SPUD_LEAVE_SERVICE( "SPUDSendAndRecv", status, TRUE );
return status;
}
BumpCount( CtrSendRecvSlowRecv );
irp->RequestorMode = UserMode;
irp->Tail.Overlay.OriginalFileObject = fileObject;
irp->Tail.Overlay.Thread = PsGetCurrentThread();
IoQueueThreadIrp( irp );
irpSp = IoGetNextIrpStackLocation( irp );
irpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
irpSp->FileObject = fileObject;
irpSp->DeviceObject = SpudAfdDeviceObject;
// irpSp->Parameters.DeviceIoControl.OutputBufferLength = 0;
irpSp->Parameters.DeviceIoControl.InputBufferLength = sizeof(AFD_SEND_INFO);
irpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_AFD_SEND;
irpSp->Parameters.DeviceIoControl.Type3InputBuffer = sendInfo;
IoSetCompletionRoutine(
irp,
SpudAfdContinueRecv,
SpudReqContext,
TRUE,
TRUE,
TRUE
);
IoCallDriver( SpudAfdDeviceObject, irp );
status = STATUS_PENDING;
SPUD_LEAVE_SERVICE( "SPUDSendAndRecv", status, FALSE );
return status;
} // SPUDSendAndRecv