📄 read.c
字号:
/* $Id: read.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/read.c
* PURPOSE: Ancillary functions driver
* PROGRAMMER: Art Yerkes (ayerkes@speakeasy.net)
* UPDATE HISTORY:
* 20040708 Created
*
* Improve buffering code
*
* We're keeping data receiving in one of two states:
* A) Some data available in the FCB
* FCB->Recv.BytesUsed != FCB->Recv.Content
* FCB->ReceiveIrp.InFlightRequest == NULL
* AFD_EVENT_RECEIVE set in FCB->PollState
* B) No data available in the FCB
* FCB->Recv.BytesUsed == FCB->Recv.Content (== 0)
* FCB->RecieveIrp.InFlightRequest != NULL
* AFD_EVENT_RECEIVED not set in FCB->PollState
* So basically we either have data available or a TDI receive
* in flight.
*/
#include "afd.h"
#include "tdi_proto.h"
#include "tdiconn.h"
#include "debug.h"
static BOOLEAN CantReadMore( PAFD_FCB FCB ) {
UINT BytesAvailable = FCB->Recv.Content - FCB->Recv.BytesUsed;
return !BytesAvailable &&
(FCB->PollState & (AFD_EVENT_CLOSE | AFD_EVENT_DISCONNECT));
}
static VOID HandleEOFOnIrp( PAFD_FCB FCB, NTSTATUS Status, UINT Information ) {
if( Status == STATUS_SUCCESS && Information == 0 ) {
AFD_DbgPrint(MID_TRACE,("Looks like an EOF\n"));
FCB->PollState |= AFD_EVENT_DISCONNECT;
PollReeval( FCB->DeviceExt, FCB->FileObject );
}
}
static NTSTATUS TryToSatisfyRecvRequestFromBuffer( PAFD_FCB FCB,
PAFD_RECV_INFO RecvReq,
PUINT TotalBytesCopied ) {
UINT i, BytesToCopy = 0,
BytesAvailable =
FCB->Recv.Content - FCB->Recv.BytesUsed;
PAFD_MAPBUF Map;
NTSTATUS Status;
*TotalBytesCopied = 0;
AFD_DbgPrint(MID_TRACE,("Called, BytesAvailable = %d\n",
BytesAvailable));
if( CantReadMore(FCB) ) return STATUS_SUCCESS;
if( !BytesAvailable ) return STATUS_PENDING;
Map = (PAFD_MAPBUF)(RecvReq->BufferArray + RecvReq->BufferCount);
AFD_DbgPrint(MID_TRACE,("Buffer Count: %d @ %x\n",
RecvReq->BufferCount,
RecvReq->BufferArray));
for( i = 0;
RecvReq->BufferArray &&
BytesAvailable &&
i < RecvReq->BufferCount;
i++ ) {
BytesToCopy =
MIN( RecvReq->BufferArray[i].len, BytesAvailable );
if( Map[i].Mdl ) {
Map[i].BufferAddress = MmMapLockedPages( Map[i].Mdl, KernelMode );
AFD_DbgPrint(MID_TRACE,("Buffer %d: %x:%d\n",
i,
Map[i].BufferAddress,
BytesToCopy));
RtlCopyMemory( Map[i].BufferAddress,
FCB->Recv.Window + FCB->Recv.BytesUsed,
BytesToCopy );
MmUnmapLockedPages( Map[i].BufferAddress, Map[i].Mdl );
FCB->Recv.BytesUsed += BytesToCopy;
*TotalBytesCopied += BytesToCopy;
BytesAvailable -= BytesToCopy;
}
}
/* If there's nothing left in our buffer start a new request */
if( FCB->Recv.BytesUsed == FCB->Recv.Content ) {
FCB->Recv.BytesUsed = FCB->Recv.Content = 0;
FCB->PollState &= ~AFD_EVENT_RECEIVE;
if( !FCB->ReceiveIrp.InFlightRequest ) {
AFD_DbgPrint(MID_TRACE,("Replenishing buffer\n"));
SocketCalloutEnter( FCB );
Status = TdiReceive( &FCB->ReceiveIrp.InFlightRequest,
FCB->Connection.Object,
TDI_RECEIVE_NORMAL,
FCB->Recv.Window,
FCB->Recv.Size,
&FCB->ReceiveIrp.Iosb,
ReceiveComplete,
FCB );
SocketCalloutLeave( FCB );
if( Status == STATUS_SUCCESS )
FCB->Recv.Content = FCB->ReceiveIrp.Iosb.Information;
HandleEOFOnIrp( FCB, Status, FCB->ReceiveIrp.Iosb.Information );
}
}
return STATUS_SUCCESS;
}
static NTSTATUS ReceiveActivity( PAFD_FCB FCB, PIRP Irp ) {
PLIST_ENTRY NextIrpEntry;
PIRP NextIrp;
PIO_STACK_LOCATION NextIrpSp;
PAFD_RECV_INFO RecvReq;
UINT TotalBytesCopied = 0;
NTSTATUS Status = STATUS_SUCCESS, RetStatus = STATUS_PENDING;
AFD_DbgPrint(MID_TRACE,("%x %x\n", FCB, Irp));
if( CantReadMore( FCB ) ) {
/* Success here means that we got an EOF. Complete a pending read
* with zero bytes if we haven't yet overread, then kill the others.
*/
while( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_RECV] ) ) {
NextIrpEntry =
RemoveHeadList(&FCB->PendingIrpList[FUNCTION_RECV]);
NextIrp =
CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
NextIrpSp = IoGetCurrentIrpStackLocation( NextIrp );
RecvReq = NextIrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
AFD_DbgPrint(MID_TRACE,("Completing recv %x (%d)\n", NextIrp,
TotalBytesCopied));
UnlockBuffers( RecvReq->BufferArray,
RecvReq->BufferCount, FALSE );
Status = NextIrp->IoStatus.Status =
FCB->Overread ? STATUS_END_OF_FILE : STATUS_SUCCESS;
NextIrp->IoStatus.Information = 0;
if( NextIrp == Irp ) RetStatus = Status;
IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
FCB->Overread = TRUE;
//FCB->PollState |= AFD_EVENT_DISCONNECT;
PollReeval( FCB->DeviceExt, FCB->FileObject );
}
} else {
/* Kick the user that receive would be possible now */
/* XXX Not implemented yet */
AFD_DbgPrint(MID_TRACE,("FCB %x Receive data waiting %d\n",
FCB, FCB->Recv.Content));
/*OskitDumpBuffer( FCB->Recv.Window, FCB->Recv.Content );*/
Status = STATUS_SUCCESS;
/* Try to clear some requests */
while( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_RECV] ) &&
NT_SUCCESS(Status) ) {
NextIrpEntry =
RemoveHeadList(&FCB->PendingIrpList[FUNCTION_RECV]);
NextIrp =
CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
NextIrpSp = IoGetCurrentIrpStackLocation( NextIrp );
RecvReq = NextIrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
AFD_DbgPrint(MID_TRACE,("RecvReq @ %x\n", RecvReq));
Status = TryToSatisfyRecvRequestFromBuffer
( FCB, RecvReq, &TotalBytesCopied );
if( Status == STATUS_PENDING ) {
AFD_DbgPrint(MID_TRACE,("Ran out of data for %x\n", NextIrp));
InsertHeadList(&FCB->PendingIrpList[FUNCTION_RECV],
&NextIrp->Tail.Overlay.ListEntry);
break;
} else {
AFD_DbgPrint(MID_TRACE,("Completing recv %x (%d)\n", NextIrp,
TotalBytesCopied));
UnlockBuffers( RecvReq->BufferArray,
RecvReq->BufferCount, FALSE );
NextIrp->IoStatus.Status = Status;
NextIrp->IoStatus.Information = TotalBytesCopied;
if( NextIrp == Irp ) RetStatus = Status;
IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
}
}
}
if( FCB->Recv.Content ) {
FCB->PollState |= AFD_EVENT_RECEIVE;
} else
FCB->PollState &= ~AFD_EVENT_RECEIVE;
PollReeval( FCB->DeviceExt, FCB->FileObject );
AFD_DbgPrint(MID_TRACE,("RetStatus for irp %x is %x\n", Irp, RetStatus));
return RetStatus;
}
NTSTATUS NTAPI ReceiveComplete
( PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID Context ) {
NTSTATUS Status = Irp->IoStatus.Status;
PAFD_FCB FCB = (PAFD_FCB)Context;
AFD_DbgPrint(MID_TRACE,("Called\n"));
ASSERT_IRQL(APC_LEVEL);
if( !SocketAcquireStateLock( FCB ) ) return Status;
FCB->ReceiveIrp.InFlightRequest = NULL;
FCB->Recv.Content = Irp->IoStatus.Information;
FCB->Recv.BytesUsed = 0;
if( FCB->State == SOCKET_STATE_CLOSED ) {
AFD_DbgPrint(MIN_TRACE,("!!! CLOSED SOCK GOT A RECEIVE COMPLETE !!!\n"));
SocketStateUnlock( FCB );
DestroySocket( FCB );
return STATUS_SUCCESS;
} else if( FCB->State == SOCKET_STATE_LISTENING ) {
AFD_DbgPrint(MIN_TRACE,("!!! LISTENER GOT A RECEIVE COMPLETE !!!\n"));
SocketStateUnlock( FCB );
return STATUS_UNSUCCESSFUL;
}
HandleEOFOnIrp( FCB, Irp->IoStatus.Status, Irp->IoStatus.Information );
ReceiveActivity( FCB, NULL );
PollReeval( FCB->DeviceExt, FCB->FileObject );
SocketStateUnlock( FCB );
AFD_DbgPrint(MID_TRACE,("Returned %x\n", Status));
return STATUS_SUCCESS;
}
NTSTATUS STDCALL
AfdConnectedSocketReadData(PDEVICE_OBJECT DeviceObject, PIRP Irp,
PIO_STACK_LOCATION IrpSp, BOOLEAN Short) {
NTSTATUS Status = STATUS_INVALID_PARAMETER;
PFILE_OBJECT FileObject = IrpSp->FileObject;
PAFD_FCB FCB = FileObject->FsContext;
PAFD_RECV_INFO RecvReq;
UINT TotalBytesCopied = 0;
AFD_DbgPrint(MID_TRACE,("Called on %x\n", FCB));
if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp, FALSE );
if( FCB->State != SOCKET_STATE_CONNECTED &&
FCB->State != SOCKET_STATE_CONNECTING ) {
AFD_DbgPrint(MID_TRACE,("Called recv on wrong kind of socket (s%x)\n",
FCB->State));
return UnlockAndMaybeComplete( FCB, STATUS_UNSUCCESSFUL,
Irp, 0, NULL, FALSE );
}
if( FCB->Flags & AFD_ENDPOINT_CONNECTIONLESS )
{
AFD_DbgPrint(MID_TRACE,("Receive on connection-less sockets not implemented\n"));
return UnlockAndMaybeComplete( FCB, STATUS_NOT_IMPLEMENTED,
Irp, 0, NULL, FALSE );
}
FCB->EventsFired &= ~AFD_EVENT_RECEIVE;
PollReeval( FCB->DeviceExt, FCB->FileObject );
if( !(RecvReq = LockRequest( Irp, IrpSp )) )
return UnlockAndMaybeComplete( FCB, STATUS_NO_MEMORY,
Irp, 0, NULL, FALSE );
AFD_DbgPrint(MID_TRACE,("Recv flags %x\n", RecvReq->AfdFlags));
RecvReq->BufferArray = LockBuffers( RecvReq->BufferArray,
RecvReq->BufferCount,
NULL, NULL,
TRUE, FALSE );
if( !RecvReq->BufferArray ) {
return UnlockAndMaybeComplete( FCB, STATUS_ACCESS_VIOLATION,
Irp, 0, NULL, FALSE );
}
Irp->IoStatus.Status = STATUS_PENDING;
Irp->IoStatus.Information = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -