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
|
||
|