323 lines
6.4 KiB
C
323 lines
6.4 KiB
C
/*++
|
||
|
||
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;
|
||
}
|