/*++
Copyright (c) 1997 Microsoft Corporation
Module Name: KeepAliveP.c
Abstract:
Sample ISAPI Extension demonstrating Keep-Alive with a thread pool.
--*/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <httpext.h>
#include <stdio.h>
#include "threadpool.h"
BOOL WINAPI
DllMain(
IN HINSTANCE hinstDll,
IN DWORD fdwReason,
IN LPVOID lpvContext
)
/*++
Purpose:
Initialize the thread pool when the DLL is loaded by IIS.
Arguments:
hinstDLL - DLL instance handle
fdwReason - notification code
lpdvContext - reserved
Returns:
TRUE if notification was successfully processed by the DLL
FALSE to indicate a failure
--*/
{
BOOL fReturn = TRUE;
switch ( fdwReason ) {
case DLL_PROCESS_ATTACH:
fReturn = InitThreadPool( );
break;
}
return fReturn;
}
BOOL WINAPI
GetExtensionVersion(
OUT HSE_VERSION_INFO * pVer
)
/*++
Purpose:
This is required ISAPI Extension DLL entry point.
Arguments:
pVer - poins to extension version info structure
Returns:
always returns TRUE
--*/
{
pVer->dwExtensionVersion = MAKELONG( HSE_VERSION_MINOR, HSE_VERSION_MAJOR );
lstrcpyn(
pVer->lpszExtensionDesc,
"ISAPI Keep-Alive with Thread Pool Extension Sample",
HSE_MAX_EXT_DLL_NAME_LEN );
return TRUE;
}
DWORD WINAPI
HttpExtensionProc(
IN EXTENSION_CONTROL_BLOCK * pECB
)
/*++
Purpose:
Demonstrate usage of persistent connections serviced by a thread pool.
Arguments:
pECB - points to the extension control block
Returns:
HSE_STATUS_PENDING if request was successfully queued
HSE_SUCCESS_AND_KEEP_CONN if request was served immediately
(presumably because the queue was full)
--*/
{
DWORD dwSize;
HSE_SEND_HEADER_EX_INFO HeaderExInfo;
char szHeader[] =
"Connection: Keep-Alive\r\n"
"Content-Length: %lu\r\n"
"Content-type: text/html\r\n\r\n";
char szBusyMessage[] =
"<html> <form method=get action=KeepAliveP.dll> <input type=submit> "
"<br>pECB->ConnID=%lu <br>Server was too busy. </form></html>";
char szBuffer[4096];
char szBuffer2[4096];
EnterCriticalSection( &csQueueLock );
if ( !AddWorkQueueEntry( pECB ) ) {
//
// if ECB could not be assigned
//
LeaveCriticalSection( &csQueueLock );
sprintf( szBuffer2, szBusyMessage, pECB->ConnID );
//
// Send outgoing header
//
sprintf( szBuffer, szHeader, strlen( szBuffer2 ) );
HeaderExInfo.pszHeader = szBuffer;
HeaderExInfo.cchHeader = strlen( szBuffer );
HeaderExInfo.pszStatus = "200 OK";
HeaderExInfo.cchStatus = strlen( HeaderExInfo.pszStatus );
HeaderExInfo.fKeepConn = TRUE;
pECB->ServerSupportFunction(
pECB->ConnID,
HSE_REQ_SEND_RESPONSE_HEADER_EX,
&HeaderExInfo,
NULL,
NULL
);
//
// Send content
//
dwSize = strlen( szBuffer2 );
pECB->WriteClient( pECB->ConnID, szBuffer2, &dwSize, 0 );
return HSE_STATUS_SUCCESS_AND_KEEP_CONN;
} else {
//
// release 1 thread from the pool
//
ReleaseSemaphore( hWorkSem, 1, NULL );
LeaveCriticalSection( &csQueueLock );
}
return HSE_STATUS_PENDING;
}
BOOL WINAPI
TerminateExtension(
IN DWORD dwFlags
)
/*++
Routine Description:
This function is called when the WWW service is shutdown
Arguments:
dwFlags - HSE_TERM_ADVISORY_UNLOAD or HSE_TERM_MUST_UNLOAD
Return Value:
TRUE if extension is ready to be unloaded,
FALSE otherwise
--*/
{
return TRUE;
}
DWORD WINAPI
WorkerFunction(
IN LPVOID pvThreadNum
)
/*++
Purpose:
Worker thread function - simulates extended processing
of the HTTP request
Arguments:
pvThreadNum - thread number
Returns:
alsways returns 0
--*/
{
EXTENSION_CONTROL_BLOCK *pECB;
DWORD dwRet, dwState, dwSize, dwThreadNum;
HSE_SEND_HEADER_EX_INFO HeaderExInfo;
//This header will be filled in with the content length
char szHeader[] =
"Connection: Keep-Alive\r\nContent-Length: %lu\r\n"
"Content-type: text/html\r\n\r\n";
char szContent[] =
"<html> <form method=get action=KeepAliveP.dll><input type=submit> "
"<br>pECB->ConnID=%lu <br>dwThreadNum=%lu</form></html>";
char szBuffer[4096];
char szBuffer2[4096];
dwThreadNum = ( DWORD ) pvThreadNum;
while ( TRUE ) {
dwRet = WaitForSingleObject( hWorkSem, INFINITE );
if ( dwRet == WAIT_OBJECT_0 ) {
EnterCriticalSection( &csQueueLock );
if ( GetWorkQueueEntry( &pECB ) ) {
//
// Found work to do
//
LeaveCriticalSection( &csQueueLock );
sprintf( szBuffer2, szContent, pECB->ConnID, dwThreadNum );
// Send outgoing header
sprintf( szBuffer, szHeader, strlen( szBuffer2 ) );
HeaderExInfo.pszHeader = szBuffer;
HeaderExInfo.cchHeader = strlen( szBuffer );
HeaderExInfo.pszStatus = "200 OK";
HeaderExInfo.cchStatus = strlen( HeaderExInfo.pszStatus );
HeaderExInfo.fKeepConn = TRUE;
pECB->ServerSupportFunction(
pECB->ConnID,
HSE_REQ_SEND_RESPONSE_HEADER_EX,
&HeaderExInfo,
NULL,
NULL
);
//
// Simulate extended processing
//
Sleep( 3000 );
//
// Send content
//
dwSize = strlen( szBuffer2 );
pECB->WriteClient( pECB->ConnID, szBuffer2, &dwSize, 0 );
//
// Tell IIS to keep the connection open
//
dwState = HSE_STATUS_SUCCESS_AND_KEEP_CONN;
pECB->ServerSupportFunction(
pECB->ConnID,
HSE_REQ_DONE_WITH_SESSION,
&dwState,
NULL,
0
);
} else {
//
// No item found is unexpected condition - exit thread
//
LeaveCriticalSection( &csQueueLock );
ExitThread( 0 );
}
} else {
break;
}
}
return 0;
}