G:/ScriptBasic/source/variations/winisapi/winisapi_new.c

Go to the documentation of this file.
00001 /*
00002 FILE:   winisapi.c
00003 HEADER: winisapi.h
00004 
00005 --GNU LGPL
00006 This library is free software; you can redistribute it and/or
00007 modify it under the terms of the GNU Lesser General Public
00008 License as published by the Free Software Foundation; either
00009 version 2.1 of the License, or (at your option) any later version.
00010 
00011 This library is distributed in the hope that it will be useful,
00012 but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014 Lesser General Public License for more details.
00015 
00016 You should have received a copy of the GNU Lesser General Public
00017 License along with this library; if not, write to the Free Software
00018 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 
00020 --
00021 */
00022 
00023 /*POD
00024 =H ISAPI variation of ScriptBasic
00025 
00026 This file implements the "main" function that embeds ScriptBasic as an isapi extension
00027 application for the Microsoft IIS web server.
00028 
00029 This function implements three major and some auxilliary functions. These are:
00030 
00031 =toc
00032 
00033 These are the functions that all ISAPI extensions should implement. Using this version
00034 under Windows NT instead of the standalone version (with CGI protocol) has speed
00035 advantage. This version reads the config file only once, and may keep the code also
00036 in memory.
00037 
00038 The weakness of the implementation is that after a code is loaded into memory it does
00039 not check if the source has changed. Therefore it is recommended to turn memory caching
00040 off during development and on in real word application.
00041 
00042 CUT*/
00043 
00044 #include <stdio.h>
00045 #include <stdlib.h>
00046 #include <string.h>
00047 #include <windows.h>
00048 #include <time.h>
00049 #include <httpext.h>
00050 #include <process.h>
00051 
00052 #include "../../scriba.h"
00053 
00054 /*POD
00055 =section IsapiStdOutFunction
00056 =H Standard output function
00057 
00058 ScriptBasic execution may have pointers to the standard input and
00059 standard output functions. The print command uses the standard
00060 output function pointer unless it is NULL. Here we implement a very
00061 simple function that can be used as standard output function when
00062 running under ISAPI. This function uses the ISAPI interface function
00063 WriteClient in a very inefficient mode sending characters by character,
00064 but the output is buffered anyway.
00065 
00066 The function has two arguments. The first is the character to send to
00067 the standard output. The second argument is the embedder pointer. This
00068 pointer in this case is the ISAPI extension control block pointer.
00069 /*FUNCTION*/
00070 static void IsapiStdOutFunction(char Character,
00071                                 LPEXTENSION_CONTROL_BLOCK lpECB
00072   ){
00073 /*noverbatim
00074 CUT*/
00075   static DWORD dwBytes = 1;
00076   lpECB->WriteClient(lpECB->ConnID,&Character,&dwBytes,HSE_IO_SYNC);
00077   }
00078 
00079 /*
00080  Configuration data is read only once, when the first basic program is executed.
00081  This makes execution faster. You have to restart the web server for any
00082  configuration change.
00083 */
00084 static pSbProgram pProgramConfig;
00085 static char *szCache;
00086 static char *szReportFile;
00087 static FILE *ReportFile;
00088 static CRITICAL_SECTION csReport;
00089 static char *szErrorMessage;
00090 
00091 static int DoMemoryCache; /* we can switch it off while developing */
00092 static CRITICAL_SECTION csSymbolTable; /* to lock the symbol table */
00093 static SymbolTable ProgramCache;
00094 static void *pCacheMemorySegment;
00095 typedef struct _CacheItem {
00096   pSbProgram pProgram;
00097   int boolValid; /* true if the code is loaded and valid */
00098   CRITICAL_SECTION csCompile;
00099   }CacheItem,*pCacheItem;
00100 
00101 static void IsapiErrorScreen(LPEXTENSION_CONTROL_BLOCK lpECB){
00102   DWORD dwBytes;
00103   static char *szDefaultErrorMessage =
00104 "</PRE></FONT>\n</BODY>\n</HTML>\n";
00105 
00106   if( szErrorMessage == NULL )szErrorMessage = szDefaultErrorMessage;
00107 
00108   dwBytes = strlen(szErrorMessage);
00109   lpECB->WriteClient(lpECB->ConnID,szErrorMessage,&dwBytes,HSE_IO_SYNC);
00110 
00111   }
00112 
00113 int GetC(void *f){ return getc((FILE *)f); }
00114 
00115 void isapi_report(void *vlpECB,
00116                   char *FileName,
00117                   long LineNumber,
00118                   unsigned int iErrorCode,
00119                   int iErrorSeverity,
00120                   int *piErrorCounter,
00121                   char *szErrorString,
00122                   unsigned long *fFlags
00123   ){
00124   char timebuf[9],datebuf[9];
00125   LPEXTENSION_CONTROL_BLOCK lpECB=vlpECB;
00126   char ErrMes[256];
00127   DWORD dwBytes;
00128   static char *szErrorHeader =
00129 "HTTP/1.0 200 OK\nContent-Type: text/html\n\n"
00130 "<HTML>\n<HEAD>\n<TITLE>ScriptBasic Program Error</TITLE>\n</HEAD>\n<BODY BGCOLOR=\"WHITE\">\n"
00131 "<FONT FACE=\"VERDANA\" SIZE=\"2\">\n"
00132 "<H1>ScriptBasic Program Error</H1>\n"
00133 "An error happened while executing the program.<P>\n<FONT SIZE=\"3\"><TT>";
00134 
00135 #define EMIT  dwBytes = strlen(ErrMes);lpECB->WriteClient(lpECB->ConnID,ErrMes,&dwBytes,HSE_IO_SYNC)
00136 
00137   if(  !((*fFlags) & REPORT_F_FRST) ){
00138     dwBytes = strlen(szErrorHeader);
00139     lpECB->WriteClient(lpECB->ConnID,szErrorHeader,&dwBytes,HSE_IO_SYNC);
00140     }
00141 
00142   if( szReportFile == NULL )return;
00143   EnterCriticalSection(&csReport);
00144   ReportFile = fopen(szReportFile,"a");
00145   if( ReportFile == NULL )
00146     LeaveCriticalSection(&csReport);
00147 
00148   _strtime( timebuf );
00149   _strdate( datebuf );
00150   if( szErrorString && strlen(szErrorString) > 80 )szErrorString[79] = (char)0;
00151 
00152   if( iErrorSeverity >= REPORT_ERROR && piErrorCounter )(*piErrorCounter)++;
00153 
00154   if( ReportFile )fprintf(ReportFile,"%s %s:",datebuf,timebuf);
00155   sprintf(ErrMes,"%s %s:",datebuf,timebuf);
00156   EMIT;
00157   if( FileName && ReportFile )fprintf(ReportFile,"%s(%ld):",FileName,LineNumber);
00158   if( FileName ){
00159     sprintf(ErrMes,"%s(%ld):",FileName,LineNumber);
00160     EMIT;
00161     }
00162   if( ReportFile )
00163     fprintf(ReportFile,(iErrorCode < MAX_ERROR_CODE ? " error &H%x:" : " error 0x%08x:"),iErrorCode);
00164   sprintf(ErrMes,(iErrorCode < MAX_ERROR_CODE ? " error &H%x:" : " error 0x%08x:"),iErrorCode);
00165   EMIT;
00166   if( iErrorCode >= MAX_ERROR_CODE )iErrorCode = COMMAND_ERROR_EXTENSION_SPECIFIC;
00167   if( szErrorString ){
00168     fprintf(ReportFile,en_error_messages[iErrorCode],szErrorString);
00169     fprintf(ReportFile,"\n");
00170     }else
00171     fprintf(ReportFile,"%s\n",en_error_messages[iErrorCode]);
00172 
00173   if( szErrorString ){
00174     sprintf(ErrMes,en_error_messages[iErrorCode],szErrorString);
00175     EMIT;
00176     sprintf(ErrMes,"<P>\n");
00177     EMIT;
00178     }else{
00179     sprintf(ErrMes,"%s<P>\n",en_error_messages[iErrorCode]);
00180     EMIT;
00181     }
00182   *fFlags |= REPORT_F_FRST;
00183   if( ReportFile ){
00184     fclose(ReportFile);
00185     LeaveCriticalSection(&csReport);
00186     }
00187   }
00188 
00189 /*POD
00190 =section HttpExtensionProc
00191 =H Major execution function
00192 
00193 This is the major execution function called whenever the extension is expected to run a
00194 BASIC program.
00195 
00196 /*FUNCTION*/
00197 DWORD WINAPI HttpExtensionProc(LPEXTENSION_CONTROL_BLOCK lpECB
00198   ){
00199 /*noverbatim
00200 CUT*/
00201   pSbProgram pProgram;
00202   unsigned long fErrorFlags;
00203   int iError,iErrorCounter;
00204   char *szInputFile;
00205   char *pszPreprocessedFileName=NULL;
00206   int binarycode;
00207 #define FULL_PATH_BUFFER_LENGTH 256
00208   pCacheItem *ppCache;
00209 
00210   lpECB->dwHttpStatusCode = 200; /* if no one else sets */
00211 
00212   /* default values for command line options */
00213   szInputFile = lpECB->lpszPathTranslated;
00214 
00215   if( DoMemoryCache ){
00216 
00217     EnterCriticalSection(&csSymbolTable);
00218     ppCache = (pCacheItem *)sym_LookupSymbol(szInputFile,
00219                                              ProgramCache,
00220                                              1,
00221                                              alloc_Alloc,
00222                                              alloc_Free,
00223                                              pCacheMemorySegment);
00224     /* if the file is not in the cache yet then allocate space for the description */
00225     if( *ppCache == NULL ){
00226         *ppCache = alloc_Alloc(sizeof(CacheItem),pCacheMemorySegment);
00227         if( *ppCache == NULL ){
00228           LeaveCriticalSection(&csSymbolTable);
00229           isapi_report(stderr,"",0,COMMAND_ERROR_MEMORY_LOW,REPORT_ERROR,&iErrorCounter,NULL,&fErrorFlags);
00230           return HSE_STATUS_SUCCESS;
00231           }
00232       (*ppCache)->pProgram = NULL;
00233       InitializeCriticalSection(&((*ppCache)->csCompile));
00234       EnterCriticalSection(&((*ppCache)->csCompile));
00235       LeaveCriticalSection(&csSymbolTable);
00236       (*ppCache)->boolValid = 0; /* no valid code is loaded up to now */
00237       pProgram = (*ppCache)->pProgram = scriba_new(malloc,free);
00238       if( pProgram == NULL ){
00239         LeaveCriticalSection(&((*ppCache)->csCompile));
00240         LeaveCriticalSection(&csSymbolTable);
00241         isapi_report(stderr,"",0,COMMAND_ERROR_MEMORY_LOW,REPORT_ERROR,&iErrorCounter,NULL,&fErrorFlags);
00242         return HSE_STATUS_SUCCESS;
00243         }
00244       scriba_SetFileName(pProgram,szInputFile);
00245       if( scriba_UseCacheFile(pProgram) == SCRIBA_ERROR_SUCCESS )binarycode = 1;
00246       if( binarycode || scriba_IsFileBinaryFormat(pProgram) ){
00247         scriba_LoadBinaryProgram(pProgram);
00248         }else{
00249         if( iError=scriba_RunExternalPreprocessor(pProgram,NULL) ){
00250           LeaveCriticalSection(&((*ppCache)->csCompile));
00251           LeaveCriticalSection(&csSymbolTable);
00252           isapi_report(stderr,"",0,iError,REPORT_ERROR,&iErrorCounter,NULL,&fErrorFlags);
00253           return HSE_STATUS_SUCCESS;
00254           }
00255         if( scriba_LoadSourceProgram(pProgram) )return HSE_STATUS_SUCCESS;
00256         scriba_SaveCacheFile(pProgram);
00257         }
00258       (*ppCache)->boolValid = 1;
00259       LeaveCriticalSection(&((*ppCache)->csCompile));
00260       }else{
00261       LeaveCriticalSection(&csSymbolTable);
00262       }
00263 
00264     /* this is a simple way to wait for the first occurence of the code to
00265        load first then we can execute simultaneous */
00266     EnterCriticalSection(&((*ppCache)->csCompile));
00267     LeaveCriticalSection(&((*ppCache)->csCompile));
00268 
00269     /* if the code could not be loaded due to syntax error we do not try again */
00270     if( ! (*ppCache)->boolValid ){
00271       isapi_report(stderr,"",0,COMMAND_ERROR_INVALID_CODE,REPORT_ERROR,&iErrorCounter,NULL,&fErrorFlags);
00272       return HSE_STATUS_SUCCESS;
00273       }
00274 
00275     pProgram = scriba_new(malloc,free);
00276     if( pProgram == NULL ){
00277       isapi_report(stderr,"",0,COMMAND_ERROR_MEMORY_LOW,REPORT_ERROR,&iErrorCounter,NULL,&fErrorFlags);
00278       return HSE_STATUS_SUCCESS;
00279       }
00280     scriba_InheritConfiguration(pProgram,pProgramConfig);
00281     scriba_InheritBinaryProgram(pProgram,(*ppCache)->pProgram);
00282     /* here we are ready to execute the code it is loaded into memory */
00283 
00284     }else{/* if we do not use memory cache */
00285 
00286     pProgram = scriba_new(malloc,free);
00287     if( pProgram == NULL ){
00288       isapi_report(stderr,"",0,COMMAND_ERROR_MEMORY_LOW,REPORT_ERROR,&iErrorCounter,NULL,&fErrorFlags);
00289       return HSE_STATUS_SUCCESS;
00290       }
00291     scriba_InheritConfiguration(pProgram,pProgramConfig);
00292     scriba_SetFileName(pProgram,szInputFile);
00293     if( scriba_UseCacheFile(pProgram) == SCRIBA_ERROR_SUCCESS )binarycode = 1;
00294     if( binarycode || scriba_IsFileBinaryFormat(pProgram) ){
00295       scriba_LoadBinaryProgram(pProgram);
00296       }else{
00297       if( iError=scriba_RunExternalPreprocessor(pProgram,NULL) ){
00298         isapi_report(stderr,"",0,iError,REPORT_ERROR,&iErrorCounter,NULL,&fErrorFlags);
00299         return HSE_STATUS_SUCCESS;
00300         }
00301       if( scriba_LoadSourceProgram(pProgram) )return HSE_STATUS_SUCCESS;
00302       scriba_SaveCacheFile(pProgram);
00303       }
00304   }
00305 
00306   scriba_Run(pProgram,NULL);
00307   scriba_destroy(pProgram);
00308 
00309   sprintf(lpECB->lpszLogData,"executed %s.",szInputFile);
00310   return HSE_STATUS_SUCCESS;
00311   }
00312 
00313 /*POD
00314 =section TerminateExtension
00315 =H Terminate the extension
00316 
00317 This function is called by the IIS before the extension is unloaded.
00318 
00319 /*FUNCTION*/
00320 BOOL WINAPI TerminateExtension(DWORD dwFlags
00321   ){
00322 /*noverbatim
00323 CUT*/
00324   char timebuf[9],datebuf[9];
00325 
00326   switch( dwFlags ){
00327     case HSE_TERM_ADVISORY_UNLOAD:
00328       if( szReportFile != NULL ){
00329         EnterCriticalSection(&csReport);
00330         ReportFile = fopen(szReportFile,"a");
00331         if( ReportFile != NULL ){
00332           _strtime( timebuf );
00333           _strdate( datebuf );
00334           fprintf(ReportFile,"%s %s: ScriptBasic ISAPI variation was unloaded upon request.\n",datebuf,timebuf);
00335           fclose(ReportFile);
00336           }
00337         LeaveCriticalSection(&csReport);
00338         }
00339       scriba_destroy(pProgramConfig);
00340       pProgramConfig = NULL;
00341       return TRUE;
00342     case HSE_TERM_MUST_UNLOAD:
00343       if( szReportFile != NULL ){
00344         EnterCriticalSection(&csReport);
00345         ReportFile = fopen(szReportFile,"a");
00346         if( ReportFile != NULL ){
00347           _strtime( timebuf );
00348           _strdate( datebuf );
00349           fprintf(ReportFile,"%s %s: ScriptBasic ISAPI variation was forcefully unloaded.\n",datebuf,timebuf);
00350           fclose(ReportFile);
00351           }
00352         LeaveCriticalSection(&csReport);
00353         }
00354       scriba_destroy(pProgramConfig);
00355       pProgramConfig = NULL;
00356       return TRUE;
00357     default:;
00358     }
00359   return 0;
00360   }
00361 
00362 /*POD
00363 =section GetExtensionVersion
00364 =H Version negotiation and startup function
00365 
00366 /*FUNCTION*/
00367 BOOL WINAPI  GetExtensionVersion(HSE_VERSION_INFO *pVer
00368   ){
00369 /*noverbatim
00370 CUT*/
00371   char *szErrorMessageFile,*s;
00372   char timebuf[9],datebuf[9];
00373 
00374   /* create the pseudo program that will hold the configuration information */
00375   pProgramConfig = scriba_new(malloc,free);
00376 
00377   /* note that there is no forced config file name that
00378      could come from a command line that we do not have */
00379   scriba_LoadConfiguration(pProgramConfig,NULL);
00380 
00381   /* Get some parameters from the config file. */
00382   szCache = cft_GetString(pProgramConfig->pCONF,"cache");
00383   szReportFile = cft_GetString(pProgramConfig->pCONF,"isapi.report");
00384 
00385   /* this lock is used to prevent two threads writing the report file at once */
00386   InitializeCriticalSection(&csReport);
00387 
00388   /* this lock is used to prevent symultaneous access to the symbol table */
00389   InitializeCriticalSection(&csSymbolTable);
00390 
00391   /* get the error message text that is sent to the user screen when an error happens */
00392   szErrorMessageFile = cft_GetString(pProgramConfig->pCONF,"isapi.errormessage");
00393 
00394   /* write the start message into the report file */
00395   if( szReportFile != NULL ){
00396     EnterCriticalSection(&csReport);
00397     ReportFile = fopen(szReportFile,"a");
00398     if( ReportFile != NULL ){
00399       _strtime( timebuf );
00400       _strdate( datebuf );
00401       fprintf(ReportFile,"%s %s: ScriptBasic ISAPI variation was loaded.\n",datebuf,timebuf);
00402       fclose(ReportFile);
00403       }
00404     LeaveCriticalSection(&csReport);
00405     }
00406 
00407   /* This variation caches programs in memory, and we should have
00408      a symbol table that tells us where the collected code is.
00409   */
00410 
00411   s = cft_GetString(pProgramConfig->pCONF,"isapi.memcache");
00412   if( s && !strcmp(s,"yes") ){
00413     pCacheMemorySegment = alloc_InitSegment(malloc,free);
00414     if( pCacheMemorySegment == NULL )return FALSE;
00415     ProgramCache = sym_NewSymbolTable(alloc_Alloc,pCacheMemorySegment);
00416     if( ProgramCache == NULL )return FALSE;
00417     DoMemoryCache = 1;
00418     }else{
00419     DoMemoryCache = 0;
00420     pCacheMemorySegment = NULL;
00421     ProgramCache = NULL;
00422     }
00423 
00424   pVer->dwExtensionVersion = HSE_VERSION;
00425   return TRUE;
00426   }

Generated on Sun Mar 12 23:56:32 2006 for ScriptBasic by  doxygen 1.4.6-NO