/*++ 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 #include #include #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[] = "
" "
pECB->ConnID=%lu
Server was too busy.
"; 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[] = "
" "
pECB->ConnID=%lu
dwThreadNum=%lu
"; 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; }