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.
482 lines
10 KiB
482 lines
10 KiB
/*++
|
|
|
|
Copyright (c) 1994 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ftrans.c
|
|
|
|
Abstract:
|
|
|
|
This module demonstrates a simple file transfer using ISAPI application
|
|
using the Async TransmitFile support with callback.
|
|
|
|
Author:
|
|
|
|
Murali R. Krishnan ( MuraliK ) 26-Apr-1996
|
|
|
|
Revision History:
|
|
--*/
|
|
|
|
#include <windows.h>
|
|
#include <httpext.h>
|
|
|
|
# include <openf.h>
|
|
|
|
/************************************************************
|
|
* Global Data
|
|
************************************************************/
|
|
|
|
LIST_ENTRY g_lWorkItems;
|
|
CRITICAL_SECTION g_csWorkItems;
|
|
|
|
# define USE_WORK_QUEUE (0)
|
|
|
|
|
|
DWORD
|
|
SendHeaderToClient( IN EXTENSION_CONTROL_BLOCK * pecb, IN LPCSTR pszErrorMsg);
|
|
|
|
|
|
DWORD
|
|
SendFileToClient( IN EXTENSION_CONTROL_BLOCK * pecb, IN LPCSTR pszFile);
|
|
|
|
DWORD
|
|
SendFileOver( IN EXTENSION_CONTROL_BLOCK * pecb,
|
|
IN HANDLE hFile,
|
|
IN LPCSTR pszFile);
|
|
|
|
|
|
|
|
|
|
/************************************************************
|
|
* Functions
|
|
************************************************************/
|
|
|
|
|
|
BOOL WINAPI
|
|
DllLibMain(
|
|
IN HINSTANCE hinstDll,
|
|
IN DWORD fdwReason,
|
|
IN LPVOID lpvContext OPTIONAL)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function DllLibMain() is the main initialization function for
|
|
this DLL. It initializes local variables and prepares it to be invoked
|
|
subsequently.
|
|
|
|
Arguments:
|
|
|
|
hinstDll Instance Handle of the DLL
|
|
fdwReason Reason why NT called this DLL
|
|
lpvReserved Reserved parameter for future use.
|
|
|
|
Return Value:
|
|
|
|
Returns TRUE is successful; otherwise FALSE is returned.
|
|
|
|
--*/
|
|
{
|
|
BOOL fReturn = TRUE;
|
|
|
|
switch (fdwReason ) {
|
|
|
|
case DLL_PROCESS_ATTACH:
|
|
{
|
|
OutputDebugString( " Initializing the global data\n");
|
|
|
|
//
|
|
// Initialize various data and modules.
|
|
//
|
|
InitializeCriticalSection(&g_csWorkItems);
|
|
InitializeListHead( &g_lWorkItems);
|
|
InitFileHandleCache();
|
|
|
|
break;
|
|
} /* case DLL_PROCESS_ATTACH */
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
{
|
|
|
|
//
|
|
// Only cleanup when we are called because of a FreeLibrary().
|
|
// i.e., when lpvContext == NULL
|
|
// If we are called because of a process termination,
|
|
// dont free anything. System will free resources and memory for us.
|
|
//
|
|
|
|
CleanupFileHandleCache();
|
|
if ( lpvContext != NULL) {
|
|
|
|
DeleteCriticalSection(&g_csWorkItems);
|
|
}
|
|
|
|
break;
|
|
} /* case DLL_PROCESS_DETACH */
|
|
|
|
default:
|
|
break;
|
|
} /* switch */
|
|
|
|
return ( fReturn);
|
|
} /* DllLibMain() */
|
|
|
|
|
|
|
|
|
|
DWORD
|
|
HttpExtensionProc(
|
|
EXTENSION_CONTROL_BLOCK * pecb
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function performs the necessary action to send response for the
|
|
request received from the client. It picks up the name of a file from
|
|
the pecb->lpszQueryString and transmits that file to the client.
|
|
|
|
Arguments:
|
|
|
|
pecb pointer to ECB containing parameters related to the request.
|
|
|
|
Return Value:
|
|
|
|
Returns HSE_* status codes
|
|
--*/
|
|
{
|
|
char buff[2048];
|
|
DWORD hseStatus;
|
|
|
|
|
|
if ( pecb->lpszQueryString == NULL ||
|
|
*pecb->lpszQueryString == '\0'
|
|
) {
|
|
|
|
hseStatus = SendHeaderToClient( pecb, "File Not Specified");
|
|
} else {
|
|
|
|
hseStatus = SendFileToClient( pecb, pecb->lpszQueryString);
|
|
}
|
|
|
|
return ( hseStatus);
|
|
|
|
} // HttpExtensionProc()
|
|
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
GetExtensionVersion(
|
|
HSE_VERSION_INFO * pver
|
|
)
|
|
{
|
|
pver->dwExtensionVersion = MAKELONG( 1, 0 );
|
|
strcpy( pver->lpszExtensionDesc,
|
|
"File Transfer using TransmitFile" );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DWORD
|
|
SendHeaderToClient( IN EXTENSION_CONTROL_BLOCK * pecb, IN LPCSTR pszErrorMsg)
|
|
{
|
|
|
|
CHAR buff[600];
|
|
|
|
//
|
|
// Note the HTTP header block is terminated by a blank '\r\n' pair,
|
|
// followed by the document body
|
|
//
|
|
|
|
wsprintf( buff,
|
|
"Content-Type: text/html\r\n"
|
|
"\r\n"
|
|
"<head><title>Simple File Transfer</title></head>\n"
|
|
"<body><h1>%s</h1>\n"
|
|
,
|
|
pszErrorMsg );
|
|
|
|
if ( !pecb->ServerSupportFunction( pecb->ConnID,
|
|
HSE_REQ_SEND_RESPONSE_HEADER,
|
|
"200 OK",
|
|
NULL,
|
|
(LPDWORD) buff )
|
|
) {
|
|
|
|
return HSE_STATUS_ERROR;
|
|
}
|
|
|
|
return ( HSE_STATUS_SUCCESS);
|
|
} // SendHeaderToClient()
|
|
|
|
|
|
|
|
DWORD
|
|
SendFileToClient( IN EXTENSION_CONTROL_BLOCK * pecb, IN LPCSTR pszFile)
|
|
{
|
|
CHAR pchBuffer[1024];
|
|
HANDLE hFile;
|
|
DWORD hseStatus = HSE_STATUS_SUCCESS;
|
|
|
|
hFile = FcOpenFile( pszFile);
|
|
|
|
if ( hFile == INVALID_HANDLE_VALUE) {
|
|
|
|
|
|
wsprintfA( pchBuffer,
|
|
"OpenFailed: Error (%d) while opening the file %s.\n",
|
|
GetLastError(), pszFile);
|
|
|
|
hseStatus = SendHeaderToClient( pecb, pchBuffer);
|
|
|
|
} else {
|
|
|
|
#if SEPARATE_HEADERS
|
|
hseStatus = SendHeaderToClient( pecb, "File Transfer begins");
|
|
#else
|
|
hseStatus = HSE_STATUS_SUCCESS;
|
|
#endif
|
|
|
|
if ( hseStatus == HSE_STATUS_SUCCESS) {
|
|
|
|
hseStatus = SendFileOver( pecb, hFile, pszFile);
|
|
|
|
if ( hseStatus != HSE_STATUS_PENDING) {
|
|
|
|
//
|
|
// assume that the data is transmitted.
|
|
//
|
|
|
|
if ( hseStatus != HSE_STATUS_SUCCESS) {
|
|
|
|
//
|
|
// Error in transmitting the file. Send error message.
|
|
//
|
|
|
|
wsprintfA( pchBuffer,
|
|
"Send Failed: Error (%d) for file %s.\n",
|
|
GetLastError(), pszFile);
|
|
|
|
SendHeaderToClient( pecb, pchBuffer);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( hseStatus != HSE_STATUS_PENDING) {
|
|
|
|
//
|
|
// file handle is closed for all non-pending cases
|
|
// if the status is pending, file handle is cleaned up in callback
|
|
//
|
|
FcCloseFile( hFile);
|
|
}
|
|
}
|
|
|
|
return (hseStatus);
|
|
|
|
} // SendFileToClient()
|
|
|
|
|
|
|
|
|
|
# define MAX_BUFFER_SIZE (400)
|
|
|
|
typedef struct _AIO_WORK_ITEM {
|
|
|
|
LIST_ENTRY listEntry;
|
|
EXTENSION_CONTROL_BLOCK * pecb;
|
|
HSE_TF_INFO hseTf;
|
|
CHAR pchBuffer[ MAX_BUFFER_SIZE ];
|
|
|
|
} AIO_WORK_ITEM, * PAWI;
|
|
|
|
|
|
|
|
|
|
VOID
|
|
CleanupAW( IN PAWI paw, IN BOOL fDoneWithSession)
|
|
{
|
|
|
|
DWORD err = GetLastError();
|
|
|
|
if ( paw->hseTf.hFile != INVALID_HANDLE_VALUE) {
|
|
|
|
FcCloseFile( paw->hseTf.hFile);
|
|
}
|
|
|
|
if (fDoneWithSession) {
|
|
|
|
paw->pecb->ServerSupportFunction( paw->pecb->ConnID,
|
|
HSE_REQ_DONE_WITH_SESSION,
|
|
NULL, NULL, NULL);
|
|
}
|
|
SetLastError( err);
|
|
|
|
//
|
|
// Remove from work items list
|
|
//
|
|
#if USE_WORK_QUEUE
|
|
EnterCriticalSection( &g_csWorkItems);
|
|
RemoveEntryList( &paw->listEntry);
|
|
LeaveCriticalSection( &g_csWorkItems);
|
|
# endif
|
|
|
|
LocalFree( paw);
|
|
return;
|
|
|
|
} // CleanupAW()
|
|
|
|
|
|
|
|
|
|
VOID
|
|
HseIoCompletion(
|
|
IN EXTENSION_CONTROL_BLOCK * pECB,
|
|
IN PVOID pContext,
|
|
IN DWORD cbIO,
|
|
IN DWORD dwError
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the callback function for handling completions of asynchronous IO.
|
|
This function performs necessary cleanup and resubmits additional IO
|
|
(if required). In this case, this function is called at the end of a
|
|
successful TransmitFile() operation. This function primarily cleans up
|
|
the data and worker queue item and exits.
|
|
|
|
Arguments:
|
|
|
|
pecb pointer to ECB containing parameters related to the request.
|
|
pContext context information supplied with the asynchronous IO call.
|
|
cbIO count of bytes of IO in the last call.
|
|
dwError Error if any, for the last IO operation.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
--*/
|
|
{
|
|
PAWI paw = (PAWI ) pContext;
|
|
EXTENSION_CONTROL_BLOCK * pecb = paw->pecb;
|
|
DWORD hseStatus;
|
|
|
|
|
|
// assert( pecb == paw->pecb);
|
|
|
|
//
|
|
// 1. if no errors, we are done transmitting the file
|
|
// 2. cleanup and exit
|
|
//
|
|
|
|
|
|
//
|
|
// Do Cleanup
|
|
//
|
|
|
|
CleanupAW( paw, TRUE);
|
|
|
|
|
|
return;
|
|
|
|
} // HseIoCompletion()
|
|
|
|
|
|
|
|
|
|
DWORD
|
|
SendFileOver( IN EXTENSION_CONTROL_BLOCK * pecb,
|
|
IN HANDLE hFile,
|
|
IN LPCSTR pszFile)
|
|
{
|
|
|
|
PAWI paw;
|
|
DWORD hseStatus = HSE_STATUS_PENDING;
|
|
DWORD err;
|
|
|
|
paw = (PAWI ) LocalAlloc( LMEM_FIXED, sizeof(AIO_WORK_ITEM));
|
|
if ( paw == NULL) {
|
|
|
|
SetLastError( ERROR_NOT_ENOUGH_MEMORY);
|
|
return (HSE_STATUS_ERROR);
|
|
}
|
|
|
|
//
|
|
// Fill in all the data in AIO_WORK_ITEM
|
|
//
|
|
paw->pecb = pecb;
|
|
InitializeListHead( &paw->listEntry);
|
|
|
|
paw->hseTf.pfnHseIO = HseIoCompletion;
|
|
paw->hseTf.pContext = paw;
|
|
paw->hseTf.dwFlags = (HSE_IO_ASYNC | HSE_IO_DISCONNECT_AFTER_SEND);
|
|
|
|
paw->hseTf.hFile = hFile;
|
|
paw->hseTf.BytesToWrite = GetFileSize(hFile, NULL);
|
|
paw->hseTf.Offset = 0;
|
|
paw->hseTf.pTail = NULL;
|
|
paw->hseTf.TailLength = 0;
|
|
|
|
|
|
//
|
|
// Set up the header to be sentout for the file
|
|
//
|
|
|
|
#if SEPARATE_HEADERS
|
|
paw->hseTf.HeadLength = 0;
|
|
paw->hseTf.pHead = NULL;
|
|
|
|
#else
|
|
paw->hseTf.HeadLength =
|
|
wsprintfA ( paw->pchBuffer,
|
|
"HTTP/1.0 200 OK\r\n"
|
|
"Content-Type: text/html\r\n"
|
|
"\r\n"
|
|
"<head><title>Simple File Transfer (TransmitFile) "
|
|
"</title></head>\n"
|
|
"<h1>Sending File %s</h1>\n"
|
|
,
|
|
pszFile );
|
|
paw->hseTf.pHead = paw->pchBuffer;
|
|
# endif
|
|
|
|
// Add to the list
|
|
#if USE_WORK_QUEUE
|
|
EnterCriticalSection( &g_csWorkItems);
|
|
InsertTailList( &g_lWorkItems, &paw->listEntry);
|
|
LeaveCriticalSection( &g_csWorkItems);
|
|
#endif
|
|
|
|
//
|
|
// Setup the Async TransmitFile
|
|
//
|
|
|
|
if ( !pecb->ServerSupportFunction( pecb->ConnID,
|
|
HSE_REQ_TRANSMIT_FILE,
|
|
&paw->hseTf,
|
|
NULL,
|
|
NULL)
|
|
) {
|
|
|
|
//
|
|
// Do cleanup and return error
|
|
//
|
|
|
|
// File handle will be freed by the caller for errors
|
|
paw->hseTf.hFile = INVALID_HANDLE_VALUE;
|
|
|
|
CleanupAW( paw, FALSE);
|
|
hseStatus = HSE_STATUS_ERROR;
|
|
}
|
|
|
|
return (hseStatus);
|
|
|
|
} // SendFileOver()
|