439 lines
10 KiB
C++
439 lines
10 KiB
C++
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1996 Microsoft Corporation
|
|||
|
|
|||
|
Module Name :
|
|||
|
|
|||
|
atqxmit.cxx
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
Contains internal support routines for transmit file
|
|||
|
|
|||
|
Author:
|
|||
|
Johnson Apacible (johnsona) 26-Mar-1996
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "isatq.hxx"
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Size of buffers for fake xmits
|
|||
|
//
|
|||
|
|
|||
|
DWORD g_cbXmitBufferSize = ATQ_REG_DEF_NONTF_BUFFER_SIZE;
|
|||
|
|
|||
|
VOID
|
|||
|
I_CleanupFakeTransmitFile(
|
|||
|
IN PATQ_CONT pContext
|
|||
|
)
|
|||
|
{
|
|||
|
//
|
|||
|
// Put the old completion routine back and free allocated buffers
|
|||
|
//
|
|||
|
|
|||
|
pContext->pfnCompletion = pContext->arInfo.uop.opFakeXmit.pfnCompletion;
|
|||
|
pContext->ClientContext = pContext->arInfo.uop.opFakeXmit.ClientContext;
|
|||
|
if ( pContext->arInfo.uop.opFakeXmit.pBuffer != NULL ) {
|
|||
|
LocalFree(pContext->arInfo.uop.opFakeXmit.pBuffer);
|
|||
|
pContext->arInfo.uop.opFakeXmit.pBuffer = NULL;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Clean up the event
|
|||
|
//
|
|||
|
|
|||
|
if ( pContext->arInfo.uop.opFakeXmit.hOvEvent != NULL ) {
|
|||
|
CloseHandle( pContext->arInfo.uop.opFakeXmit.hOvEvent );
|
|||
|
pContext->arInfo.uop.opFakeXmit.hOvEvent = NULL;
|
|||
|
}
|
|||
|
return;
|
|||
|
|
|||
|
} // I_CleanupFakeTransmitFile
|
|||
|
|
|||
|
VOID
|
|||
|
I_FakeTransmitFileCompletion(
|
|||
|
IN PVOID ClientContext,
|
|||
|
IN DWORD BytesWritten,
|
|||
|
IN DWORD CompletionStatus,
|
|||
|
IN OVERLAPPED * lpo
|
|||
|
)
|
|||
|
{
|
|||
|
PATQ_CONT pContext;
|
|||
|
DWORD nWrite = 0;
|
|||
|
DWORD nRead;
|
|||
|
PCHAR buffer;
|
|||
|
INT err;
|
|||
|
PVOID tail;
|
|||
|
OVERLAPPED ov;
|
|||
|
OVERLAPPED *pov = &ov;
|
|||
|
|
|||
|
pContext = (PATQ_CONT)ClientContext;
|
|||
|
pContext->arInfo.uop.opFakeXmit.BytesWritten += BytesWritten;
|
|||
|
|
|||
|
if ( CompletionStatus != NO_ERROR ) {
|
|||
|
|
|||
|
//
|
|||
|
// An error occured, call the completion routine
|
|||
|
//
|
|||
|
|
|||
|
goto call_completion;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// We already have a buffer of size g_cbXmitBufferSize
|
|||
|
//
|
|||
|
|
|||
|
nRead = pContext->arInfo.uop.opFakeXmit.BytesLeft;
|
|||
|
buffer = pContext->arInfo.uop.opFakeXmit.pBuffer;
|
|||
|
ATQ_ASSERT(buffer != NULL);
|
|||
|
|
|||
|
if ( nRead > 0 ) {
|
|||
|
|
|||
|
//
|
|||
|
// Do the read at the specified offset
|
|||
|
//
|
|||
|
|
|||
|
pov->OffsetHigh = 0;
|
|||
|
pov->Offset = pContext->arInfo.uop.opFakeXmit.FileOffset;
|
|||
|
pov->hEvent = pContext->arInfo.uop.opFakeXmit.hOvEvent;
|
|||
|
ATQ_ASSERT(pov->hEvent != NULL);
|
|||
|
ResetEvent(pov->hEvent);
|
|||
|
|
|||
|
if (!ReadFile(
|
|||
|
pContext->arInfo.uop.opFakeXmit.hFile,
|
|||
|
buffer,
|
|||
|
g_cbXmitBufferSize,
|
|||
|
&nRead,
|
|||
|
pov
|
|||
|
) ) {
|
|||
|
|
|||
|
err = GetLastError();
|
|||
|
if ( (err != ERROR_IO_PENDING) ||
|
|||
|
!GetOverlappedResult(
|
|||
|
pContext->arInfo.uop.opFakeXmit.hFile,
|
|||
|
pov,
|
|||
|
&nRead,
|
|||
|
TRUE )) {
|
|||
|
|
|||
|
CompletionStatus = GetLastError();
|
|||
|
ATQ_PRINTF(( DBG_CONTEXT,"ReadFile error %d\n",CompletionStatus));
|
|||
|
goto call_completion;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// if nRead is zero, we reached the EOF.
|
|||
|
//
|
|||
|
|
|||
|
if ( nRead > 0 ) {
|
|||
|
|
|||
|
//
|
|||
|
// Update for next read
|
|||
|
//
|
|||
|
|
|||
|
pContext->arInfo.uop.opFakeXmit.BytesLeft -= nRead;
|
|||
|
pContext->arInfo.uop.opFakeXmit.FileOffset += nRead;
|
|||
|
|
|||
|
//
|
|||
|
// Do the write
|
|||
|
//
|
|||
|
|
|||
|
I_SetNextTimeout(pContext);
|
|||
|
pContext->BytesSent = nRead;
|
|||
|
|
|||
|
//
|
|||
|
// Write to the socket
|
|||
|
//
|
|||
|
|
|||
|
if ( !WriteFile(
|
|||
|
pContext->hAsyncIO,
|
|||
|
buffer,
|
|||
|
nRead,
|
|||
|
&nWrite,
|
|||
|
&pContext->Overlapped
|
|||
|
) &&
|
|||
|
(GetLastError() != ERROR_IO_PENDING) ) {
|
|||
|
|
|||
|
CompletionStatus = GetLastError();
|
|||
|
ATQ_PRINTF(( DBG_CONTEXT,
|
|||
|
"WriteFile error %d\n",CompletionStatus));
|
|||
|
goto call_completion;
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Time for the tail. If one exist, send it synchronously and then
|
|||
|
// call the completion routine
|
|||
|
//
|
|||
|
|
|||
|
tail = pContext->arInfo.uop.opFakeXmit.Tail;
|
|||
|
if ( tail != NULL ) {
|
|||
|
|
|||
|
DWORD tailLength = pContext->arInfo.uop.opFakeXmit.TailLength;
|
|||
|
|
|||
|
ATQ_ASSERT(tailLength > 0);
|
|||
|
|
|||
|
//
|
|||
|
// Send it synchronously
|
|||
|
//
|
|||
|
|
|||
|
err = send(
|
|||
|
HANDLE_TO_SOCKET(pContext->hAsyncIO),
|
|||
|
(PCHAR)tail,
|
|||
|
tailLength,
|
|||
|
0
|
|||
|
);
|
|||
|
|
|||
|
if ( err == SOCKET_ERROR ) {
|
|||
|
CompletionStatus = GetLastError();
|
|||
|
} else {
|
|||
|
pContext->arInfo.uop.opFakeXmit.BytesWritten += err;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
call_completion:
|
|||
|
|
|||
|
//
|
|||
|
// cleanup and call real completion routine
|
|||
|
//
|
|||
|
|
|||
|
I_CleanupFakeTransmitFile( pContext );
|
|||
|
if ( pContext->pfnCompletion != NULL ) {
|
|||
|
|
|||
|
pContext->pfnCompletion(
|
|||
|
pContext->ClientContext,
|
|||
|
pContext->arInfo.uop.opFakeXmit.BytesWritten,
|
|||
|
CompletionStatus,
|
|||
|
lpo
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
} // I_FakeTransmitFileCompletion
|
|||
|
|
|||
|
BOOL
|
|||
|
I_DoFakeTransmitFile(
|
|||
|
IN PATQ_CONT pContext,
|
|||
|
IN HANDLE hFile,
|
|||
|
IN DWORD dwBytesInFile,
|
|||
|
IN LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Posts a completion status on the completion port queue
|
|||
|
|
|||
|
An IO pending error code is treated as a success error code
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
patqContext - pointer to ATQ context
|
|||
|
hFile - Handle to the file to be read.
|
|||
|
dwBytesInFile - Number of bytes to read in the file
|
|||
|
lpTransmitBuffers - the transmitfile structure
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if successful, FALSE on error (call GetLastError)
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
PCHAR buffer = NULL;
|
|||
|
DWORD nWrite;
|
|||
|
DWORD nRead = 0;
|
|||
|
OVERLAPPED ov;
|
|||
|
INT err;
|
|||
|
DWORD cBuffer = 0;
|
|||
|
OVERLAPPED *pov = &ov;
|
|||
|
HANDLE hOvEvent = NULL;
|
|||
|
|
|||
|
INC_ATQ_COUNTER( g_cTotalAllowedRequests);
|
|||
|
|
|||
|
//
|
|||
|
// See if we need to send a header
|
|||
|
//
|
|||
|
|
|||
|
pContext->arInfo.uop.opFakeXmit.BytesWritten = 0;
|
|||
|
if ( lpTransmitBuffers != NULL ) {
|
|||
|
|
|||
|
//
|
|||
|
// Store the tail
|
|||
|
//
|
|||
|
|
|||
|
pContext->arInfo.uop.opFakeXmit.Tail = lpTransmitBuffers->Tail;
|
|||
|
pContext->arInfo.uop.opFakeXmit.TailLength = lpTransmitBuffers->TailLength;
|
|||
|
|
|||
|
if (lpTransmitBuffers->HeadLength > 0) {
|
|||
|
ATQ_ASSERT(lpTransmitBuffers->Head != NULL);
|
|||
|
|
|||
|
//
|
|||
|
// Send it synchronously
|
|||
|
//
|
|||
|
|
|||
|
err = send(
|
|||
|
HANDLE_TO_SOCKET(pContext->hAsyncIO),
|
|||
|
(PCHAR)lpTransmitBuffers->Head,
|
|||
|
lpTransmitBuffers->HeadLength,
|
|||
|
0
|
|||
|
);
|
|||
|
|
|||
|
if ( err == SOCKET_ERROR ) {
|
|||
|
ATQ_PRINTF(( DBG_CONTEXT, "Error %d in send.\n",err));
|
|||
|
return(FALSE);
|
|||
|
}
|
|||
|
pContext->arInfo.uop.opFakeXmit.BytesWritten += err;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check the number of bytes to send
|
|||
|
//
|
|||
|
|
|||
|
if ( dwBytesInFile == 0 ) {
|
|||
|
|
|||
|
//
|
|||
|
// Send the whole file.
|
|||
|
//
|
|||
|
|
|||
|
dwBytesInFile = GetFileSize( hFile, NULL );
|
|||
|
ATQ_ASSERT(dwBytesInFile >= pContext->Overlapped.Offset);
|
|||
|
dwBytesInFile -= pContext->Overlapped.Offset;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Allocate the io buffer
|
|||
|
//
|
|||
|
|
|||
|
cBuffer = min( dwBytesInFile, g_cbXmitBufferSize );
|
|||
|
if ( cBuffer > 0 ) {
|
|||
|
|
|||
|
//
|
|||
|
// Read the first chunk of the body
|
|||
|
//
|
|||
|
|
|||
|
buffer = (PCHAR)LocalAlloc( 0, cBuffer );
|
|||
|
if ( buffer == NULL ) {
|
|||
|
ATQ_PRINTF(( DBG_CONTEXT,
|
|||
|
"Cannot allocate %d bytes for xmitfile\n",cBuffer));
|
|||
|
return(FALSE);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Do the read at the specified offset
|
|||
|
//
|
|||
|
|
|||
|
hOvEvent = pov->hEvent = IIS_CREATE_EVENT(
|
|||
|
"OVERLAPPED::hEvent",
|
|||
|
pov,
|
|||
|
TRUE,
|
|||
|
FALSE
|
|||
|
);
|
|||
|
|
|||
|
if ( hOvEvent == NULL ) {
|
|||
|
ATQ_PRINTF(( DBG_CONTEXT,
|
|||
|
"Create event failed with %d\n",GetLastError()));
|
|||
|
LocalFree( buffer );
|
|||
|
return(FALSE);
|
|||
|
}
|
|||
|
|
|||
|
pov->OffsetHigh = 0;
|
|||
|
pov->Offset = pContext->Overlapped.Offset;
|
|||
|
|
|||
|
if (!ReadFile(
|
|||
|
hFile,
|
|||
|
buffer,
|
|||
|
cBuffer,
|
|||
|
&nRead,
|
|||
|
pov
|
|||
|
) ) {
|
|||
|
|
|||
|
err = GetLastError();
|
|||
|
if ( (err != ERROR_IO_PENDING) ||
|
|||
|
!GetOverlappedResult( hFile, pov, &nRead, TRUE )) {
|
|||
|
|
|||
|
err = GetLastError();
|
|||
|
CloseHandle( hOvEvent );
|
|||
|
LocalFree( buffer );
|
|||
|
SetLastError(err);
|
|||
|
ATQ_PRINTF(( DBG_CONTEXT,
|
|||
|
"Error %d in readfile\n",err));
|
|||
|
return(FALSE);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// are we done reading the body?
|
|||
|
//
|
|||
|
|
|||
|
if ( nRead < g_cbXmitBufferSize ) {
|
|||
|
|
|||
|
//
|
|||
|
// Done.
|
|||
|
//
|
|||
|
|
|||
|
pContext->arInfo.uop.opFakeXmit.BytesLeft = 0;
|
|||
|
} else {
|
|||
|
|
|||
|
pContext->arInfo.uop.opFakeXmit.BytesLeft = dwBytesInFile - nRead;
|
|||
|
pContext->arInfo.uop.opFakeXmit.FileOffset =
|
|||
|
pContext->Overlapped.Offset + nRead;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// store data for restarting the operation.
|
|||
|
//
|
|||
|
|
|||
|
pContext->arInfo.uop.opFakeXmit.pBuffer = buffer;
|
|||
|
pContext->arInfo.uop.opFakeXmit.hOvEvent = hOvEvent;
|
|||
|
pContext->arInfo.uop.opFakeXmit.hFile = hFile;
|
|||
|
|
|||
|
//
|
|||
|
// replace the completion function with our own
|
|||
|
//
|
|||
|
|
|||
|
pContext->arInfo.uop.opFakeXmit.pfnCompletion = pContext->pfnCompletion;
|
|||
|
pContext->arInfo.uop.opFakeXmit.ClientContext = pContext->ClientContext;
|
|||
|
pContext->pfnCompletion = I_FakeTransmitFileCompletion;
|
|||
|
pContext->ClientContext = pContext;
|
|||
|
|
|||
|
//
|
|||
|
// Set the timeout
|
|||
|
//
|
|||
|
|
|||
|
I_SetNextTimeout(pContext);
|
|||
|
pContext->BytesSent = nRead;
|
|||
|
|
|||
|
//
|
|||
|
// Write to the socket
|
|||
|
//
|
|||
|
|
|||
|
if ( !WriteFile(
|
|||
|
pContext->hAsyncIO,
|
|||
|
buffer,
|
|||
|
nRead,
|
|||
|
&nWrite,
|
|||
|
&pContext->Overlapped
|
|||
|
) &&
|
|||
|
(GetLastError() != ERROR_IO_PENDING)) {
|
|||
|
|
|||
|
err = GetLastError();
|
|||
|
I_CleanupFakeTransmitFile( pContext );
|
|||
|
SetLastError(err);
|
|||
|
return(FALSE);
|
|||
|
}
|
|||
|
|
|||
|
SetLastError(NO_ERROR);
|
|||
|
return(TRUE);
|
|||
|
|
|||
|
} // I_DoFakeTransmitFile
|
|||
|
|