⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 read.c

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $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 + -