home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 February / CHIP_2_98.iso / software / pelne / optionp / iis4_07.cab / ftrans.c < prev    next >
C/C++ Source or Header  |  1997-10-25  |  12KB  |  525 lines

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