mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
221 lines
7.3 KiB
221 lines
7.3 KiB
/*++
|
|
|
|
Copyright (c) 1994 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
tranfile.c
|
|
|
|
Abstract:
|
|
|
|
This module contains support TransmitFile() extended
|
|
WinSock API.
|
|
|
|
Author:
|
|
|
|
David Treadwell (davidtr) 3-Aug-1994
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "winsockp.h"
|
|
|
|
|
|
BOOL
|
|
TransmitFile (
|
|
IN SOCKET hSocket,
|
|
IN HANDLE hFile,
|
|
IN DWORD nNumberOfBytesToWrite,
|
|
IN DWORD nNumberOfBytesPerSend,
|
|
IN LPOVERLAPPED lpOverlapped,
|
|
IN LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers,
|
|
IN DWORD dwFlags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Transmits file data over a connected socket handle by interfacing
|
|
with the cache manager to retrieve the file data. Use this routine
|
|
when high performance file data transfer over sockets is required.
|
|
|
|
Arguments:
|
|
|
|
hSocket - a connected socket handle. The socket may be a datagram
|
|
socket or a virtual circuit socket.
|
|
|
|
hFile - an open file handle. Since the file data is read
|
|
sequentially, it is recommended that the handle be opened with
|
|
FILE_FLAG_SEQUENTIAL_SCAN to improve caching performance.
|
|
|
|
nNumberOfBytesToWrite - the count of bytes to send from the file.
|
|
This request will not complete until the entire requested amount
|
|
has been sent, or until an error is encountered. If this
|
|
parameter is equal to zero, then the entire file is transmited.
|
|
|
|
nNumberOfBytesPerSend - informs the sockets layer of the size to use
|
|
for each send it performs. The value 0 indicates that an
|
|
intelligent default should be used. This is mainly useful for
|
|
datagram or message protocols that have limitations of the size
|
|
of individual send requests.
|
|
|
|
lpOverlapped - specify this parameter when the socket handle is
|
|
opened as overlapped to achieve overlapped I/O. Note that by
|
|
default sockets are opened as overlapped.
|
|
|
|
Also use this parameter to specify an offset within the file at
|
|
which to start the file data transfer. The file pointer is
|
|
ignored by this API, so if lpOverlapped is NULL the transmission
|
|
always starts at offset 0 in the file.
|
|
|
|
When lpOverlapped is non-NULL, TransmitFile() may return
|
|
ERROR_IO_PENDING to allow the calling function to continue
|
|
processing while the operation completes. The event (or hSocket
|
|
if hEvent is NULL) will be set to the signalled state upon
|
|
completion of the request.
|
|
|
|
lpTransmitBuffers - an optional pointer to a TRANSMIT_FILE_BUFFERS
|
|
structure which contains pointers to data to send before the
|
|
file (the head buffer) and after the file (the tail buffer). If
|
|
only the file is to be sent, this parameter may be specified as
|
|
NULL.
|
|
|
|
dwFlags - any combination of the following:
|
|
|
|
TF_DISCONNECT - start a transport-level disconnect after all the
|
|
file data has been queued to the transport.
|
|
|
|
TF_REUSE_SOCKET - prepare the socket handle to be reused. When
|
|
the TransmitFile request completes, the socket handle may be
|
|
passed to the SuperAccept API. Only valid if TF_DISCONNECT
|
|
is also specified.
|
|
|
|
TF_WRITE_BEHIND - complete the TransmitFile request immediately,
|
|
without pending. If this flag is specified and TransmitFile
|
|
succeeds, then the data has been accepted by the system but not
|
|
necessarily acknowledged by the remote end. Do not use this
|
|
setting with the other two settings.
|
|
|
|
Return Value:
|
|
|
|
TRUE - The operation was successul.
|
|
|
|
FALSE - The operation failed. Extended error status is available
|
|
using GetLastError().
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
AFD_TRANSMIT_FILE_INFO transmitInfo;
|
|
NTSTATUS status;
|
|
IO_STATUS_BLOCK ioStatusBlock;
|
|
|
|
//
|
|
// Set up general imformation about the request.
|
|
//
|
|
|
|
transmitInfo.WriteLength.QuadPart = nNumberOfBytesToWrite;
|
|
transmitInfo.SendPacketLength = nNumberOfBytesPerSend;
|
|
transmitInfo.FileHandle = hFile;
|
|
transmitInfo.Flags = dwFlags;
|
|
|
|
if ( ARGUMENT_PRESENT( lpTransmitBuffers ) ) {
|
|
transmitInfo.Head = lpTransmitBuffers->Head;
|
|
transmitInfo.HeadLength = lpTransmitBuffers->HeadLength;
|
|
transmitInfo.Tail = lpTransmitBuffers->Tail;
|
|
transmitInfo.TailLength = lpTransmitBuffers->TailLength;
|
|
} else {
|
|
transmitInfo.Head = NULL;
|
|
transmitInfo.HeadLength = 0;
|
|
transmitInfo.Tail = NULL;
|
|
transmitInfo.TailLength = 0;
|
|
}
|
|
|
|
//
|
|
// Handle the request differently based on whether an lpOverlapped
|
|
// structure was specified. If it was specified, then the socket
|
|
// handle must have been opened for asynchronous access.
|
|
//
|
|
|
|
if ( ARGUMENT_PRESENT( lpOverlapped ) ) {
|
|
|
|
lpOverlapped->Internal = (DWORD)STATUS_PENDING;
|
|
|
|
transmitInfo.Offset.LowPart = lpOverlapped->Offset;
|
|
transmitInfo.Offset.HighPart = lpOverlapped->OffsetHigh;
|
|
|
|
//
|
|
// Call AFD to transmit the file. Note that we pass a smaller
|
|
// input buffer than the full structure in order to save the
|
|
// input buffer copy in the I/O system. Also note that we do
|
|
// pass an output buffer: this ensures that the I/O system
|
|
// allocates a large enough system buffer for AFD to use as a
|
|
// scratch buffer.
|
|
//
|
|
|
|
status = NtDeviceIoControlFile(
|
|
(HANDLE)hSocket,
|
|
lpOverlapped->hEvent,
|
|
NULL,
|
|
(DWORD)lpOverlapped->hEvent & 1 ? NULL : lpOverlapped,
|
|
(PIO_STATUS_BLOCK)(&lpOverlapped->Internal),
|
|
IOCTL_AFD_TRANSMIT_FILE,
|
|
&transmitInfo,
|
|
sizeof(transmitInfo),
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
if ( NT_SUCCESS(status) && status != STATUS_PENDING) {
|
|
return TRUE;
|
|
} else {
|
|
SetLastError( SockNtStatusToSocketError(status) );
|
|
return FALSE;
|
|
}
|
|
|
|
} else {
|
|
|
|
transmitInfo.Offset.LowPart = 0;
|
|
transmitInfo.Offset.HighPart = 0;
|
|
|
|
//
|
|
// Call AFD to transmit the file. Note that we pass a smaller
|
|
// input buffer than the full structure in order to save the
|
|
// input buffer copy in the I/O system. Also note that we do
|
|
// pass an output buffer: this ensures that the I/O system
|
|
// allocates a large enough system buffer for AFD to use as a
|
|
// scratch buffer.
|
|
//
|
|
|
|
status = NtDeviceIoControlFile(
|
|
(HANDLE)hSocket,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&ioStatusBlock,
|
|
IOCTL_AFD_TRANSMIT_FILE,
|
|
&transmitInfo,
|
|
sizeof(transmitInfo),
|
|
NULL,
|
|
0
|
|
);
|
|
if ( status == STATUS_PENDING) {
|
|
// Operation must complete before return & IoStatusBlock destroyed
|
|
status = NtWaitForSingleObject( (HANDLE)hSocket, FALSE, NULL );
|
|
if ( NT_SUCCESS(status)) {
|
|
status = ioStatusBlock.Status;
|
|
}
|
|
}
|
|
|
|
if ( NT_SUCCESS(status) ) {
|
|
return TRUE;
|
|
} else {
|
|
SetLastError( SockNtStatusToSocketError(status) );
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
} // TransmitFile
|