/*++ 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