Microsoft KB Archive/171617: Difference between revisions

From BetaArchive Wiki
(importing KB archive)
 
m (Text replacement - "&" to "&")
 
(3 intermediate revisions by the same user not shown)
Line 34: Line 34:
When an IIS ISAPI extension implements a WorkerFunction, and then that worker function completes its task, the worker function thread and the associated thread within IIS that issued the read request are torn down. As a result, the session is torn down.<br />
When an IIS ISAPI extension implements a WorkerFunction, and then that worker function completes its task, the worker function thread and the associated thread within IIS that issued the read request are torn down. As a result, the session is torn down.<br />
<br />
<br />
To test if you are running into this situation, you can add a statement (&quot;Sleep ( INFINITE );&quot; ) to the end of your WorkerFunction to delay it so the read request can return.<br />
To test if you are running into this situation, you can add a statement ("Sleep ( INFINITE );" ) to the end of your WorkerFunction to delay it so the read request can return.<br />
<br />
<br />
To verify this is what is taking place, you should take a network trace and check to make sure that the socket number for the session is being maintained when the client hits refresh or some other object on the web page.<br />
To verify this is what is taking place, you should take a network trace and check to make sure that the socket number for the session is being maintained when the client hits refresh or some other object on the web page.<br />
Line 47: Line 47:
//  a worker thread.
//  a worker thread.
//  
//  
//  KeepAlive.c  -&gt; Sample ISAPI Extension demonstrating Keep-Alive.
//  KeepAlive.c  -> Sample ISAPI Extension demonstrating Keep-Alive.
// **************************************************************  
// **************************************************************  


#include &lt;windows.h&gt;
#include <windows.h>
#include &lt;httpext.h&gt;
#include <httpext.h>
#include &lt;stdio.h&gt;
#include <stdio.h>


BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer)
BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer)
{
{
     pVer-&gt;dwExtensionVersion = MAKELONG(HSE_VERSION_MINOR, HSE_VERSION_MAJOR);
     pVer->dwExtensionVersion = MAKELONG(HSE_VERSION_MINOR, HSE_VERSION_MAJOR);
     lstrcpyn(pVer-&gt;lpszExtensionDesc, &quot;ISAPI Keep-Alive Extension Sample&quot;,  
     lstrcpyn(pVer->lpszExtensionDesc, "ISAPI Keep-Alive Extension Sample",  
             HSE_MAX_EXT_DLL_NAME_LEN);
             HSE_MAX_EXT_DLL_NAME_LEN);


Line 69: Line 69:
// This header will be filled in with the content length
// This header will be filled in with the content length


     char szHeader[]=&quot;Connection: Keep-Alive\r\nContent-Length: %lu\r\nContent-type:
     char szHeader[]="Connection: Keep-Alive\r\nContent-Length: %lu\r\nContent-type:
                                     text/html\r\n\r\n&quot;;
                                     text/html\r\n\r\n";
     char szContent[]=&quot;&lt;html&gt; &lt;form method=get action=KeepAlive.dll&gt;&lt;input type=submit&gt;
     char szContent[]="<html> <form method=get action=KeepAlive.dll><input type=submit>
                                     &lt;/form&gt;&lt;/html&gt;&quot;;
                                     </form></html>";
     char szBuffer[4096];
     char szBuffer[4096];


Line 79: Line 79:
     sprintf(szBuffer, szHeader, strlen(szContent));
     sprintf(szBuffer, szHeader, strlen(szContent));
     dwSize = strlen(szBuffer);
     dwSize = strlen(szBuffer);
     pECB-&gt;ServerSupportFunction(pECB, HSE_REQ_SEND_RESPONSE_HEADER,
     pECB->ServerSupportFunction(pECB, HSE_REQ_SEND_RESPONSE_HEADER,
                             NULL, &amp;dwSize, (unsigned long *)szBuffer);
                             NULL, &dwSize, (unsigned long *)szBuffer);
      
      
     // Send content
     // Send content
     dwSize = strlen(szContent);
     dwSize = strlen(szContent);
     pECB-&gt;WriteClient(pECB, szContent, &amp;dwSize, 0);
     pECB->WriteClient(pECB, szContent, &dwSize, 0);


     return HSE_STATUS_SUCCESS_AND_KEEP_CONN;
     return HSE_STATUS_SUCCESS_AND_KEEP_CONN;
Line 98: Line 98:
//    implementing Keep-Alive.
//    implementing Keep-Alive.
//  
//  
//  KeepAliveT.c  -&gt; Sample ISAPI Extension demonstrating Keep-Alive
//  KeepAliveT.c  -> Sample ISAPI Extension demonstrating Keep-Alive
//    in a worker thread that terminates immediately which causes the
//    in a worker thread that terminates immediately which causes the
//  session to NOT be maintained.
//  session to NOT be maintained.
//  *******************************************************************
//  *******************************************************************


#include &lt;windows.h&gt;
#include <windows.h>
#include &lt;httpext.h&gt;
#include <httpext.h>
#include &lt;stdio.h&gt;
#include <stdio.h>


DWORD WINAPI WorkerFunction( LPVOID );  
DWORD WINAPI WorkerFunction( LPVOID );  
Line 111: Line 111:
BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer)
BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer)
{
{
     pVer-&gt;dwExtensionVersion = MAKELONG(HSE_VERSION_MINOR, HSE_VERSION_MAJOR);
     pVer->dwExtensionVersion = MAKELONG(HSE_VERSION_MINOR, HSE_VERSION_MAJOR);
     lstrcpyn(pVer-&gt;lpszExtensionDesc, &quot;ISAPI Keep-Alive Extension Sample&quot;,  
     lstrcpyn(pVer->lpszExtensionDesc, "ISAPI Keep-Alive Extension Sample",  
             HSE_MAX_EXT_DLL_NAME_LEN);
             HSE_MAX_EXT_DLL_NAME_LEN);


Line 122: Line 122:
     DWORD dwThreadID;
     DWORD dwThreadID;


     CreateThread(NULL, 0, WorkerFunction, pECB, 0, &amp;dwThreadID);
     CreateThread(NULL, 0, WorkerFunction, pECB, 0, &dwThreadID);


     return HSE_STATUS_PENDING;
     return HSE_STATUS_PENDING;
Line 134: Line 134:


     //This header will be filled in with the content length
     //This header will be filled in with the content length
     char szHeader[]=&quot;Connection: Keep-Alive\r\nContent-Length: %lu\r\nContent-type: text/html\r\n\r\n&quot;;
     char szHeader[]="Connection: Keep-Alive\r\nContent-Length: %lu\r\nContent-type: text/html\r\n\r\n";
     char szContent[]=&quot;&lt;html&gt; &lt;form method=get action=KeepAliveT.dll&gt;&lt;input type=submit&gt; &lt;/form&gt;&lt;/html&gt;&quot;;
     char szContent[]="<html> <form method=get action=KeepAliveT.dll><input type=submit> </form></html>";
     char szBuffer[4096];
     char szBuffer[4096];


Line 143: Line 143:
     sprintf(szBuffer, szHeader, strlen(szContent));
     sprintf(szBuffer, szHeader, strlen(szContent));
     dwSize = strlen(szBuffer);
     dwSize = strlen(szBuffer);
     pECB-&gt;ServerSupportFunction(pECB-&gt;ConnID, HSE_REQ_SEND_RESPONSE_HEADER,
     pECB->ServerSupportFunction(pECB->ConnID, HSE_REQ_SEND_RESPONSE_HEADER,
                 NULL, &amp;dwSize, (unsigned long *)szBuffer);
                 NULL, &dwSize, (unsigned long *)szBuffer);
      
      
     // Send content
     // Send content
     dwSize = strlen(szContent);
     dwSize = strlen(szContent);
     pECB-&gt;WriteClient(pECB-&gt;ConnID, szContent, &amp;dwSize, 0);
     pECB->WriteClient(pECB->ConnID, szContent, &dwSize, 0);
      
      
     dwState = HSE_STATUS_SUCCESS_AND_KEEP_CONN;
     dwState = HSE_STATUS_SUCCESS_AND_KEEP_CONN;
     pECB-&gt;ServerSupportFunction(pECB-&gt;ConnID, HSE_REQ_DONE_WITH_SESSION, &amp;dwState, NULL, 0);
     pECB->ServerSupportFunction(pECB->ConnID, HSE_REQ_DONE_WITH_SESSION, &dwState, NULL, 0);


     return 0;
     return 0;
Line 165: Line 165:
// and work queue.
// and work queue.
//  
//  
// KeepAliveP.c  -&gt; Sample ISAPI Extension demonstrating
// KeepAliveP.c  -> Sample ISAPI Extension demonstrating
//                  Keep-Alive with a thread pool.
//                  Keep-Alive with a thread pool.
// ***************************************************************
// ***************************************************************


#include &lt;windows.h&gt;
#include <windows.h>
#include &lt;httpext.h&gt;
#include <httpext.h>
#include &lt;stdio.h&gt;
#include <stdio.h>


#define POOL_THREADS 2
#define POOL_THREADS 2
Line 206: Line 206:
                 return FALSE;
                 return FALSE;


             InitializeCriticalSection(&amp;csQueueLock );
             InitializeCriticalSection(&csQueueLock );
              
              
             fFirstCall=TRUE;
             fFirstCall=TRUE;


             // Create Pool Threads
             // Create Pool Threads
             for(i=0; i&lt;POOL_THREADS; i++)
             for(i=0; i<POOL_THREADS; i++)
             {   
             {   
                 if(CreateThread(NULL, 0, WorkerFunction, (LPVOID)i, 0, &amp;dwThreadID)==NULL)
                 if(CreateThread(NULL, 0, WorkerFunction, (LPVOID)i, 0, &dwThreadID)==NULL)
                     return FALSE;
                     return FALSE;
             }
             }
Line 229: Line 229:
BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer)
BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer)
{
{
     pVer-&gt;dwExtensionVersion = MAKELONG(HSE_VERSION_MINOR, HSE_VERSION_MAJOR);
     pVer->dwExtensionVersion = MAKELONG(HSE_VERSION_MINOR, HSE_VERSION_MAJOR);
     lstrcpyn(pVer-&gt;lpszExtensionDesc, &quot;ISAPI Keep-Alive Extension Sample&quot;,  
     lstrcpyn(pVer->lpszExtensionDesc, "ISAPI Keep-Alive Extension Sample",  
             HSE_MAX_EXT_DLL_NAME_LEN);
             HSE_MAX_EXT_DLL_NAME_LEN);


Line 239: Line 239:
{
{
     DWORD dwSize;
     DWORD dwSize;
     char szHeader[]=&quot;Connection: Keep-Alive\r\nContent-Length: %lu\r\nContent-type: text/html\r\n\r\n&quot;;
     char szHeader[]="Connection: Keep-Alive\r\nContent-Length: %lu\r\nContent-type: text/html\r\n\r\n";
     char szContent[]=&quot;&lt;html&gt; &lt;form method=get action=KeepAliveP.dll&gt; &lt;input type=submit&gt; &quot; \  
     char szContent[]="<html> <form method=get action=KeepAliveP.dll> <input type=submit> " \  
                     &quot;&lt;br&gt;pECB-&gt;ConnID=%lu  &lt;br&gt;Server was too busy. &lt;/form&gt;&lt;/html&gt;&quot;;
                     "<br>pECB->ConnID=%lu  <br>Server was too busy. </form></html>";
     char szBuffer[4096];
     char szBuffer[4096];
     char szBuffer2[4096];
     char szBuffer2[4096];


     EnterCriticalSection(&amp;csQueueLock);
     EnterCriticalSection(&csQueueLock);
     if(!AddWorkQueueEntry(pECB)) // if ECB could not be assigned
     if(!AddWorkQueueEntry(pECB)) // if ECB could not be assigned
     {
     {
         LeaveCriticalSection(&amp;csQueueLock);
         LeaveCriticalSection(&csQueueLock);


         sprintf(szBuffer2, szContent, pECB-&gt;ConnID);
         sprintf(szBuffer2, szContent, pECB->ConnID);


         // Send outgoing header
         // Send outgoing header
         sprintf(szBuffer, szHeader, strlen(szBuffer2));
         sprintf(szBuffer, szHeader, strlen(szBuffer2));
         dwSize = strlen(szBuffer);
         dwSize = strlen(szBuffer);
         pECB-&gt;ServerSupportFunction(pECB-&gt;ConnID, HSE_REQ_SEND_RESPONSE_HEADER,
         pECB->ServerSupportFunction(pECB->ConnID, HSE_REQ_SEND_RESPONSE_HEADER,
             NULL, &amp;dwSize, (unsigned long *)szBuffer);
             NULL, &dwSize, (unsigned long *)szBuffer);
      
      
         // Send content
         // Send content
         dwSize = strlen(szBuffer2);
         dwSize = strlen(szBuffer2);
         pECB-&gt;WriteClient(pECB-&gt;ConnID, szBuffer2, &amp;dwSize, 0);
         pECB->WriteClient(pECB->ConnID, szBuffer2, &dwSize, 0);


         return HSE_STATUS_SUCCESS_AND_KEEP_CONN;
         return HSE_STATUS_SUCCESS_AND_KEEP_CONN;
Line 267: Line 267:
     {
     {
         ReleaseSemaphore( hWorkSem, 1, NULL );  //Release 1 thread from pool
         ReleaseSemaphore( hWorkSem, 1, NULL );  //Release 1 thread from pool
         LeaveCriticalSection(&amp;csQueueLock);
         LeaveCriticalSection(&csQueueLock);
     }
     }


Line 278: Line 278:
     DWORD i;
     DWORD i;


     for(i=0; i&lt;WORK_QUEUE_ENTRIES; i++)
     for(i=0; i<WORK_QUEUE_ENTRIES; i++)
     {
     {
         if (ECBqueue[i].pECB==NULL)
         if (ECBqueue[i].pECB==NULL)
Line 322: Line 322:


     //This header will be filled in with the content length
     //This header will be filled in with the content length
     char szHeader[]=&quot;Connection: Keep-Alive\r\nContent-Length: %lu\r\nContent-type: text/html\r\n\r\n&quot;;
     char szHeader[]="Connection: Keep-Alive\r\nContent-Length: %lu\r\nContent-type: text/html\r\n\r\n";
     char szContent[]=&quot;&lt;html&gt; &lt;form method=get action=KeepAliveP.dll&gt;&lt;input type=submit&gt; &quot;\  
     char szContent[]="<html> <form method=get action=KeepAliveP.dll><input type=submit> "\  
                     &quot;&lt;br&gt;pECB-&gt;ConnID=%lu  &lt;br&gt;dwThreadNum=%lu&lt;/form&gt;&lt;/html&gt;&quot;;
                     "<br>pECB->ConnID=%lu  <br>dwThreadNum=%lu</form></html>";
     char szBuffer[4096];
     char szBuffer[4096];
     char szBuffer2[4096];
     char szBuffer2[4096];
Line 336: Line 336:
         {
         {


             EnterCriticalSection(&amp;csQueueLock);
             EnterCriticalSection(&csQueueLock);


             if( GetWorkQueueEntry(&amp;pECB) )  // This function should always return true
             if( GetWorkQueueEntry(&pECB) )  // This function should always return true
             {
             {
                 LeaveCriticalSection(&amp;csQueueLock);
                 LeaveCriticalSection(&csQueueLock);
      
      
                 sprintf(szBuffer2, szContent, pECB-&gt;ConnID, dwThreadNum);
                 sprintf(szBuffer2, szContent, pECB->ConnID, dwThreadNum);


                 // Send outgoing header
                 // Send outgoing header
                 sprintf(szBuffer, szHeader, strlen(szBuffer2));
                 sprintf(szBuffer, szHeader, strlen(szBuffer2));
                 dwSize = strlen(szBuffer);
                 dwSize = strlen(szBuffer);
                 pECB-&gt;ServerSupportFunction(pECB-&gt;ConnID, HSE_REQ_SEND_RESPONSE_HEADER,
                 pECB->ServerSupportFunction(pECB->ConnID, HSE_REQ_SEND_RESPONSE_HEADER,
                     NULL, &amp;dwSize, (unsigned long *)szBuffer);
                     NULL, &dwSize, (unsigned long *)szBuffer);
          
          
                 Sleep(3000);
                 Sleep(3000);
Line 354: Line 354:
                 // Send content
                 // Send content
                 dwSize = strlen(szBuffer2);
                 dwSize = strlen(szBuffer2);
                 pECB-&gt;WriteClient(pECB-&gt;ConnID, szBuffer2, &amp;dwSize, 0);
                 pECB->WriteClient(pECB->ConnID, szBuffer2, &dwSize, 0);


                 dwState = HSE_STATUS_SUCCESS_AND_KEEP_CONN;
                 dwState = HSE_STATUS_SUCCESS_AND_KEEP_CONN;
                 pECB-&gt;ServerSupportFunction(pECB-&gt;ConnID, HSE_REQ_DONE_WITH_SESSION, &amp;dwState, NULL, 0);
                 pECB->ServerSupportFunction(pECB->ConnID, HSE_REQ_DONE_WITH_SESSION, &dwState, NULL, 0);
             }
             }
             else
             else
                 LeaveCriticalSection(&amp;csQueueLock);
                 LeaveCriticalSection(&csQueueLock);
                  
                  
         }
         }

Latest revision as of 12:30, 21 July 2020

IIS ISAPI ServerSupportFunction and Keep-Alive Session

Q171617



The information in this article applies to:


  • Microsoft Internet Server Application Programming Interface (API)
  • Microsoft Internet Information Server 3.0





SUMMARY

When you create an ISAPI application for Internet Information Server (IIS), this application will require that the session between the client browser and IIS be maintained via the Keep-Alive header.



MORE INFORMATION

To implement Keep-Alive, IIS uses an async I/O read request via a completion port on the session to maintain it. This method requires that the thread that sent the read request still be active when the read request returns, or else the session will be torn down.

When an IIS ISAPI extension implements a WorkerFunction, and then that worker function completes its task, the worker function thread and the associated thread within IIS that issued the read request are torn down. As a result, the session is torn down.

To test if you are running into this situation, you can add a statement ("Sleep ( INFINITE );" ) to the end of your WorkerFunction to delay it so the read request can return.

To verify this is what is taking place, you should take a network trace and check to make sure that the socket number for the session is being maintained when the client hits refresh or some other object on the web page.

The following are examples of how to maintain the session with Keep-Alive, and one example that shows it failing.


SAMPLE ONE:

// **************************************************************
//   Code sample showing Keep-Alive while implementing
//   a worker thread.
// 
//   KeepAlive.c  -> Sample ISAPI Extension demonstrating Keep-Alive.
// ************************************************************** 

#include <windows.h>
#include <httpext.h>
#include <stdio.h>

BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer)
{
    pVer->dwExtensionVersion = MAKELONG(HSE_VERSION_MINOR, HSE_VERSION_MAJOR);
    lstrcpyn(pVer->lpszExtensionDesc, "ISAPI Keep-Alive Extension Sample", 
            HSE_MAX_EXT_DLL_NAME_LEN);

    return TRUE;
}

DWORD WINAPI HttpExtensionProc(EXTENSION_CONTROL_BLOCK *pECB)
{
    DWORD dwSize;

// This header will be filled in with the content length

    char szHeader[]="Connection: Keep-Alive\r\nContent-Length: %lu\r\nContent-type:
                                    text/html\r\n\r\n";
    char szContent[]="<html> <form method=get action=KeepAlive.dll><input type=submit>
                                    </form></html>";
    char szBuffer[4096];

// Send outgoing header

    sprintf(szBuffer, szHeader, strlen(szContent));
    dwSize = strlen(szBuffer);
    pECB->ServerSupportFunction(pECB, HSE_REQ_SEND_RESPONSE_HEADER,
                            NULL, &dwSize, (unsigned long *)szBuffer);
    
    // Send content
    dwSize = strlen(szContent);
    pECB->WriteClient(pECB, szContent, &dwSize, 0);

    return HSE_STATUS_SUCCESS_AND_KEEP_CONN;
} 



SAMPLE TWO:

    
// *******************************************************************
//  The same code sample as above, but using a worker thread
//    implementing Keep-Alive.
// 
//  KeepAliveT.c  -> Sample ISAPI Extension demonstrating Keep-Alive
//    in a worker thread that terminates immediately which causes the
//  session to NOT be maintained.
//  *******************************************************************

#include <windows.h>
#include <httpext.h>
#include <stdio.h>

DWORD WINAPI WorkerFunction( LPVOID ); 

BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer)
{
    pVer->dwExtensionVersion = MAKELONG(HSE_VERSION_MINOR, HSE_VERSION_MAJOR);
    lstrcpyn(pVer->lpszExtensionDesc, "ISAPI Keep-Alive Extension Sample", 
            HSE_MAX_EXT_DLL_NAME_LEN);

    return TRUE;
}

DWORD WINAPI HttpExtensionProc(EXTENSION_CONTROL_BLOCK *pECB)
{
    DWORD dwThreadID;

    CreateThread(NULL, 0, WorkerFunction, pECB, 0, &dwThreadID);

    return HSE_STATUS_PENDING;
}


DWORD WINAPI WorkerFunction(LPVOID vECB)
{
    EXTENSION_CONTROL_BLOCK *pECB;
    DWORD dwState, dwSize;

    //This header will be filled in with the content length
    char szHeader[]="Connection: Keep-Alive\r\nContent-Length: %lu\r\nContent-type: text/html\r\n\r\n";
    char szContent[]="<html> <form method=get action=KeepAliveT.dll><input type=submit> </form></html>";
    char szBuffer[4096];

    pECB = vECB;
    
    // Send outgoing header
    sprintf(szBuffer, szHeader, strlen(szContent));
    dwSize = strlen(szBuffer);
    pECB->ServerSupportFunction(pECB->ConnID, HSE_REQ_SEND_RESPONSE_HEADER,
                NULL, &dwSize, (unsigned long *)szBuffer);
    
    // Send content
    dwSize = strlen(szContent);
    pECB->WriteClient(pECB->ConnID, szContent, &dwSize, 0);
    
    dwState = HSE_STATUS_SUCCESS_AND_KEEP_CONN;
    pECB->ServerSupportFunction(pECB->ConnID, HSE_REQ_DONE_WITH_SESSION, &dwState, NULL, 0);

    return 0;
} 



SAMPLE THREE:

// ***************************************************************
// This program demonstates the recommendated method for
// implementing Keep-Alive in a worker function using a thread pool
// and work queue.
// 
// KeepAliveP.c  -> Sample ISAPI Extension demonstrating
//                  Keep-Alive with a thread pool.
// ***************************************************************

#include <windows.h>
#include <httpext.h>
#include <stdio.h>

#define POOL_THREADS 2
#define WORK_QUEUE_ENTRIES 2

typedef struct {
    EXTENSION_CONTROL_BLOCK * pECB;
    DWORD dwNextEntry;
} ECB_QUEUE_ENTRY;

ECB_QUEUE_ENTRY ECBqueue[WORK_QUEUE_ENTRIES];

DWORD dwCurrentEntry, dwLastEntry;
CRITICAL_SECTION csQueueLock;
BOOL fFirstCall;
HANDLE hWorkSem;

BOOL AddWorkQueueEntry(EXTENSION_CONTROL_BLOCK *);
BOOL GetWorkQueueEntry(EXTENSION_CONTROL_BLOCK ** ppECB);
DWORD WINAPI WorkerFunction(LPVOID vThreadNum);

BOOL WINAPI DllMain(IN HINSTANCE hinstDll, IN DWORD fdwReason, IN LPVOID lpvContext OPTIONAL)
{
    BOOL        fReturn = TRUE;
    DWORD       i;
    DWORD       dwThreadID;

    switch (fdwReason )
    {
    case DLL_PROCESS_ATTACH:
        {
            // Create Semaphore in nonsignaled state
            if( (hWorkSem = CreateSemaphore( NULL, 0, 0x7fffffff, NULL )) ==NULL)
                return FALSE;

            InitializeCriticalSection(&csQueueLock );
            
            fFirstCall=TRUE;

            // Create Pool Threads
            for(i=0; i<POOL_THREADS; i++)
            {   
                if(CreateThread(NULL, 0, WorkerFunction, (LPVOID)i, 0, &dwThreadID)==NULL)
                    return FALSE;
            }

            // Clear work queue
            ZeroMemory(ECBqueue, WORK_QUEUE_ENTRIES*sizeof(ECB_QUEUE_ENTRY) );
        }
    }
    
    return fReturn;
}

DWORD WINAPI WorkerFunction( LPVOID ); 

BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer)
{
    pVer->dwExtensionVersion = MAKELONG(HSE_VERSION_MINOR, HSE_VERSION_MAJOR);
    lstrcpyn(pVer->lpszExtensionDesc, "ISAPI Keep-Alive Extension Sample", 
            HSE_MAX_EXT_DLL_NAME_LEN);

    return TRUE;
}

DWORD WINAPI HttpExtensionProc(EXTENSION_CONTROL_BLOCK *pECB)
{
    DWORD dwSize;
    char szHeader[]="Connection: Keep-Alive\r\nContent-Length: %lu\r\nContent-type: text/html\r\n\r\n";
    char szContent[]="<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, szContent, pECB->ConnID);

        // Send outgoing header
        sprintf(szBuffer, szHeader, strlen(szBuffer2));
        dwSize = strlen(szBuffer);
        pECB->ServerSupportFunction(pECB->ConnID, HSE_REQ_SEND_RESPONSE_HEADER,
            NULL, &dwSize, (unsigned long *)szBuffer);
    
        // Send content
        dwSize = strlen(szBuffer2);
        pECB->WriteClient(pECB->ConnID, szBuffer2, &dwSize, 0);

        return HSE_STATUS_SUCCESS_AND_KEEP_CONN;
    }
    else
    {
        ReleaseSemaphore( hWorkSem, 1, NULL );  //Release 1 thread from pool
        LeaveCriticalSection(&csQueueLock);
    }

    return HSE_STATUS_PENDING;
}


BOOL AddWorkQueueEntry(EXTENSION_CONTROL_BLOCK * pECB)
{
    DWORD i;

    for(i=0; i<WORK_QUEUE_ENTRIES; i++)
    {
        if (ECBqueue[i].pECB==NULL)
        {
            if(fFirstCall)
            {
                dwCurrentEntry=i;
                fFirstCall = FALSE;
            }
            else
                ECBqueue[dwLastEntry].dwNextEntry=i;
            ECBqueue[i].pECB=pECB;
            dwLastEntry=i;
            return TRUE;
        }
    }

    // If no NULL queue entry found, indicate failure
    return FALSE;
}

BOOL GetWorkQueueEntry(EXTENSION_CONTROL_BLOCK ** ppECB)
{
    if( (*ppECB=ECBqueue[dwCurrentEntry].pECB) == NULL)
        return FALSE;
    else
    {
        ECBqueue[dwCurrentEntry].pECB = NULL;
        if(dwCurrentEntry == dwLastEntry) // If this is only pending item
            fFirstCall = TRUE;
        else
            dwCurrentEntry = ECBqueue[dwCurrentEntry].dwNextEntry;
    }
    
    return TRUE;
}


DWORD WINAPI WorkerFunction(LPVOID pvThreadNum)
{
    EXTENSION_CONTROL_BLOCK *pECB;
    DWORD dwRet, dwState, dwSize, dwThreadNum;

    //This header will be filled in with the content length
    char szHeader[]="Connection: Keep-Alive\r\nContent-Length: %lu\r\nContent-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) )  // This function should always return true
            {
                LeaveCriticalSection(&csQueueLock);
    
                sprintf(szBuffer2, szContent, pECB->ConnID, dwThreadNum);

                // Send outgoing header
                sprintf(szBuffer, szHeader, strlen(szBuffer2));
                dwSize = strlen(szBuffer);
                pECB->ServerSupportFunction(pECB->ConnID, HSE_REQ_SEND_RESPONSE_HEADER,
                    NULL, &dwSize, (unsigned long *)szBuffer);
        
                Sleep(3000);
    
                // Send content
                dwSize = strlen(szBuffer2);
                pECB->WriteClient(pECB->ConnID, szBuffer2, &dwSize, 0);

                dwState = HSE_STATUS_SUCCESS_AND_KEEP_CONN;
                pECB->ServerSupportFunction(pECB->ConnID, HSE_REQ_DONE_WITH_SESSION, &dwState, NULL, 0);
            }
            else
                LeaveCriticalSection(&csQueueLock);
                
        }
        else
            break;
    }

    return 0;
} 

Additional query words: iis

Keywords : kbinterop
Issue type : kbhowto
Technology : kbiisSearch kbAudDeveloper kbiis300 kbISAPI kbISAPISearch


Last Reviewed: May 2, 1999
© 2001 Microsoft Corporation. All rights reserved. Terms of Use.