NTSTATUS TdiSendMessage( ULONG Ip, USHORT Port, PCHAR Message, ULONG Length ) { PFILE_OBJECT ConnectionFileObject, AddressFileObject; HANDLE AddressHandle, ConnectionHandle; CHAR Buffer[80], Data[] = "Hello from Gary"; NTSTATUS Status; KEVENT Done; KeInitializeEvent(&Done, NotificationEvent, FALSE); Status = TdiCreateConnection(&ConnectionHandle, &ConnectionFileObject); if (!NT_SUCCESS(Status)) return Status; Status = TdiCreateAddress(&AddressHandle, &AddressFileObject, SOCK_STREAM, 0, 0); if (!NT_SUCCESS(Status)) return Status; do { IO_STATUS_BLOCK IoStatus; KEVENT Event; Status = TdiSetEventHandler(AddressFileObject, TDI_EVENT_DISCONNECT, TdiEventDisconnect, &Done); if (!NT_SUCCESS(Status)) break; Status = TdiSetEventHandler(AddressFileObject, TDI_EVENT_ERROR, TdiEventError, 0); if (!NT_SUCCESS(Status)) break; Status = TdiSetEventHandler(AddressFileObject, TDI_EVENT_RECEIVE, TdiEventReceive, 0); if (!NT_SUCCESS(Status)) break; Status = TdiBind(ConnectionFileObject, AddressHandle); if (!NT_SUCCESS(Status)) break; Status = TdiConnect(ConnectionFileObject, Ip, Port, NULL); if (!NT_SUCCESS(Status)) break; Status = TdiSend(ConnectionFileObject, Message, Length); if (!NT_SUCCESS(Status)) break; Status = TdiDisconnect(ConnectionFileObject); if (!NT_SUCCESS(Status)) break; KeWaitForSingleObject(&Done, UserRequest, KernelMode, FALSE, 0); } while (0); ObDereferenceObject(ConnectionFileObject); ObDereferenceObject(AddressFileObject); ZwClose(ConnectionHandle); ZwClose(AddressHandle); return Status; }
NTSTATUS TdiTest() { PFILE_OBJECT ConnectionFileObject, AddressFileObject; HANDLE AddressHandle, ConnectionHandle; CHAR Buffer[80], Data[] = "Hello from Gary"; NTSTATUS Status; KEVENT Done; KeInitializeEvent(&Done, NotificationEvent, FALSE); Status = TdiCreateConnection(&ConnectionHandle, &ConnectionFileObject); if (!NT_SUCCESS(Status)) return Status; Status = TdiCreateAddress(&AddressHandle, &AddressFileObject, SOCK_STREAM, 0, 0); if (!NT_SUCCESS(Status)) return Status; do { IO_STATUS_BLOCK IoStatus = {0}; KEVENT Event; Status = TdiSetEventHandler(AddressFileObject, TDI_EVENT_DISCONNECT, TdiEventDisconnect, &Done); if (!NT_SUCCESS(Status)) break; Status = TdiSetEventHandler(AddressFileObject, TDI_EVENT_ERROR, TdiEventError, 0); if (!NT_SUCCESS(Status)) break; Status = TdiSetEventHandler(AddressFileObject, TDI_EVENT_RECEIVE, TdiEventReceive, 0); if (!NT_SUCCESS(Status)) break; Status = TdiBind(ConnectionFileObject, AddressHandle); if (!NT_SUCCESS(Status)) break; Status = TdiConnect(ConnectionFileObject, 0x41A1F6A8, 0x700, NULL); if (!NT_SUCCESS(Status)) break; KeInitializeEvent(&Event, NotificationEvent, FALSE); // Status = TdiRecv(ConnectionFileObject, Buffer, sizeof Buffer, &Event, &IoStatus); // if (!NT_SUCCESS(Status)) break; Status = TdiSend(ConnectionFileObject, Data, sizeof Data); if (!NT_SUCCESS(Status)) break; Status = TdiSend(ConnectionFileObject, Data, sizeof Data); if (!NT_SUCCESS(Status)) break; Status = TdiSend(ConnectionFileObject, Data, sizeof Data); if (!NT_SUCCESS(Status)) break; Status = TdiDisconnect(ConnectionFileObject); if (!NT_SUCCESS(Status)) break; Status = KeWaitForSingleObject(&Event, UserRequest, KernelMode, FALSE, 0); if (Status == STATUS_SUCCESS) Status = IoStatus.Status; DbgPrint("Status = %lx, IoStatus.Status = %lx, IoStatus.Information = %ld\n", Status, IoStatus.Status, IoStatus.Information); KeWaitForSingleObject(&Done, UserRequest, KernelMode, FALSE, 0); } while (0); ObDereferenceObject(ConnectionFileObject); ObDereferenceObject(AddressFileObject); ZwClose(ConnectionHandle); ZwClose(AddressHandle); return Status; }
NTSTATUS NTAPI AfdConnectedSocketWriteData(PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp, BOOLEAN Short) { NTSTATUS Status = STATUS_SUCCESS; PFILE_OBJECT FileObject = IrpSp->FileObject; PAFD_FCB FCB = FileObject->FsContext; PAFD_SEND_INFO SendReq; UINT TotalBytesCopied = 0, i, SpaceAvail = 0, BytesCopied, SendLength; KPROCESSOR_MODE LockMode; UNREFERENCED_PARAMETER(DeviceObject); UNREFERENCED_PARAMETER(Short); AFD_DbgPrint(MID_TRACE,("Called on %p\n", FCB)); if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp ); FCB->EventSelectDisabled &= ~AFD_EVENT_SEND; if( FCB->Flags & AFD_ENDPOINT_CONNECTIONLESS ) { PAFD_SEND_INFO_UDP SendReq; PTDI_CONNECTION_INFORMATION TargetAddress; /* Check that the socket is bound */ if( FCB->State != SOCKET_STATE_BOUND || !FCB->RemoteAddress ) { AFD_DbgPrint(MIN_TRACE,("Invalid parameter\n")); return UnlockAndMaybeComplete( FCB, STATUS_INVALID_PARAMETER, Irp, 0 ); } if( !(SendReq = LockRequest( Irp, IrpSp, FALSE, &LockMode )) ) return UnlockAndMaybeComplete( FCB, STATUS_NO_MEMORY, Irp, 0 ); /* Must lock buffers before handing off user data */ SendReq->BufferArray = LockBuffers( SendReq->BufferArray, SendReq->BufferCount, NULL, NULL, FALSE, FALSE, LockMode ); if( !SendReq->BufferArray ) { return UnlockAndMaybeComplete( FCB, STATUS_ACCESS_VIOLATION, Irp, 0 ); } Status = TdiBuildConnectionInfo( &TargetAddress, FCB->RemoteAddress ); if( NT_SUCCESS(Status) ) { FCB->PollState &= ~AFD_EVENT_SEND; Status = QueueUserModeIrp(FCB, Irp, FUNCTION_SEND); if (Status == STATUS_PENDING) { TdiSendDatagram(&FCB->SendIrp.InFlightRequest, FCB->AddressFile.Object, SendReq->BufferArray[0].buf, SendReq->BufferArray[0].len, TargetAddress, PacketSocketSendComplete, FCB); } ExFreePool( TargetAddress ); SocketStateUnlock(FCB); return STATUS_PENDING; } else { UnlockBuffers(SendReq->BufferArray, SendReq->BufferCount, FALSE); return UnlockAndMaybeComplete( FCB, Status, Irp, 0 ); } } if (FCB->PollState & AFD_EVENT_CLOSE) { AFD_DbgPrint(MIN_TRACE,("Connection reset by remote peer\n")); /* This is an unexpected remote disconnect */ return UnlockAndMaybeComplete(FCB, FCB->PollStatus[FD_CLOSE_BIT], Irp, 0); } if (FCB->PollState & AFD_EVENT_ABORT) { AFD_DbgPrint(MIN_TRACE,("Connection aborted\n")); /* This is an abortive socket closure on our side */ return UnlockAndMaybeComplete(FCB, FCB->PollStatus[FD_CLOSE_BIT], Irp, 0); } if (FCB->SendClosed) { AFD_DbgPrint(MIN_TRACE,("No more sends\n")); /* This is a graceful send closure */ return UnlockAndMaybeComplete(FCB, STATUS_FILE_CLOSED, Irp, 0); } if( !(SendReq = LockRequest( Irp, IrpSp, FALSE, &LockMode )) ) return UnlockAndMaybeComplete ( FCB, STATUS_NO_MEMORY, Irp, 0 ); SendReq->BufferArray = LockBuffers( SendReq->BufferArray, SendReq->BufferCount, NULL, NULL, FALSE, FALSE, LockMode ); if( !SendReq->BufferArray ) { return UnlockAndMaybeComplete( FCB, STATUS_ACCESS_VIOLATION, Irp, 0 ); } AFD_DbgPrint(MID_TRACE,("Socket state %u\n", FCB->State)); if( FCB->State != SOCKET_STATE_CONNECTED ) { if (!(SendReq->AfdFlags & AFD_OVERLAPPED) && ((SendReq->AfdFlags & AFD_IMMEDIATE) || (FCB->NonBlocking))) { AFD_DbgPrint(MID_TRACE,("Nonblocking\n")); UnlockBuffers( SendReq->BufferArray, SendReq->BufferCount, FALSE ); return UnlockAndMaybeComplete( FCB, STATUS_CANT_WAIT, Irp, 0 ); } else { AFD_DbgPrint(MID_TRACE,("Queuing request\n")); return LeaveIrpUntilLater( FCB, Irp, FUNCTION_SEND ); } } AFD_DbgPrint(MID_TRACE,("FCB->Send.BytesUsed = %u\n", FCB->Send.BytesUsed)); SpaceAvail = FCB->Send.Size - FCB->Send.BytesUsed; AFD_DbgPrint(MID_TRACE,("We can accept %u bytes\n", SpaceAvail)); /* Count the total transfer size */ SendLength = 0; for (i = 0; i < SendReq->BufferCount; i++) { SendLength += SendReq->BufferArray[i].len; } /* Make sure we've got the space */ if (SendLength > SpaceAvail) { /* Blocking sockets have to wait here */ if (SendLength <= FCB->Send.Size && !((SendReq->AfdFlags & AFD_IMMEDIATE) || (FCB->NonBlocking))) { FCB->PollState &= ~AFD_EVENT_SEND; return LeaveIrpUntilLater(FCB, Irp, FUNCTION_SEND); } /* Check if we can send anything */ if (SpaceAvail == 0) { FCB->PollState &= ~AFD_EVENT_SEND; /* Non-overlapped sockets will fail if we can send nothing */ if (!(SendReq->AfdFlags & AFD_OVERLAPPED)) { UnlockBuffers( SendReq->BufferArray, SendReq->BufferCount, FALSE ); return UnlockAndMaybeComplete( FCB, STATUS_CANT_WAIT, Irp, 0 ); } else { /* Overlapped sockets just pend */ return LeaveIrpUntilLater(FCB, Irp, FUNCTION_SEND); } } } for ( i = 0; SpaceAvail > 0 && i < SendReq->BufferCount; i++ ) { BytesCopied = MIN(SendReq->BufferArray[i].len, SpaceAvail); AFD_DbgPrint(MID_TRACE,("Copying Buffer %u, %p:%u to %p\n", i, SendReq->BufferArray[i].buf, BytesCopied, FCB->Send.Window + FCB->Send.BytesUsed)); RtlCopyMemory(FCB->Send.Window + FCB->Send.BytesUsed, SendReq->BufferArray[i].buf, BytesCopied); TotalBytesCopied += BytesCopied; SpaceAvail -= BytesCopied; FCB->Send.BytesUsed += BytesCopied; } Irp->IoStatus.Information = TotalBytesCopied; if( TotalBytesCopied == 0 ) { AFD_DbgPrint(MID_TRACE,("Empty send\n")); UnlockBuffers( SendReq->BufferArray, SendReq->BufferCount, FALSE ); return UnlockAndMaybeComplete ( FCB, STATUS_SUCCESS, Irp, TotalBytesCopied ); } if (SpaceAvail) { FCB->PollState |= AFD_EVENT_SEND; FCB->PollStatus[FD_WRITE_BIT] = STATUS_SUCCESS; PollReeval( FCB->DeviceExt, FCB->FileObject ); } else { FCB->PollState &= ~AFD_EVENT_SEND; } /* We use the IRP tail for some temporary storage here */ Irp->Tail.Overlay.DriverContext[3] = (PVOID)Irp->IoStatus.Information; Status = QueueUserModeIrp(FCB, Irp, FUNCTION_SEND); if (Status == STATUS_PENDING && !FCB->SendIrp.InFlightRequest) { TdiSend(&FCB->SendIrp.InFlightRequest, FCB->Connection.Object, 0, FCB->Send.Window, FCB->Send.BytesUsed, SendComplete, FCB); } SocketStateUnlock(FCB); return STATUS_PENDING; }
static NTSTATUS NTAPI SendComplete ( PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context ) { NTSTATUS Status = Irp->IoStatus.Status; PAFD_FCB FCB = (PAFD_FCB)Context; PLIST_ENTRY NextIrpEntry; PIRP NextIrp = NULL; PIO_STACK_LOCATION NextIrpSp; PAFD_SEND_INFO SendReq = NULL; PAFD_MAPBUF Map; UINT TotalBytesCopied = 0, TotalBytesProcessed = 0, SpaceAvail, i; UINT SendLength, BytesCopied; BOOLEAN HaltSendQueue; UNREFERENCED_PARAMETER(DeviceObject); /* * The Irp parameter passed in is the IRP of the stream between AFD and * TDI driver. It's not very usefull to us. We need the IRPs of the stream * between usermode and AFD. Those are chained from * FCB->PendingIrpList[FUNCTION_SEND] and you'll see them in the code * below as "NextIrp" ('cause they are the next usermode IRP to be * processed). */ AFD_DbgPrint(MID_TRACE,("Called, status %x, %u bytes used\n", Irp->IoStatus.Status, Irp->IoStatus.Information)); if( !SocketAcquireStateLock( FCB ) ) return STATUS_FILE_CLOSED; ASSERT(FCB->SendIrp.InFlightRequest == Irp); FCB->SendIrp.InFlightRequest = NULL; /* Request is not in flight any longer */ if( FCB->State == SOCKET_STATE_CLOSED ) { /* Cleanup our IRP queue because the FCB is being destroyed */ while( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_SEND] ) ) { NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_SEND]); NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry); NextIrpSp = IoGetCurrentIrpStackLocation( NextIrp ); SendReq = GetLockedData(NextIrp, NextIrpSp); NextIrp->IoStatus.Status = STATUS_FILE_CLOSED; NextIrp->IoStatus.Information = 0; UnlockBuffers(SendReq->BufferArray, SendReq->BufferCount, FALSE); if( NextIrp->MdlAddress ) UnlockRequest( NextIrp, IoGetCurrentIrpStackLocation( NextIrp ) ); (void)IoSetCancelRoutine(NextIrp, NULL); IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT ); } RetryDisconnectCompletion(FCB); SocketStateUnlock( FCB ); return STATUS_FILE_CLOSED; } if( !NT_SUCCESS(Status) ) { /* Complete all following send IRPs with error */ while( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_SEND] ) ) { NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_SEND]); NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry); NextIrpSp = IoGetCurrentIrpStackLocation( NextIrp ); SendReq = GetLockedData(NextIrp, NextIrpSp); UnlockBuffers( SendReq->BufferArray, SendReq->BufferCount, FALSE ); NextIrp->IoStatus.Status = Status; NextIrp->IoStatus.Information = 0; if ( NextIrp->MdlAddress ) UnlockRequest( NextIrp, IoGetCurrentIrpStackLocation( NextIrp ) ); (void)IoSetCancelRoutine(NextIrp, NULL); IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT ); } RetryDisconnectCompletion(FCB); SocketStateUnlock( FCB ); return STATUS_SUCCESS; } RtlMoveMemory( FCB->Send.Window, FCB->Send.Window + Irp->IoStatus.Information, FCB->Send.BytesUsed - Irp->IoStatus.Information ); TotalBytesProcessed = 0; SendLength = Irp->IoStatus.Information; HaltSendQueue = FALSE; while (!IsListEmpty(&FCB->PendingIrpList[FUNCTION_SEND]) && SendLength > 0) { NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_SEND]); NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry); NextIrpSp = IoGetCurrentIrpStackLocation( NextIrp ); SendReq = GetLockedData(NextIrp, NextIrpSp); Map = (PAFD_MAPBUF)(SendReq->BufferArray + SendReq->BufferCount); TotalBytesCopied = (ULONG_PTR)NextIrp->Tail.Overlay.DriverContext[3]; ASSERT(TotalBytesCopied != 0); /* If we didn't get enough, keep waiting */ if (TotalBytesCopied > SendLength) { /* Update the bytes left to copy */ TotalBytesCopied -= SendLength; NextIrp->Tail.Overlay.DriverContext[3] = (PVOID)TotalBytesCopied; /* Update the state variables */ FCB->Send.BytesUsed -= SendLength; TotalBytesProcessed += SendLength; SendLength = 0; /* Pend the IRP */ InsertHeadList(&FCB->PendingIrpList[FUNCTION_SEND], &NextIrp->Tail.Overlay.ListEntry); HaltSendQueue = TRUE; break; } ASSERT(NextIrp->IoStatus.Information != 0); NextIrp->IoStatus.Status = Irp->IoStatus.Status; FCB->Send.BytesUsed -= TotalBytesCopied; TotalBytesProcessed += TotalBytesCopied; SendLength -= TotalBytesCopied; (void)IoSetCancelRoutine(NextIrp, NULL); UnlockBuffers( SendReq->BufferArray, SendReq->BufferCount, FALSE ); if (NextIrp->MdlAddress) UnlockRequest(NextIrp, NextIrpSp); IoCompleteRequest(NextIrp, IO_NETWORK_INCREMENT); } ASSERT(SendLength == 0); if ( !HaltSendQueue && !IsListEmpty( &FCB->PendingIrpList[FUNCTION_SEND] ) ) { NextIrpEntry = FCB->PendingIrpList[FUNCTION_SEND].Flink; NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry); NextIrpSp = IoGetCurrentIrpStackLocation( NextIrp ); SendReq = GetLockedData(NextIrp, NextIrpSp); Map = (PAFD_MAPBUF)(SendReq->BufferArray + SendReq->BufferCount); AFD_DbgPrint(MID_TRACE,("SendReq @ %p\n", SendReq)); SpaceAvail = FCB->Send.Size - FCB->Send.BytesUsed; TotalBytesCopied = 0; /* Count the total transfer size */ SendLength = 0; for (i = 0; i < SendReq->BufferCount; i++) { SendLength += SendReq->BufferArray[i].len; } /* Make sure we've got the space */ if (SendLength > SpaceAvail) { /* Blocking sockets have to wait here */ if (SendLength <= FCB->Send.Size && !((SendReq->AfdFlags & AFD_IMMEDIATE) || (FCB->NonBlocking))) { FCB->PollState &= ~AFD_EVENT_SEND; NextIrp = NULL; } /* Check if we can send anything */ if (SpaceAvail == 0) { FCB->PollState &= ~AFD_EVENT_SEND; /* We should never be non-overlapped and get to this point */ ASSERT(SendReq->AfdFlags & AFD_OVERLAPPED); NextIrp = NULL; } } if (NextIrp != NULL) { for( i = 0; i < SendReq->BufferCount; i++ ) { BytesCopied = MIN(SendReq->BufferArray[i].len, SpaceAvail); Map[i].BufferAddress = MmMapLockedPages( Map[i].Mdl, KernelMode ); RtlCopyMemory( FCB->Send.Window + FCB->Send.BytesUsed, Map[i].BufferAddress, BytesCopied ); MmUnmapLockedPages( Map[i].BufferAddress, Map[i].Mdl ); TotalBytesCopied += BytesCopied; SpaceAvail -= BytesCopied; FCB->Send.BytesUsed += BytesCopied; } NextIrp->IoStatus.Information = TotalBytesCopied; NextIrp->Tail.Overlay.DriverContext[3] = (PVOID)NextIrp->IoStatus.Information; } } if (FCB->Send.Size - FCB->Send.BytesUsed != 0 && !FCB->SendClosed && IsListEmpty(&FCB->PendingIrpList[FUNCTION_SEND])) { FCB->PollState |= AFD_EVENT_SEND; FCB->PollStatus[FD_WRITE_BIT] = STATUS_SUCCESS; PollReeval( FCB->DeviceExt, FCB->FileObject ); } else { FCB->PollState &= ~AFD_EVENT_SEND; } /* Some data is still waiting */ if( FCB->Send.BytesUsed ) { Status = TdiSend( &FCB->SendIrp.InFlightRequest, FCB->Connection.Object, 0, FCB->Send.Window, FCB->Send.BytesUsed, SendComplete, FCB ); } else { /* Nothing is waiting so try to complete a pending disconnect */ RetryDisconnectCompletion(FCB); } SocketStateUnlock( FCB ); return STATUS_SUCCESS; }
NTSTATUS NTAPI AfdConnectedSocketWriteData(PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp, BOOLEAN Short) { NTSTATUS Status = STATUS_SUCCESS; PFILE_OBJECT FileObject = IrpSp->FileObject; PAFD_FCB FCB = FileObject->FsContext; PAFD_SEND_INFO SendReq; UINT TotalBytesCopied = 0, i, SpaceAvail = 0; BOOLEAN NoSpace = FALSE; AFD_DbgPrint(MID_TRACE,("Called on %x\n", FCB)); if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp ); if( FCB->Flags & AFD_ENDPOINT_CONNECTIONLESS ) { PAFD_SEND_INFO_UDP SendReq; PTDI_CONNECTION_INFORMATION TargetAddress; /* Check that the socket is bound */ if( FCB->State != SOCKET_STATE_BOUND || !FCB->RemoteAddress ) { AFD_DbgPrint(MIN_TRACE,("Invalid parameter\n")); return UnlockAndMaybeComplete( FCB, STATUS_INVALID_PARAMETER, Irp, 0 ); } if( !(SendReq = LockRequest( Irp, IrpSp )) ) return UnlockAndMaybeComplete( FCB, STATUS_NO_MEMORY, Irp, 0 ); /* Must lock buffers before handing off user data */ SendReq->BufferArray = LockBuffers( SendReq->BufferArray, SendReq->BufferCount, NULL, NULL, FALSE, FALSE ); if( !SendReq->BufferArray ) { return UnlockAndMaybeComplete( FCB, STATUS_ACCESS_VIOLATION, Irp, 0 ); } Status = TdiBuildConnectionInfo( &TargetAddress, FCB->RemoteAddress ); if( NT_SUCCESS(Status) ) { FCB->EventSelectDisabled &= ~AFD_EVENT_SEND; FCB->PollState &= ~AFD_EVENT_SEND; Status = QueueUserModeIrp(FCB, Irp, FUNCTION_SEND); if (Status == STATUS_PENDING) { TdiSendDatagram(&FCB->SendIrp.InFlightRequest, FCB->AddressFile.Object, SendReq->BufferArray[0].buf, SendReq->BufferArray[0].len, TargetAddress, &FCB->SendIrp.Iosb, PacketSocketSendComplete, FCB); } ExFreePool( TargetAddress ); SocketStateUnlock(FCB); return STATUS_PENDING; } else { UnlockBuffers(SendReq->BufferArray, SendReq->BufferCount, FALSE); return UnlockAndMaybeComplete( FCB, Status, Irp, 0 ); } } if (FCB->PollState & AFD_EVENT_CLOSE) { AFD_DbgPrint(MIN_TRACE,("Connection reset by remote peer\n")); /* This is an unexpected remote disconnect */ return UnlockAndMaybeComplete(FCB, FCB->PollStatus[FD_CLOSE_BIT], Irp, 0); } if (FCB->PollState & AFD_EVENT_ABORT) { AFD_DbgPrint(MIN_TRACE,("Connection aborted\n")); /* This is an abortive socket closure on our side */ return UnlockAndMaybeComplete(FCB, FCB->PollStatus[FD_CLOSE_BIT], Irp, 0); } if (FCB->SendClosed) { AFD_DbgPrint(MIN_TRACE,("No more sends\n")); /* This is a graceful send closure */ return UnlockAndMaybeComplete(FCB, STATUS_FILE_CLOSED, Irp, 0); } if( !(SendReq = LockRequest( Irp, IrpSp )) ) return UnlockAndMaybeComplete ( FCB, STATUS_NO_MEMORY, Irp, TotalBytesCopied ); SendReq->BufferArray = LockBuffers( SendReq->BufferArray, SendReq->BufferCount, NULL, NULL, FALSE, FALSE ); if( !SendReq->BufferArray ) { return UnlockAndMaybeComplete( FCB, STATUS_ACCESS_VIOLATION, Irp, 0 ); } AFD_DbgPrint(MID_TRACE,("Socket state %d\n", FCB->State)); if( FCB->State != SOCKET_STATE_CONNECTED ) { if( (SendReq->AfdFlags & AFD_IMMEDIATE) || (FCB->NonBlocking) ) { AFD_DbgPrint(MID_TRACE,("Nonblocking\n")); UnlockBuffers( SendReq->BufferArray, SendReq->BufferCount, FALSE ); return UnlockAndMaybeComplete ( FCB, STATUS_CANT_WAIT, Irp, 0 ); } else { AFD_DbgPrint(MID_TRACE,("Queuing request\n")); return LeaveIrpUntilLater( FCB, Irp, FUNCTION_SEND ); } } AFD_DbgPrint(MID_TRACE,("FCB->Send.BytesUsed = %d\n", FCB->Send.BytesUsed)); SpaceAvail = FCB->Send.Size - FCB->Send.BytesUsed; AFD_DbgPrint(MID_TRACE,("We can accept %d bytes\n", SpaceAvail)); for( i = 0; FCB->Send.BytesUsed < FCB->Send.Size && i < SendReq->BufferCount; i++ ) { if (SpaceAvail < SendReq->BufferArray[i].len) { if (TotalBytesCopied + SendReq->BufferArray[i].len > FCB->Send.Size) { UnlockBuffers( SendReq->BufferArray, SendReq->BufferCount, FALSE ); return UnlockAndMaybeComplete(FCB, STATUS_BUFFER_OVERFLOW, Irp, 0); } SpaceAvail += TotalBytesCopied; NoSpace = TRUE; break; } AFD_DbgPrint(MID_TRACE,("Copying Buffer %d, %x:%d to %x\n", i, SendReq->BufferArray[i].buf, SendReq->BufferArray[i].len, FCB->Send.Window + FCB->Send.BytesUsed)); RtlCopyMemory( FCB->Send.Window + FCB->Send.BytesUsed, SendReq->BufferArray[i].buf, SendReq->BufferArray[i].len ); TotalBytesCopied += SendReq->BufferArray[i].len; SpaceAvail -= SendReq->BufferArray[i].len; } FCB->EventSelectDisabled &= ~AFD_EVENT_SEND; if( TotalBytesCopied == 0 ) { AFD_DbgPrint(MID_TRACE,("Empty send\n")); UnlockBuffers( SendReq->BufferArray, SendReq->BufferCount, FALSE ); return UnlockAndMaybeComplete ( FCB, STATUS_SUCCESS, Irp, TotalBytesCopied ); } if (SpaceAvail) { FCB->PollState |= AFD_EVENT_SEND; FCB->PollStatus[FD_WRITE_BIT] = STATUS_SUCCESS; PollReeval( FCB->DeviceExt, FCB->FileObject ); } else { FCB->PollState &= ~AFD_EVENT_SEND; } if (!NoSpace) { FCB->Send.BytesUsed += TotalBytesCopied; AFD_DbgPrint(MID_TRACE,("Copied %d bytes\n", TotalBytesCopied)); Status = QueueUserModeIrp(FCB, Irp, FUNCTION_SEND); if (Status == STATUS_PENDING && !FCB->SendIrp.InFlightRequest) { TdiSend(&FCB->SendIrp.InFlightRequest, FCB->Connection.Object, 0, FCB->Send.Window, FCB->Send.BytesUsed, &FCB->SendIrp.Iosb, SendComplete, FCB); } SocketStateUnlock(FCB); return STATUS_PENDING; } else { FCB->PollState &= ~AFD_EVENT_SEND; if( (SendReq->AfdFlags & AFD_IMMEDIATE) || (FCB->NonBlocking) ) { AFD_DbgPrint(MID_TRACE,("Nonblocking\n")); UnlockBuffers( SendReq->BufferArray, SendReq->BufferCount, FALSE ); return UnlockAndMaybeComplete ( FCB, STATUS_CANT_WAIT, Irp, 0 ); } else { AFD_DbgPrint(MID_TRACE,("Queuing request\n")); return LeaveIrpUntilLater( FCB, Irp, FUNCTION_SEND ); } } }
static NTSTATUS NTAPI SendComplete ( PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context ) { NTSTATUS Status = Irp->IoStatus.Status; PAFD_FCB FCB = (PAFD_FCB)Context; PLIST_ENTRY NextIrpEntry; PIRP NextIrp = NULL; PIO_STACK_LOCATION NextIrpSp; PAFD_SEND_INFO SendReq = NULL; PAFD_MAPBUF Map; UINT TotalBytesCopied = 0, TotalBytesProcessed = 0, SpaceAvail, i; /* * The Irp parameter passed in is the IRP of the stream between AFD and * TDI driver. It's not very usefull to us. We need the IRPs of the stream * between usermode and AFD. Those are chained from * FCB->PendingIrpList[FUNCTION_SEND] and you'll see them in the code * below as "NextIrp" ('cause they are the next usermode IRP to be * processed). */ AFD_DbgPrint(MID_TRACE,("Called, status %x, %d bytes used\n", Irp->IoStatus.Status, Irp->IoStatus.Information)); if( !SocketAcquireStateLock( FCB ) ) return STATUS_FILE_CLOSED; ASSERT(FCB->SendIrp.InFlightRequest == Irp); FCB->SendIrp.InFlightRequest = NULL; /* Request is not in flight any longer */ if( FCB->State == SOCKET_STATE_CLOSED ) { /* Cleanup our IRP queue because the FCB is being destroyed */ while( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_SEND] ) ) { NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_SEND]); NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry); NextIrpSp = IoGetCurrentIrpStackLocation( NextIrp ); SendReq = GetLockedData(NextIrp, NextIrpSp); NextIrp->IoStatus.Status = STATUS_FILE_CLOSED; NextIrp->IoStatus.Information = 0; UnlockBuffers(SendReq->BufferArray, SendReq->BufferCount, FALSE); if( NextIrp->MdlAddress ) UnlockRequest( NextIrp, IoGetCurrentIrpStackLocation( NextIrp ) ); (void)IoSetCancelRoutine(NextIrp, NULL); IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT ); } RetryDisconnectCompletion(FCB); SocketStateUnlock( FCB ); return STATUS_FILE_CLOSED; } if( !NT_SUCCESS(Status) ) { /* Complete all following send IRPs with error */ while( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_SEND] ) ) { NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_SEND]); NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry); NextIrpSp = IoGetCurrentIrpStackLocation( NextIrp ); SendReq = GetLockedData(NextIrp, NextIrpSp); UnlockBuffers( SendReq->BufferArray, SendReq->BufferCount, FALSE ); NextIrp->IoStatus.Status = Status; NextIrp->IoStatus.Information = 0; if ( NextIrp->MdlAddress ) UnlockRequest( NextIrp, IoGetCurrentIrpStackLocation( NextIrp ) ); (void)IoSetCancelRoutine(NextIrp, NULL); IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT ); } RetryDisconnectCompletion(FCB); SocketStateUnlock( FCB ); return STATUS_SUCCESS; } RtlMoveMemory( FCB->Send.Window, FCB->Send.Window + FCB->Send.BytesUsed, FCB->Send.BytesUsed - Irp->IoStatus.Information ); TotalBytesProcessed = 0; while (!IsListEmpty(&FCB->PendingIrpList[FUNCTION_SEND]) && TotalBytesProcessed != Irp->IoStatus.Information) { NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_SEND]); NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry); NextIrpSp = IoGetCurrentIrpStackLocation( NextIrp ); SendReq = GetLockedData(NextIrp, NextIrpSp); Map = (PAFD_MAPBUF)(SendReq->BufferArray + SendReq->BufferCount); TotalBytesCopied = 0; for( i = 0; i < SendReq->BufferCount; i++ ) TotalBytesCopied += SendReq->BufferArray[i].len; NextIrp->IoStatus.Status = Irp->IoStatus.Status; NextIrp->IoStatus.Information = TotalBytesCopied; TotalBytesProcessed += TotalBytesCopied; (void)IoSetCancelRoutine(NextIrp, NULL); UnlockBuffers( SendReq->BufferArray, SendReq->BufferCount, FALSE ); if (NextIrp->MdlAddress) UnlockRequest(NextIrp, NextIrpSp); IoCompleteRequest(NextIrp, IO_NETWORK_INCREMENT); } ASSERT(TotalBytesProcessed == Irp->IoStatus.Information); FCB->Send.BytesUsed -= TotalBytesProcessed; while( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_SEND] ) ) { NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_SEND]); NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry); NextIrpSp = IoGetCurrentIrpStackLocation( NextIrp ); SendReq = GetLockedData(NextIrp, NextIrpSp); Map = (PAFD_MAPBUF)(SendReq->BufferArray + SendReq->BufferCount); AFD_DbgPrint(MID_TRACE,("SendReq @ %x\n", SendReq)); SpaceAvail = FCB->Send.Size - FCB->Send.BytesUsed; TotalBytesCopied = 0; for( i = 0; i < SendReq->BufferCount; i++ ) { if (SpaceAvail < SendReq->BufferArray[i].len) { InsertHeadList(&FCB->PendingIrpList[FUNCTION_SEND], &NextIrp->Tail.Overlay.ListEntry); NextIrp = NULL; break; } Map[i].BufferAddress = MmMapLockedPages( Map[i].Mdl, KernelMode ); RtlCopyMemory( FCB->Send.Window + FCB->Send.BytesUsed, Map[i].BufferAddress, SendReq->BufferArray[i].len ); MmUnmapLockedPages( Map[i].BufferAddress, Map[i].Mdl ); TotalBytesCopied += SendReq->BufferArray[i].len; SpaceAvail -= SendReq->BufferArray[i].len; } if (NextIrp != NULL) { FCB->Send.BytesUsed += TotalBytesCopied; } else break; } if (FCB->Send.Size - FCB->Send.BytesUsed != 0 && !FCB->SendClosed) { FCB->PollState |= AFD_EVENT_SEND; FCB->PollStatus[FD_WRITE_BIT] = STATUS_SUCCESS; PollReeval( FCB->DeviceExt, FCB->FileObject ); } else { FCB->PollState &= ~AFD_EVENT_SEND; } /* Some data is still waiting */ if( FCB->Send.BytesUsed ) { Status = TdiSend( &FCB->SendIrp.InFlightRequest, FCB->Connection.Object, 0, FCB->Send.Window, FCB->Send.BytesUsed, &FCB->SendIrp.Iosb, SendComplete, FCB ); } else { /* Nothing is waiting so try to complete a pending disconnect */ RetryDisconnectCompletion(FCB); } SocketStateUnlock( FCB ); return STATUS_SUCCESS; }