home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 February / CHIP_2_98.iso / software / pelne / optionp / iis4_07.cab / fwasync.c < prev    next >
Text File  |  1997-10-25  |  12KB  |  552 lines

  1. /*++
  2.  
  3. Copyright (c) 1995-1997  Microsoft Corporation
  4.  
  5. Module Name:
  6.  
  7.     fwasync.c
  8.  
  9. Abstract:
  10.  
  11.     This module demonstrates a simple file transfer using ISAPI application
  12.       using the Async WriteClient() with callback.
  13.  
  14. Revision History:
  15. --*/
  16.  
  17. # include <windows.h>
  18. # include <stdio.h>
  19. # include "httpext.h"
  20. # include "openf.h"
  21.  
  22. /************************************************************
  23.  *  Global Data
  24.  ************************************************************/
  25.  
  26. LIST_ENTRY g_lWorkItems;
  27. CRITICAL_SECTION g_csWorkItems;
  28.  
  29. # define USE_WORK_QUEUE   (0)
  30.  
  31.  
  32. DWORD
  33. SendHeaderToClient( IN EXTENSION_CONTROL_BLOCK  * pecb, IN LPCSTR pszErrorMsg);
  34.  
  35.  
  36. DWORD
  37. SendFileToClient( IN EXTENSION_CONTROL_BLOCK  * pecb, IN LPCSTR pszFile);
  38.  
  39. DWORD
  40. SendFileOver( IN EXTENSION_CONTROL_BLOCK  * pecb, IN HANDLE hFile);
  41.  
  42.  
  43.  
  44.  
  45.  
  46. /************************************************************
  47.  *    Functions
  48.  ************************************************************/
  49.  
  50.  
  51. BOOL WINAPI
  52. DllMain(
  53.      IN HINSTANCE hinstDll,
  54.      IN DWORD     fdwReason,
  55.      IN LPVOID    lpvContext OPTIONAL)
  56. /*++
  57.  
  58.  Routine Description:
  59.  
  60.    This function DllLibMain() is the main initialization function for
  61.     this DLL. It initializes local variables and prepares it to be invoked
  62.     subsequently.
  63.  
  64.  Arguments:
  65.  
  66.    hinstDll          Instance Handle of the DLL
  67.    fdwReason         Reason why NT called this DLL
  68.    lpvReserved       Reserved parameter for future use.
  69.  
  70.  Return Value:
  71.  
  72.     Returns TRUE is successful; otherwise FALSE is returned.
  73.  
  74. --*/
  75. {
  76.   BOOL    fReturn = TRUE;
  77.  
  78.   switch (fdwReason ) {
  79.  
  80.     case DLL_PROCESS_ATTACH:
  81.       {
  82.           OutputDebugString( "Initializing the global data for fwasync.dll\n");
  83.  
  84.           //
  85.           // Initialize various data and modules.
  86.           //
  87.           InitializeCriticalSection(&g_csWorkItems);
  88.           InitializeListHead( &g_lWorkItems);
  89.           fReturn = (InitFileHandleCache() == NO_ERROR);
  90.  
  91.           break;
  92.       } /* case DLL_PROCESS_ATTACH */
  93.  
  94.     case DLL_PROCESS_DETACH:
  95.       {
  96.  
  97.           //
  98.           // Only cleanup when we are called because of a FreeLibrary().
  99.           //  i.e., when lpvContext == NULL
  100.           // If we are called because of a process termination,
  101.           //  dont free anything. System will free resources and memory for us.
  102.           //
  103.  
  104.           CleanupFileHandleCache();
  105.           if ( lpvContext != NULL) {
  106.  
  107.               DeleteCriticalSection(&g_csWorkItems);
  108.           }
  109.  
  110.           break;
  111.       } /* case DLL_PROCESS_DETACH */
  112.  
  113.     default:
  114.       break;
  115.   }   /* switch */
  116.  
  117.   return ( fReturn);
  118. }  /* DllLibMain() */
  119.  
  120.  
  121.  
  122.  
  123. DWORD WINAPI
  124. HttpExtensionProc(
  125.     EXTENSION_CONTROL_BLOCK * pecb
  126.     )
  127. /*++
  128.  
  129.  Routine Description:
  130.  
  131.    This function performs the necessary action to send response for the
  132.     request received from the client. It picks up the name of a file from
  133.     the pecb->lpszQueryString and sends the file using Asynchronous WriteClient
  134.  
  135.  Arguments:
  136.  
  137.    pecb          pointer to ECB containing parameters related to the request.
  138.  
  139.  Return Value:
  140.  
  141.     Returns HSE_* status codes
  142. --*/
  143. {
  144.     DWORD hseStatus;
  145.  
  146.  
  147.     if ( pecb->lpszQueryString == NULL) {
  148.  
  149.         hseStatus = SendHeaderToClient( pecb, "File Not Found");
  150.     } else {
  151.  
  152.         hseStatus = SendFileToClient( pecb, pecb->lpszQueryString);
  153.     }
  154.  
  155.     return ( hseStatus);
  156.  
  157. } // HttpExtensionProc()
  158.  
  159.  
  160.  
  161.  
  162.  
  163. BOOL WINAPI
  164. GetExtensionVersion(
  165.     HSE_VERSION_INFO * pver
  166.     )
  167. {
  168.     pver->dwExtensionVersion = MAKELONG( 1, 0 );
  169.     strcpy( pver->lpszExtensionDesc,
  170.            "File Transfer using WriteClient" );
  171.  
  172.     return TRUE;
  173. }
  174.  
  175.  
  176. BOOL WINAPI
  177. TerminateExtension(
  178.                    /*IN */ DWORD dwFlags
  179.     )
  180. /*++
  181.   This function is called when IIS decides to stop and unload the 
  182.   ISAPI DLL. We can do any custom cleanup for the module inside this function
  183. --*/
  184. {
  185.     //
  186.     // Nothing specific do here for cleanup
  187.     // Cleanup is done in the dll process detach in DllLibMain()
  188.     //
  189.  
  190.     return ( TRUE);
  191. }
  192.  
  193.  
  194.  
  195.  
  196. DWORD
  197. SendHeaderToClient( IN EXTENSION_CONTROL_BLOCK  * pecb, IN LPCSTR pszErrorMsg)
  198. {
  199.     HSE_SEND_HEADER_EX_INFO    SendHeaderExInfo;
  200.     char szStatus[]     = "200 OK";
  201.     char szHeader[1024];
  202.  
  203.     //
  204.     //  Note the HTTP header block is terminated by a blank '\r\n' pair,
  205.     //  followed by the document body
  206.     //
  207.  
  208.     wsprintf( szHeader,
  209.               "Content-Type: text/html\r\n"
  210.               "\r\n"              // marks the end of header block
  211.               "<head><title>Simple File Transfer (Async Write)"
  212.               "</title></head>\n"
  213.               "<body><h1>%s</h1>\n"
  214.               ,
  215.               pszErrorMsg );
  216.  
  217.  
  218.     //
  219.     //  Populate SendHeaderExInfo struct
  220.     //
  221.  
  222.     SendHeaderExInfo.pszStatus = szStatus;
  223.     SendHeaderExInfo.pszHeader = szHeader;
  224.     SendHeaderExInfo.cchStatus = lstrlen( szStatus);
  225.     SendHeaderExInfo.cchHeader = lstrlen( szHeader);
  226.     SendHeaderExInfo.fKeepConn = FALSE;
  227.  
  228.     //
  229.     //  Send header - use the EX Version to send the header blob
  230.     //
  231.  
  232.     if ( !pecb->ServerSupportFunction(
  233.                 pecb->ConnID
  234.                 , HSE_REQ_SEND_RESPONSE_HEADER_EX
  235.                 , &SendHeaderExInfo
  236.                 , NULL
  237.                 , NULL
  238.             ) ) {
  239.  
  240.         return HSE_STATUS_ERROR;
  241.     }
  242.     
  243.     return ( HSE_STATUS_SUCCESS);
  244. } // SendHeaderToClient()
  245.  
  246.  
  247.  
  248. DWORD
  249. SendFileToClient( IN EXTENSION_CONTROL_BLOCK  * pecb, IN LPCSTR pszFile)
  250. {
  251.     CHAR    pchBuffer[1024];
  252.     HANDLE  hFile;
  253.     DWORD   hseStatus = HSE_STATUS_SUCCESS;
  254.  
  255.     hFile = FcOpenFile( pecb, pszFile);
  256.  
  257.     if ( hFile == INVALID_HANDLE_VALUE) {
  258.  
  259.  
  260.         wsprintfA( pchBuffer,
  261.                   "OpenFailed: Error (%d) while opening the file %s.\n",
  262.                   GetLastError(), pszFile);
  263.  
  264.         hseStatus = SendHeaderToClient( pecb, pchBuffer);
  265.  
  266.     } else {
  267.  
  268.         wsprintfA( pchBuffer, " Transferred file contains...");
  269.  
  270.         hseStatus = SendHeaderToClient( pecb, pchBuffer);
  271.  
  272.         if ( hseStatus == HSE_STATUS_SUCCESS) {
  273.  
  274.             hseStatus = SendFileOver( pecb, hFile);
  275.  
  276.             if ( hseStatus != HSE_STATUS_PENDING) {
  277.  
  278.                 //
  279.                 // assume that the data is transmitted.
  280.                 //
  281.  
  282.                 // close file handle
  283.                 FcCloseFile( hFile);
  284.  
  285.                 if ( hseStatus != HSE_STATUS_SUCCESS) {
  286.  
  287.                     //
  288.                     // Error in transmitting the file. Send error message.
  289.                     //
  290.  
  291.                     wsprintfA( pchBuffer,
  292.                               "Send Failed: Error (%d) for file %s.\n",
  293.                               GetLastError(), pszFile);
  294.  
  295.                     SendHeaderToClient( pecb, pchBuffer);
  296.                 }
  297.             }
  298.         }
  299.     }
  300.  
  301.     return (hseStatus);
  302.  
  303. } // SendFileToClient()
  304.  
  305.  
  306.  
  307.  
  308. # define MAX_BUFFER_SIZE  (4096)
  309.  
  310. typedef struct _AIO_WORK_ITEM {
  311.  
  312.     LIST_ENTRY    listEntry;
  313.     EXTENSION_CONTROL_BLOCK * pecb;
  314.     HANDLE        hFile;
  315.     OVERLAPPED    ov;
  316.     DWORD         nRead;
  317.     CHAR          pchBuffer[ MAX_BUFFER_SIZE ];
  318.  
  319. }  AIO_WORK_ITEM, * PAWI;
  320.  
  321.  
  322.  
  323. DWORD
  324. ReadDataForPaw(IN PAWI paw)
  325. {
  326.     DWORD hseStatus = HSE_STATUS_SUCCESS;
  327.  
  328.     // read data from the file
  329.     if (!FcReadFromFile( paw->hFile, paw->pchBuffer, MAX_BUFFER_SIZE,
  330.                          &paw->nRead,
  331.                          &paw->ov)
  332.         ) {
  333.  
  334.         hseStatus = HSE_STATUS_ERROR;
  335.     }
  336.  
  337.     return (hseStatus);
  338.  
  339. } // ReadDataForPaw()
  340.  
  341.  
  342.  
  343.  
  344. DWORD
  345. SendDataForPaw(IN PAWI paw)
  346. {
  347.     DWORD hseStatus = HSE_STATUS_PENDING;
  348.  
  349.     // write data to client
  350.  
  351.     if ( !paw->pecb->WriteClient( paw->pecb->ConnID,
  352.                                  paw->pchBuffer,
  353.                                  &paw->nRead,
  354.                                  HSE_IO_ASYNC)
  355.         ) {
  356.  
  357.         hseStatus = HSE_STATUS_ERROR;
  358.     }
  359.  
  360.     return (hseStatus);
  361. } // SendDataForPaw()
  362.  
  363.  
  364.  
  365.  
  366. VOID
  367. CleanupAW( IN PAWI paw, IN BOOL fDoneWithSession)
  368. {
  369.  
  370.     DWORD err = GetLastError();
  371.  
  372.     FcCloseFile( paw->hFile);
  373.     CloseHandle( paw->ov.hEvent);
  374.  
  375.     if (fDoneWithSession) {
  376.         paw->pecb->ServerSupportFunction( paw->pecb->ConnID,
  377.                                          HSE_REQ_DONE_WITH_SESSION,
  378.                                          NULL, NULL, NULL);
  379.     }
  380.     SetLastError( err);
  381.  
  382.     //
  383.     // Remove from work items list
  384.     //
  385. #if USE_WORK_QUEUE
  386.     EnterCriticalSection( &g_csWorkItems);
  387.     RemoveEntryList( &paw->listEntry);
  388.     LeaveCriticalSection( &g_csWorkItems);
  389. # endif
  390.  
  391.     LocalFree( paw);
  392.     return;
  393.  
  394. } // CleanupAW()
  395.  
  396.  
  397.  
  398.  
  399. VOID WINAPI
  400. HseIoCompletion(
  401.                 IN EXTENSION_CONTROL_BLOCK * pECB,
  402.                 IN PVOID    pContext,
  403.                 IN DWORD    cbIO,
  404.                 IN DWORD    dwError
  405.                 )
  406. /*++
  407.  
  408.  Routine Description:
  409.  
  410.    This is the callback function for handling completions of asynchronous IO.
  411.    This function performs necessary cleanup and resubmits additional IO
  412.     (if required). In this case, this function is called at the end of a
  413.     successful Async WriteClient(). This function attempts to read the next
  414.     chunk of data and sends it to client. If there is no next chunk this
  415.     function cleans up the state and informs IIS about its intention to end
  416.     the request.
  417.  
  418.  Arguments:
  419.  
  420.    pecb          pointer to ECB containing parameters related to the request.
  421.    pContext      context information supplied with the asynchronous IO call.
  422.    cbIO          count of bytes of IO in the last call.
  423.    dwError       Error if any, for the last IO operation.
  424.  
  425.  Return Value:
  426.  
  427.    None.
  428. --*/
  429. {
  430.     PAWI    paw = (PAWI ) pContext;
  431.     EXTENSION_CONTROL_BLOCK   * pecb = paw->pecb;
  432.     DWORD   hseStatus;
  433.  
  434.  
  435.     //
  436.     // 1. if no errors, do another read of the file
  437.     // 2. send the read contents to client
  438.     // 3. if no data present, cleanup and exit
  439.     //
  440.  
  441.     if ( dwError != NO_ERROR) {
  442.  
  443.         //
  444.         // Do Cleanup
  445.         //
  446.  
  447.         CleanupAW( paw, TRUE);
  448.         return;
  449.     }
  450.  
  451.     //    assert( paw->nRead == cbIO);
  452.  
  453.  
  454.     //
  455.     // Read next chunk of data
  456.     //
  457.     
  458.     paw->nRead = 0;
  459.     hseStatus = ReadDataForPaw( paw);
  460.     
  461.     if ( hseStatus == HSE_STATUS_SUCCESS && paw->nRead > 0) {
  462.         
  463.         hseStatus = SendDataForPaw( paw);
  464.     }
  465.  
  466.     if ( hseStatus != HSE_STATUS_PENDING) {
  467.  
  468.         CleanupAW( paw, TRUE);
  469.     }
  470.  
  471.     return;
  472. } // HseIoCompletion()
  473.  
  474.  
  475.  
  476. DWORD
  477. SendFileOver( IN EXTENSION_CONTROL_BLOCK  * pecb, IN HANDLE hFile)
  478. {
  479.  
  480.     PAWI   paw;
  481.     DWORD  hseStatus = HSE_STATUS_SUCCESS;
  482.  
  483.     paw  = (PAWI ) LocalAlloc( LMEM_FIXED, sizeof(AIO_WORK_ITEM));
  484.     if ( paw == NULL) {
  485.  
  486.         SetLastError( ERROR_NOT_ENOUGH_MEMORY);
  487.         return (HSE_STATUS_ERROR);
  488.     }
  489.  
  490.     //
  491.     // Fill in all the data in AIO_WORK_ITEM
  492.     //
  493.     paw->pecb = pecb;
  494.     InitializeListHead( &paw->listEntry);
  495.     paw->hFile = hFile;
  496.     paw->nRead = 0;
  497.     memset( &paw->ov, 0, sizeof(OVERLAPPED));
  498.     paw->ov.OffsetHigh = 0;
  499.     paw->ov.Offset = 0;
  500.     paw->ov.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL);
  501.  
  502.     if ( paw->ov.hEvent == NULL) {
  503.  
  504.         LocalFree( paw);
  505.         return (HSE_STATUS_ERROR);
  506.     }
  507.  
  508.     //
  509.     // Setup the callback context for the Async IO
  510.     //
  511.  
  512.     if ( !pecb->ServerSupportFunction( pecb->ConnID,
  513.                                        HSE_REQ_IO_COMPLETION,
  514.                                        HseIoCompletion,
  515.                                        0,
  516.                                        (LPDWORD ) paw)
  517.         ) {
  518.  
  519.         //
  520.         // Do cleanup and return error
  521.         //
  522.  
  523.         CloseHandle( paw->ov.hEvent);
  524.         LocalFree( paw);
  525.         return HSE_STATUS_ERROR;
  526.     }
  527.  
  528.     // Add to the list
  529. #if USE_WORK_QUEUE
  530.     EnterCriticalSection( &g_csWorkItems);
  531.     InsertTailList( &g_lWorkItems,  &paw->listEntry);
  532.     LeaveCriticalSection( &g_csWorkItems);
  533. #endif
  534.  
  535.     hseStatus = ReadDataForPaw( paw);
  536.  
  537.     if ( hseStatus == HSE_STATUS_SUCCESS && paw->nRead > 0 ) {
  538.  
  539.  
  540.         hseStatus = SendDataForPaw( paw);
  541.     }
  542.  
  543.     if ( hseStatus != HSE_STATUS_PENDING) {
  544.  
  545.         CleanupAW(paw, FALSE);
  546.     }
  547.  
  548.     return (hseStatus);
  549.  
  550. } // SendFileOver()
  551.  
  552.