G:/ScriptBasic/source/variations/httpd/websrv.c

Go to the documentation of this file.
00001 #include <string.h>
00002 #include <stdlib.h>
00003 #include <stdio.h>
00004 #ifdef WIN32
00005 #include <process.h>
00006 #include <winsock2.h>
00007 #include <winbase.h>
00008 #include <tlhelp32.h>
00009 
00010 #include "service.h"
00011 
00012 VOID CmdInstallService();
00013 VOID CmdRemoveService();
00014 void WINAPI service_main(DWORD dwArgc, LPTSTR *lpszArgv);
00015 
00016 #else
00017 #include <sys/time.h>
00018 #include <sys/types.h>
00019 #include <netinet/in.h>
00020 #include <netdb.h>
00021 #include <unistd.h>
00022 #include <signal.h>
00023 #include <sys/wait.h>
00024 #endif
00025 
00026 #include "../../thread.h"
00027 #include "../../filesys.h"
00028 #include "../../httpd.h"
00029 #include "../../logger.h"
00030 #include "../../scriba.h"
00031 
00032 #if WIN32
00033 /* This function decides if the actual process was started as a service. This is a not so sure, but
00034    much faster way than calling the service dispatcher function */
00035 static BOOL AmIService(void){
00036   DWORD dwMyPid,dwParentPid;
00037   PROCESSENTRY32 pe;
00038   HANDLE         th;
00039 
00040   /* get the current process pid */
00041   dwMyPid = GetCurrentProcessId();
00042   th = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
00043   if( INVALID_HANDLE_VALUE == th )return FALSE;
00044   /* Count the processes to allocate the appropriate size array */
00045   pe.dwSize = sizeof(PROCESSENTRY32);
00046 
00047   if( ! Process32First(th,&pe) )return FALSE;
00048 
00049   /* get the parent process pid */
00050   while( pe.th32ProcessID != dwMyPid ){
00051     pe.dwSize = sizeof(PROCESSENTRY32);
00052     if( ! Process32Next(th,&pe) )break;
00053     }
00054   if( pe.th32ProcessID == dwMyPid ){
00055     dwParentPid = pe.th32ParentProcessID;
00056     }else{
00057     return FALSE;
00058     }
00059 
00060   if( ! Process32First(th,&pe) ){// that could be weird not to have any process running
00061     return FALSE;
00062     }
00063 
00064   /* get the parent process parameters */
00065   while( pe.th32ProcessID != dwParentPid ){
00066     pe.dwSize = sizeof(PROCESSENTRY32);
00067     if( ! Process32Next(th,&pe) )break;
00068     }
00069   if( pe.th32ProcessID == dwParentPid ){
00070     // if the parent process exe is named SERVICES.EXE then this is a service
00071     if( 0 == strnicmp("SERVICES",pe.szExeFile,8) )return TRUE;
00072     return FALSE;
00073     }else{
00074     return FALSE;
00075     }
00076   }
00077 #endif
00078 
00079 #define FULL_PATH_BUFFER_LENGTH 256
00080 #define INBLEN 10 /* Input Buffer Length */
00081 /*
00082 
00083   Global data for all threads.
00084 
00085 */
00086 typedef struct _WebData {
00087   pSbProgram pProgramConfig;
00088   char *pszHome;
00089   char szPort[10];
00090   int XForwarded; /* set this falg TRUE in config in case the engine is used behind an Apache
00091                      That means that the client IP is NOT the client IP (aka the server where
00092                      Apache is running) but the client Apache passes in the X-Forwarded-For header.
00093 
00094                      The program reading the configuration file will set this variable according
00095                      to the configuration key 'servers.proxyip'
00096                      */
00097    /*
00098    These are asynchronous and synchronous log handlers. The log handling is implemented in the
00099    file logger.c
00100 
00101    HitLog logs all hits
00102    StatLog logs all application performance statistical data (NOT ad statistics)
00103    AppLog logs all important application actions
00104    ErrLog logs errors
00105    PanicLog is an asynchronous error log and is used to log serious errors when the error
00106             prohibits the usage of the ErrLog
00107 
00108    also see panic.txt in the cwd of the process as a last resort of reporting error
00109    (note that cwd for WNT services is supposed to be WNT\System32)
00110    */
00111   tLogger HitLog,StatLog,AppLog,ErrLog,PanicLog;
00112   /*
00113    This program does not start if any of the log files can not be opened properly or
00114    not configured properly. This is to ensure that if the program starts all error
00115    conditions are logged fine. Some installation may want to run without any log.
00116    In that case the application SHOULD configure "http.nolog" to be true.
00117    */
00118   int nolog;
00119   /*
00120    This fields may point to the message that the server sends on a page not found error.
00121   */
00122   char *msg404;
00123   /*
00124    This is the error code and error text that the server sends when a page is not found.
00125    This is the text that is after the HTTP/1.0 and before the new line.
00126    */
00127   char *code404;
00128   /*
00129    This is the BASIC program to execute when a page is not found. If this is not NULL the
00130    code404 and msg404 fields are ignored.
00131    */
00132   char *run404;
00133 
00134   /* Number of virtual directory definitions */
00135   unsigned long cVdir;
00136 
00137   /* Virtual directory defintions. */
00138   char **ppszVdir;
00139 
00140   /* the pid file */
00141   char *pszPid;
00142 
00143   /* number of seconds to sleep between examining the pid file if that still exists */
00144   unsigned long lWaitLoop;
00145 
00146   /* where to send error messages bit0 client bit1 errlog */
00147 #define ERRMSGCLIENT 0x01
00148 #define ERRMSGERRLOG 0x02
00149   unsigned long bErrMsgDest;
00150 
00151   pHttpdThread pHT;
00152   } WebData, *pWebData;
00153 
00154 /*
00155    Separate data for the individual threads.
00156 */
00157 typedef struct _ApplicationThreadData {
00158   char *pszPathTranslated;
00159   char *pszClientIP;
00160   char *pszRemoteUser;
00161   char *pszPassword;
00162 #define OBLEN 20
00163 #define ENVLEN 256 /* the maximal length of an environment variable together with the key and the = sign*/
00164   unsigned char szBuffer[OBLEN];
00165   unsigned char szEnvBuf[ENVLEN];
00166   unsigned char cbBuffer;
00167   unsigned char szInBuffer[INBLEN];
00168   unsigned long cbInBuffer;
00169   unsigned char *pszInBuffer;
00170   char *pszFtpCommand; /* the actual command including the line terminating \r\n */
00171   char szThreadIndex[20]; /* the thread index decimal */
00172   int FirstHeaderLine;
00173   }ApplicationThreadData, *pApplicationThreadData;
00174 
00175 #ifdef WIN32
00176 static pHttpdThread pHT_Service;
00177 #endif
00178 
00179 static char six2pr[64] = {
00180     'A','B','C','D','E','F','G','H','I','J','K','L','M',
00181     'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
00182     'a','b','c','d','e','f','g','h','i','j','k','l','m',
00183     'n','o','p','q','r','s','t','u','v','w','x','y','z',
00184     '0','1','2','3','4','5','6','7','8','9','+','/'
00185 };
00186 static unsigned char pr2six[256];
00187 static int uudecode(char *bufcoded,
00188                     unsigned char *bufplain,
00189                     int outbufsize){
00190 /* single character decode */
00191 #define DEC(c) pr2six[(int)c]
00192 #define MAXVAL 63
00193 
00194   static int first = 1;
00195   char a[4];
00196   int j;
00197   char *bufin = bufcoded;
00198   unsigned char *bufout = bufplain;
00199 
00200   /* If this is the first call, initialize the mapping table.
00201    * This code should work even on non-ASCII machines.   */
00202   if(first) {
00203     first = 0;
00204     for(j=0; j<256; j++) pr2six[j] = MAXVAL+1;
00205     for(j=0; j<64; j++) pr2six[(int)six2pr[j]] = (unsigned char) j;
00206     }
00207 
00208   bufin = bufcoded;
00209    
00210   while( *bufin && outbufsize ){
00211     for( j = 0 ; j < 4 ; j++ )
00212       if( *bufin && pr2six[*bufin] <= MAXVAL )a[j] = *bufin++; else a[j] = 'A';
00213     *(bufout++) = (unsigned char) (DEC(*a) << 2 | DEC(a[1]) >> 4);
00214     outbufsize--;
00215     if( outbufsize < 2 ) break;
00216     *(bufout++) = (unsigned char) (DEC(a[1]) << 4 | DEC(a[2]) >> 2);
00217     outbufsize--;
00218     if( outbufsize < 2) break;
00219     *(bufout++) = (unsigned char) (DEC(a[2]) << 6 | DEC(a[3]));
00220     outbufsize--;
00221     if( outbufsize < 2) break;
00222     }
00223 
00224   *bufout = (char)0;
00225    
00226   return 0;
00227 }
00228 
00229 /* decide if p is prefix string of t
00230    if not return NULL
00231    if yes return the replace string
00232 
00233    zchar and : terminates the prefix string
00234 
00235    This function is used to search the virtual directories.
00236 */
00237 static char *prefix(char *t, char *p){
00238 
00239   if( t == NULL )return NULL;
00240   if( p == NULL )return NULL;
00241   while( *t && *p && *p != ':' ){
00242     if( *p != *t )return NULL;
00243     p++;
00244     t++;
00245     }
00246   if( ! *p )return NULL; 
00247   if( *p == ':' )return ++p;
00248   return NULL;
00249   }
00250 
00251 /*
00252  *  Convert a xxx.xxx.xxx.xxx/yyy.yyy.yyy.yyy IP/MASK string into two unsigned
00253  *  long values. Return zero on success and 1 on failure.
00254  */
00255 static int maskip(char *s, unsigned long *ip, unsigned long *mask){
00256   int i;
00257   int digit;
00258 
00259   *ip = 0;
00260   for( i = 0 ; i < 4 ; i++ ){
00261     digit = 0;
00262     while( isdigit( *s ) ){
00263       digit = 10*digit + *s++ -'0';
00264       }
00265     if( digit > 255 || (*s != '.' && *s != '/' ) )return 1;
00266     if( *s == '.' )s++;
00267     *ip = 256* *ip + digit;
00268     }
00269 
00270   if( *s != '/' )return 1;
00271   s++;
00272   *mask = 0;
00273   for( i = 0 ; i < 4 ; i++ ){
00274     digit = 0;
00275     while( isdigit( *s ) ){
00276       digit = 10*digit + *s++ -'0';
00277       }
00278     if( digit > 255 || (*s != '.' && *s != (char)0 ) )return 1;
00279     if( *s == '.' )s++;
00280     *mask = 256* *mask + digit;
00281     }
00282   return 0;
00283   }
00284 
00285 
00286 static void httpd_report(void *pEmbedPointer,
00287                          char *FileName,
00288                          long LineNumber,
00289                          unsigned int iErrorCode,
00290                          int iErrorSeverity,
00291                          int *piErrorCounter,
00292                          char *szErrorString,
00293                          unsigned long *fFlags
00294   ){
00295   pThreadData pT = pEmbedPointer;
00296   pHttpdThread pHT = pT->pThreadLocalData;
00297   pWebData pWD = pHT->AppData;
00298   char buf[256],*s;
00299 
00300   if( iErrorSeverity >= REPORT_ERROR && piErrorCounter )(*piErrorCounter)++;
00301 
00302   if( pWD->bErrMsgDest & ERRMSGCLIENT ){
00303     if( !((*fFlags) & REPORT_F_FRST) ){
00304       WriteClientText("HTTP/1.0 200 OK\nContent-Type: text/html\n\n"
00305                                   "<HTML><HEAD>\n"
00306                                   "<title>Error page, syntax error</title>\n"
00307                                   "</HEAD><BODY>\n"
00308                                   "<H1>Error has happened in the code</H1>"
00309                                   "<pre>\n");
00310       }
00311     if( szErrorString && strlen(szErrorString) > 80 )szErrorString[79] = (char)0;
00312     if( FileName ){
00313       sprintf(buf,"%s(%ld):",FileName,LineNumber);
00314       WriteClientText(buf);
00315       }
00316     sprintf(buf,(iErrorCode < MAX_ERROR_CODE ? " error &H%x:" : " error 0x%08x:"),iErrorCode);
00317     WriteClientText(buf);
00318     if( iErrorCode >= MAX_ERROR_CODE )iErrorCode = COMMAND_ERROR_EXTENSION_SPECIFIC;
00319     if( szErrorString ){
00320       sprintf(buf,en_error_messages[iErrorCode],szErrorString);
00321       WriteClientText(buf);
00322       WriteClientText("\n");
00323       }else{
00324       sprintf(buf,"%s\n",en_error_messages[iErrorCode]);
00325       WriteClientText(buf);
00326       }
00327     }
00328   if( pWD->bErrMsgDest & ERRMSGERRLOG ){
00329     if( szErrorString && strlen(szErrorString) > 80 )szErrorString[79] = (char)0;
00330     s = buf;
00331     if( FileName ){
00332       sprintf(s,"%s(%ld):",FileName,LineNumber);
00333       s += strlen(s);
00334       }
00335     sprintf(s,(iErrorCode < MAX_ERROR_CODE ? " error &H%x:" : " error 0x%08x:"),iErrorCode);
00336     s += strlen(s);
00337     if( szErrorString ){
00338       sprintf(s,en_error_messages[iErrorCode],szErrorString);
00339       }else{
00340       sprintf(s,"%s",en_error_messages[iErrorCode]);
00341       }
00342     s = buf;
00343     while( *s ){
00344       if( *s == '\n' )*s = ' ';
00345       s++;
00346       }
00347     log_printf(&(pWD->ErrLog),"%s",buf);
00348     }
00349 
00350   *fFlags |= REPORT_F_FRST;
00351   }
00352 
00353 static void ftp_report(void *pEmbedPointer,
00354                        char *FileName,
00355                        long LineNumber,
00356                        unsigned int iErrorCode,
00357                        int iErrorSeverity,
00358                        int *piErrorCounter,
00359                        char *szErrorString,
00360                        unsigned long *fFlags
00361   ){
00362   pThreadData pT = pEmbedPointer;
00363   pHttpdThread pHT = pT->pThreadLocalData;
00364   pWebData pWD = pHT->AppData;
00365   char buf[256],*s;
00366 
00367   if( iErrorSeverity >= REPORT_ERROR && piErrorCounter )(*piErrorCounter)++;
00368 
00369   if( pWD->bErrMsgDest & ERRMSGCLIENT ){
00370     if( !((*fFlags) & REPORT_F_FRST) ){
00371       WriteClientText("421 Service not available, closing control connection.\r\n");
00372       }
00373     }
00374 
00375   if( pWD->bErrMsgDest & ERRMSGERRLOG ){
00376     if( szErrorString && strlen(szErrorString) > 80 )szErrorString[79] = (char)0;
00377     s = buf;
00378     if( FileName ){
00379       sprintf(s,"%s(%ld):",FileName,LineNumber);
00380       s += strlen(s);
00381       }
00382     sprintf(s,(iErrorCode < MAX_ERROR_CODE ? " error &H%x:" : " error 0x%08x:"),iErrorCode);
00383     s += strlen(s);
00384     if( szErrorString ){
00385       sprintf(s,en_error_messages[iErrorCode],szErrorString);
00386       }else{
00387       sprintf(s,"%s",en_error_messages[iErrorCode]);
00388       }
00389     s = buf;
00390     while( *s ){
00391       if( *s == '\n' )*s = ' ';
00392       s++;
00393       }
00394     log_printf(&(pWD->ErrLog),"%s",buf);
00395     }
00396 
00397   *fFlags |= REPORT_F_FRST;
00398   }
00399 
00400 #define CONFIG(X) cft_GetString(pWD->pProgramConfig->pCONF,(X))
00401 
00402 int AppInit(int argc,char *argv[],pHttpdThread pHT,void **AppData){
00403   pWebData pWD;
00404   long myV,i;
00405   CFT_NODE ClientRootNode,ServerRootNode,ServerStartNode,Node;
00406   char *s;
00407   void *pM_Log;
00408   FILE *fpanic;
00409   int iError;
00410 
00411   iError = 0;/* No error happened so far. When an error happens this variable is set to 1.
00412                 When the function returns the value of this variable is returned indicating
00413                 error or success. When an error occures we work on to recognize further possible
00414                 errors in the log file and report it into the panic log.                          */
00415 
00416   pWD = malloc(sizeof(WebData));
00417   if( pWD == NULL )return 1;
00418 
00419   pWD->pHT = pHT;
00420 
00421   *AppData = pWD;
00422 
00423   /* default server values */
00424   pWD->XForwarded = 0;
00425   pWD->nolog = 0;
00426 
00427   /* create the pseudo program that will hold the configuration information */
00428   pWD->pProgramConfig = scriba_new(malloc,free);
00429   if( pWD->pProgramConfig == NULL ) return 2;
00430 
00431   if( scriba_LoadConfiguration(pWD->pProgramConfig,NULL) ){
00432      fprintf(stderr,"Can not initialize the configuration management system.\n");
00433      fprintf(stderr,"The expected configuration file \"%s\" can not be read.\n",pWD->pProgramConfig->pCONF->pszConfigFileName);
00434      fpanic = fopen("panic.txt","w");
00435      if( fpanic ){
00436        fprintf(fpanic,"Can not initialize the configuration management system.\n");
00437        fprintf(fpanic,"The expected configuration file \"%s\" can not be read.\n",pWD->pProgramConfig->pCONF->pszConfigFileName);
00438        fclose(fpanic);
00439        }
00440      return 1;
00441      }
00442 
00443   scriba_InitModuleInterface(pWD->pProgramConfig);
00444 
00445   /* the first server is configured by default. The rest has to be configured. */
00446   for( i= 1 ; i < MAX_SERVERS ; i++ ){
00447     pHT->server[i].ip = HTTPD_IP;   /* IP is configured by default */
00448     pHT->server[i].port = 0;        /* no port is configured by default */
00449     pHT->server[i].type = SERVER_NONE;
00450     }
00451   /* you have to explicitely configure the server not to log. Otherwise the server will not
00452      start if it can not open the vital log files for security reasons. */
00453   if( ! cft_GetEx(pWD->pProgramConfig->pCONF,"servers.nolog",NULL,NULL,&myV,NULL,NULL) )
00454     pWD->nolog = myV;
00455 
00456   pWD->bErrMsgDest = 2;
00457   if( ! cft_GetEx(pWD->pProgramConfig->pCONF,"servers.errmsgdest",NULL,NULL,&myV,NULL,NULL) )
00458     pWD->bErrMsgDest = myV;
00459 
00460   if( pWD->nolog ){
00461     log_init(&(pWD->PanicLog),NULL,NULL,NULL,NULL,LOGTYPE_SYNCHRONOUS);
00462     log_init(&(pWD->AppLog),NULL,NULL,NULL,NULL,LOGTYPE_SYNCHRONOUS);
00463     }else{
00464     /* if we have config then open the panic log as soon as possible so we can report further
00465        configuration errors to the panic log. The panic log is a synchronous log, therefore we can
00466        open it in AppInit before the main thread performs fork under UNIX. Asynchronous logs can
00467        only be started in AppStart that is called after forking into background. */
00468     pM_Log = alloc_InitSegment(malloc,free);
00469     if( pM_Log == NULL ){
00470       fprintf(stderr,"Low memory allocating segment for panic logging.\n");
00471       fpanic = fopen("panic.txt","w");
00472        if( fpanic ){
00473          fprintf(fpanic,"Low memory allocating segment for panic logging.\n");
00474          fclose(fpanic);
00475          }
00476       return 1;
00477       }
00478 
00479     if( (s = CONFIG("servers.log.panic.file")) == NULL ||
00480         log_init(&(pWD->PanicLog),
00481                  alloc_Alloc,
00482                  alloc_Free,
00483                  pM_Log,
00484                  s,
00485                  LOGTYPE_SYNCHRONOUS) ){
00486       fprintf(stderr,"Can not open panic log \"%s\".\n",s);
00487       fpanic = fopen("panic.txt","w");
00488       if( fpanic ){
00489         fprintf(fpanic,"Can not open panic log \"%s\".\n",s);
00490         fclose(fpanic);
00491         }
00492       return 1;
00493       }
00494 
00495     /* open the application log in synchronous mode and close it afterwards to
00496        reopen it in asynchronous mode */
00497     if( (s = CONFIG("servers.log.app.file")) == NULL ||
00498         log_init(&(pWD->AppLog),
00499                  alloc_Alloc,
00500                  alloc_Free,
00501                  pM_Log,
00502                  s,
00503                  LOGTYPE_SYNCHRONOUS) ){
00504       log_printf(&(pWD->PanicLog),
00505                  "Can not open the application log >>%s<<",
00506                  CONFIG("servers.log.app.file"));
00507       iError = 1;
00508       }
00509 
00510     log_printf(&(pWD->AppLog),"Eszter SB Application Engine start up initiated.");
00511     }
00512 
00513   if( ! cft_GetEx(pWD->pProgramConfig->pCONF,"servers.port",NULL,NULL,&myV,NULL,NULL) )
00514     pHT->server[0].port = (port_t)myV;
00515 
00516   /* get the ip address that we have to bind the IP address on */
00517   if( s = CONFIG("servers.ip") )
00518     pHT->server[0].ip = inet_addr(s);
00519 
00520   sprintf(pWD->szPort,"%d",pHT->server[0].port);
00521   log_printf(&(pWD->AppLog),"Listening on port %d",pHT->server[0].port);
00522 
00523   if( ! cft_GetEx(pWD->pProgramConfig->pCONF,"servers.threads",NULL,NULL,&myV,NULL,NULL) )
00524     pHT->threadmax = myV;
00525   log_printf(&(pWD->AppLog),"Maximum number of serving threads: %d",pHT->threadmax);
00526 
00527   if( ! cft_GetEx(pWD->pProgramConfig->pCONF,"servers.proxyip",NULL,NULL,&myV,NULL,NULL) )
00528     pWD->XForwarded = myV;
00529   log_printf(&(pWD->AppLog), pWD->XForwarded 
00530                                   ? "Using Apache X-Forwarded-For header to determine client IP"
00531                                   : "Using TCP/IP reported IP to determine client IP" );
00532 
00533   if( ! cft_GetEx(pWD->pProgramConfig->pCONF,"servers.listenbacklog",NULL,NULL,&myV,NULL,NULL) )
00534     pHT->listenmax = myV;
00535   log_printf(&(pWD->AppLog),"Listen backlog is %d",pHT->listenmax);
00536 
00537   pWD->pszHome = CONFIG("servers.home");
00538   if( pWD->pszHome == NULL )pWD->pszHome = "./";
00539   log_printf(&(pWD->AppLog),"http home directory is %s",pWD->pszHome);
00540 
00541   pWD->code404 = CONFIG("servers.code404");
00542   if( pWD->code404 )
00543     log_printf(&(pWD->AppLog),"Page not found error code is %s",pWD->code404);
00544 
00545   pWD->msg404 = CONFIG("servers.msg404");
00546   log_printf(&(pWD->AppLog), pWD->msg404 
00547                             ? "404 error page text is defined." 
00548                             : "404 error page text is default.");
00549 
00550   pWD->run404 = CONFIG("servers.run404");
00551   if( pWD->run404 && strlen(pWD->run404) > FULL_PATH_BUFFER_LENGTH ){
00552     log_printf(&(pWD->PanicLog),"run404 file name is too long, ignored.");
00553     pWD->run404 = NULL;
00554     }
00555   log_printf(&(pWD->AppLog), pWD->run404 
00556                             ? "404 error program is %s" 
00557                             : "no 404 error program defined",pWD->run404);
00558 
00559   pHT->lWaitSec = 10;
00560   if( ! cft_GetEx(pWD->pProgramConfig->pCONF,"servers.pid.wait.period",NULL,NULL,&myV,NULL,NULL) )
00561     pHT->lWaitSec = myV;
00562 
00563   pHT->lWaitCount = 2;
00564   if( ! cft_GetEx(pWD->pProgramConfig->pCONF,"servers.pid.wait.length",NULL,NULL,&myV,NULL,NULL) )
00565     pHT->lWaitCount = myV;
00566 
00567   /* count the servers configured */
00568   ServerRootNode = cft_FindNode(pWD->pProgramConfig->pCONF,CFT_ROOT_NODE,"servers");
00569   ServerRootNode = cft_EnumFirst(pWD->pProgramConfig->pCONF,ServerRootNode);
00570   pHT->c_servers = 0;
00571   for( ;  ServerRootNode ; ServerRootNode = cft_EnumNext(pWD->pProgramConfig->pCONF,ServerRootNode) ){
00572     s = cft_GetKey(pWD->pProgramConfig->pCONF,ServerRootNode);
00573     if( ! strcmp(s,"server") )
00574       pHT->c_servers++;
00575     }
00576   if( pHT->c_servers >= MAX_SERVERS ){
00577     log_printf(&(pWD->ErrLog),"There are %d servers configured. Max %d are allowed.",pHT->c_servers,MAX_SERVERS);
00578     return 1;
00579     }
00580   log_printf(&(pWD->AppLog),"There are %d server(s) configured",pHT->c_servers);
00581   ServerRootNode = cft_FindNode(pWD->pProgramConfig->pCONF,CFT_ROOT_NODE,"servers");
00582   ServerRootNode = cft_EnumFirst(pWD->pProgramConfig->pCONF,ServerRootNode);
00583   i = 0;
00584   for(  ;  ServerRootNode ; ServerRootNode = cft_EnumNext(pWD->pProgramConfig->pCONF,ServerRootNode) ){
00585     s = cft_GetKey(pWD->pProgramConfig->pCONF,ServerRootNode);
00586     if( ! strcmp(s,"server") ){
00587 
00588       ServerStartNode = cft_EnumFirst(pWD->pProgramConfig->pCONF,ServerRootNode);
00589 
00590       Node = cft_FindNode(pWD->pProgramConfig->pCONF,ServerStartNode,"port");
00591       if( ! cft_GetEx(pWD->pProgramConfig->pCONF,NULL,&Node,NULL,&myV,NULL,NULL) )
00592         pHT->server[i].port = (port_t)myV;
00593 
00594       Node = cft_FindNode(pWD->pProgramConfig->pCONF,ServerStartNode,"ip");
00595       if( ! cft_GetEx(pWD->pProgramConfig->pCONF,NULL,&Node,&s,NULL,NULL,NULL) )
00596         pHT->server[i].ip = inet_addr(s);
00597 
00598       Node = cft_FindNode(pWD->pProgramConfig->pCONF,ServerStartNode,"protocol");
00599       if( ! cft_GetEx(pWD->pProgramConfig->pCONF,NULL,&Node,&s,NULL,NULL,NULL) ){
00600         if( ! stricmp(s,"http") )
00601           pHT->server[i].type = SERVER_HTTP;
00602         if( ! stricmp(s,"ftp") )
00603           pHT->server[i].type = SERVER_FTP;
00604         }else
00605           pHT->server[i].type = SERVER_HTTP;
00606 
00607       Node = cft_FindNode(pWD->pProgramConfig->pCONF,ServerStartNode,"salute");
00608       if( ! cft_GetEx(pWD->pProgramConfig->pCONF,NULL,&Node,&s,NULL,NULL,NULL) )
00609         pHT->server[i].salute = s;
00610       else
00611         pHT->server[i].salute = "220 Eszter SB application Engine";
00612 
00613       Node = cft_FindNode(pWD->pProgramConfig->pCONF,ServerStartNode,"codebase");
00614       if( ! cft_GetEx(pWD->pProgramConfig->pCONF,NULL,&Node,&s,NULL,NULL,NULL) )
00615         pHT->server[i].codebase = s;
00616       else
00617         pHT->server[i].codebase = NULL;
00618 
00619 #define GET_FTP_PARAMETER(X)  Node = cft_FindNode(pWD->pProgramConfig->pCONF,ServerStartNode,"programs." #X);\
00620                               if( ! cft_GetEx(pWD->pProgramConfig->pCONF,NULL,&Node,&s,NULL,NULL,NULL) ){\
00621                                 pHT->server[i].X = s;\
00622                                 }else pHT->server[i].X = NULL;
00623       if( SERVER_FTP == pHT->server[i].type ){
00624         GET_FTP_PARAMETER(USER)
00625         GET_FTP_PARAMETER(PASS)
00626         GET_FTP_PARAMETER(ACCT)
00627         GET_FTP_PARAMETER(CWD)
00628         GET_FTP_PARAMETER(CDUP)
00629         GET_FTP_PARAMETER(SMNT)
00630         GET_FTP_PARAMETER(REIN)
00631         GET_FTP_PARAMETER(QUIT)
00632         GET_FTP_PARAMETER(PORT)
00633         GET_FTP_PARAMETER(PASV)
00634         GET_FTP_PARAMETER(TYPE)
00635         GET_FTP_PARAMETER(STRU)
00636         GET_FTP_PARAMETER(MODE)
00637         GET_FTP_PARAMETER(RETR)
00638         GET_FTP_PARAMETER(STOR)
00639         GET_FTP_PARAMETER(STOU)
00640         GET_FTP_PARAMETER(APPE)
00641         GET_FTP_PARAMETER(ALLO)
00642         GET_FTP_PARAMETER(REST)
00643         GET_FTP_PARAMETER(RNFR)
00644         GET_FTP_PARAMETER(RNTO)
00645         GET_FTP_PARAMETER(ABOR)
00646         GET_FTP_PARAMETER(DELE)
00647         GET_FTP_PARAMETER(MKD)
00648         GET_FTP_PARAMETER(PWD)
00649         GET_FTP_PARAMETER(LIST)
00650         GET_FTP_PARAMETER(NLST)
00651         GET_FTP_PARAMETER(SITE)
00652         GET_FTP_PARAMETER(SYST)
00653         GET_FTP_PARAMETER(STAT)
00654         GET_FTP_PARAMETER(HELP)
00655         GET_FTP_PARAMETER(NOOP)
00656 
00657         }
00658 
00659       ClientRootNode = cft_FindNode(pWD->pProgramConfig->pCONF,cft_EnumFirst(pWD->pProgramConfig->pCONF,ServerRootNode),"client");
00660       ClientRootNode = cft_EnumFirst(pWD->pProgramConfig->pCONF,ClientRootNode);
00661       pHT->server[i].cAllowed = 0;
00662       pHT->server[i].cDenied  = 0;
00663       for( ; ClientRootNode ; ClientRootNode = cft_EnumNext(pWD->pProgramConfig->pCONF,ClientRootNode) ){
00664         s = cft_GetKey(pWD->pProgramConfig->pCONF,ClientRootNode);
00665         if( ! strcmp(s,"allowed") )
00666           pHT->server[i].cAllowed++;
00667         else
00668         if( ! strcmp(s,"denied") )
00669           pHT->server[i].cDenied++;
00670         }
00671 
00672       log_printf(&(pWD->AppLog),
00673                  "Allowed %d Denied %d IP/MASK pairs configured for server %d",
00674                  pHT->server[i].cAllowed,pHT->server[i].cDenied,i+1);
00675 
00676       if( pHT->server[i].cAllowed ){
00677         pHT->server[i].plAllowedIP = (unsigned long *)alloc_Alloc(pHT->server[i].cAllowed *  sizeof(unsigned long),pWD->pProgramConfig->pMEM);
00678         if( pHT->server[i].plAllowedIP == NULL ){
00679           log_printf(&(pWD->PanicLog),"Memory allocation error 0001");
00680           return 1;
00681           }
00682         pHT->server[i].plAllowedMask = (unsigned long *)alloc_Alloc(pHT->server[i].cAllowed *  sizeof(unsigned long),pWD->pProgramConfig->pMEM);
00683         if( pHT->server[i].plAllowedMask == NULL ){
00684           log_printf(&(pWD->PanicLog),"Memory allocation error 0002");
00685           return 1;
00686           }
00687         }
00688 
00689       if( pHT->server[i].cDenied ){
00690         pHT->server[i].plDeniedIP = (unsigned long *)alloc_Alloc(pHT->server[i].cDenied *  sizeof(unsigned long),pWD->pProgramConfig->pMEM);
00691         if( pHT->server[i].plDeniedIP == NULL ){
00692           log_printf(&(pWD->PanicLog),"Memory allocation error 0003");
00693           return 1;
00694           }
00695         pHT->server[i].plDeniedMask = (unsigned long *)alloc_Alloc(pHT->server[i].cDenied *  sizeof(unsigned long),pWD->pProgramConfig->pMEM);
00696         if( pHT->server[i].plDeniedMask == NULL ){
00697           log_printf(&(pWD->PanicLog),"Memory allocation error 0004");
00698           return 1;
00699           }
00700         }
00701       pHT->server[i].cAllowed = 0;
00702       pHT->server[i].cDenied  = 0;
00703       ClientRootNode = cft_FindNode(pWD->pProgramConfig->pCONF,cft_EnumFirst(pWD->pProgramConfig->pCONF,ServerRootNode),"client");
00704       ClientRootNode = cft_EnumFirst(pWD->pProgramConfig->pCONF,ClientRootNode);
00705       for( ; ClientRootNode ; ClientRootNode = cft_EnumNext(pWD->pProgramConfig->pCONF,ClientRootNode) ){
00706         if( ! strcmp(cft_GetKey(pWD->pProgramConfig->pCONF,ClientRootNode),"allowed") ){
00707           if( cft_GetEx(pWD->pProgramConfig->pCONF,NULL,&ClientRootNode,&s,NULL,NULL,NULL) ){
00708             log_printf(&(pWD->PanicLog),
00709                       "cgt_GetEx( ..., %s, ... ) retuned error second time. This is an internal error.");
00710             fprintf(stderr,
00711                     "cgt_GetEx( ..., %s, ... ) retuned error second time. This is an internal error.");
00712             return 1;/* this is serious return immediately */
00713             }
00714           if( maskip(s,pHT->server[i].plAllowedIP+pHT->server[i].cAllowed,pHT->server[i].plAllowedMask+pHT->server[i].cAllowed) ){
00715             log_printf(&(pWD->PanicLog),"Invalid allowed ip/mask syntax: %s",s);
00716             iError = 1;
00717             }
00718           pHT->server[i].cAllowed++;
00719           }else
00720         if( ! strcmp(cft_GetKey(pWD->pProgramConfig->pCONF,ClientRootNode),"denied") ){
00721           if( cft_GetEx(pWD->pProgramConfig->pCONF,NULL,&ClientRootNode,&s,NULL,NULL,NULL) ){
00722             log_printf(&(pWD->PanicLog),
00723                       "cgt_GetEx( ..., %s, ... ) retuned error second time. This is an internal error.");
00724             fprintf(stderr,
00725                     "cgt_GetEx( ..., %s, ... ) retuned error second time. This is an internal error.");
00726             return 1;/* this is serious return immediately */
00727             }
00728           if( maskip(s,pHT->server[i].plDeniedIP+pHT->server[i].cDenied,pHT->server[i].plDeniedMask+pHT->server[i].cDenied) ){
00729             log_printf(&(pWD->PanicLog),"Invalid denied ip/mask syntax: %s",s);
00730             iError = 1;
00731             }
00732           pHT->server[i].cDenied++;
00733           }
00734         }
00735       i++;
00736       }
00737     }
00738 
00739   /* Count the virtual directories. */
00740   ClientRootNode = cft_FindNode(pWD->pProgramConfig->pCONF,CFT_ROOT_NODE,"servers.vdirs");
00741   ClientRootNode = cft_EnumFirst(pWD->pProgramConfig->pCONF,ClientRootNode);
00742   pWD->cVdir = 0;
00743   for( Node = ClientRootNode ;  Node ; Node = cft_EnumNext(pWD->pProgramConfig->pCONF,Node) ){
00744     s = cft_GetKey(pWD->pProgramConfig->pCONF,Node);
00745     if( ! strcmp(s,"dir") )
00746       pWD->cVdir++;
00747     }
00748   if( pWD->cVdir ){
00749     pWD->ppszVdir = (char **)alloc_Alloc(pWD->cVdir*sizeof(char *),pWD->pProgramConfig->pMEM);
00750     if( pWD->ppszVdir == NULL ){
00751       log_printf(&(pWD->PanicLog),"Memory allocation error 0005");
00752       return 1;
00753       }
00754     }
00755   else
00756     pWD->ppszVdir = NULL;
00757   if( pWD->cVdir ){
00758     i = 0;
00759     for( Node = ClientRootNode ;  Node ; Node = cft_EnumNext(pWD->pProgramConfig->pCONF,Node) ){
00760       s = cft_GetKey(pWD->pProgramConfig->pCONF,Node);
00761       if( ! strcmp(s,"dir") ){
00762         if( cft_GetEx(pWD->pProgramConfig->pCONF,NULL,&Node,&s,NULL,NULL,NULL) ){
00763           log_printf(&(pWD->PanicLog),
00764                      "cgt_GetEx( ..., %s, ... ) retuned error second time. This is an internal error.");
00765           fprintf(stderr,
00766                   "cgt_GetEx( ..., %s, ... ) retuned error second time. This is an internal error.");
00767           return 1;/* this is serious return immediately */
00768           }
00769         pWD->ppszVdir[i++] = s;
00770         }
00771       }
00772     }
00773 
00774   log_printf(&(pWD->AppLog),"AppInit returns %d",iError);
00775   /* App log was opened for syncronous logging. It will be reopened asynchronous after the possible fork */
00776   log_shutdown(&(pWD->AppLog));
00777   return iError;
00778   }
00779 
00780 #ifdef WIN32
00781 static void sleep(int x){ Sleep(1000*x); }
00782 #endif
00783 /*
00784 
00785 This GuardThread is started from the function AppStart and periodically looks at
00786 the PID file if that exists. When the system administrator deletes the PID file
00787 this thread alters the state of the httpd daemon and the http daemon stops executing
00788 more requests. However the requests currently serving are not affected.
00789 
00790 */
00791 static void GuardThread(void *p){
00792   pHttpdThread pHT;
00793   pWebData pWD;  
00794   FILE *fp;
00795   SOCKET Client;
00796   char buf[80];
00797   int i;
00798 
00799   pHT = p;
00800   pWD = pHT->AppData;
00801 
00802   while(1){
00803     fp = fopen(pWD->pszPid,"r");
00804     if( fp == NULL ){
00805       thread_LockMutex(&(pHT->mxState));
00806       pHT->iState = STATE_SHUT;
00807       thread_UnlockMutex(&(pHT->mxState));
00808       /* we have to connect to the web server port to help it out of the
00809          waiting loop. For the purpose I use this quick&dirty solution.
00810          It works and because this is not in a loop it does not matter. */
00811      for( i=0 ; i < pHT->c_servers ; i++ ){
00812        struct in_addr sip;
00813        memcpy(&sip,&(pHT->server[i].ip),sizeof(struct in_addr));
00814        sprintf(buf,"%s:%d",inet_ntoa(sip),pHT->server[i].port);
00815        log_printf(&(pWD->AppLog),"Connecting to server %s",buf);
00816        file_tcpconnect(&Client,buf);
00817        }
00818       //sprintf(buf,"127.0.0.1:%s",pWD->szPort);
00819       //file_tcpconnect(&Client,buf);
00820       return; /* exit from thread */
00821       }
00822     fclose(fp);
00823     sleep(pWD->lWaitLoop);
00824     }
00825   }
00826 
00827 struct _RunServiceProgram {
00828   pWebData pWD;
00829   char *pszProgramFileName;
00830   int iRestart;
00831   };
00832 
00833 static void ExecuteProgramThread(void *p){
00834   pSbProgram pProgram;
00835   int binarycode;
00836   char szInputFile[FULL_PATH_BUFFER_LENGTH];
00837   int iErrorCode;
00838   struct _RunServiceProgram *pRSP;
00839 
00840   pRSP = p;
00841   while( 1 ){
00842     strcpy(szInputFile,pRSP->pszProgramFileName);
00843     pProgram = scriba_new(malloc,free);
00844     if( pProgram == NULL )return;
00845 
00846     scriba_SetProcessSbObject(pProgram,pRSP->pWD->pProgramConfig);
00847     scriba_SetEmbedPointer(pProgram,pRSP->pWD);
00848     scriba_SetFileName(pProgram,szInputFile);
00849     binarycode = 0;
00850     if( scriba_UseCacheFile(pProgram) == SCRIBA_ERROR_SUCCESS )binarycode = 1;
00851     if( binarycode || scriba_IsFileBinaryFormat(pProgram) ){
00852       scriba_LoadBinaryProgram(pProgram);
00853       }else{
00854       if( scriba_RunExternalPreprocessor(pProgram,NULL) ){
00855         log_printf(&(pRSP->pWD->ErrLog),"External preprocessor failed for %s",szInputFile);
00856         return;
00857         }
00858       if( scriba_LoadSourceProgram(pProgram) ){
00859         log_printf(&(pRSP->pWD->ErrLog),"Source program loading error %s",szInputFile);
00860         return;
00861         }
00862       scriba_SaveCacheFile(pProgram);
00863       }
00864     log_printf(&(pRSP->pWD->AppLog),"Executing %s",szInputFile);
00865     iErrorCode = scriba_Run(pProgram,NULL);
00866     if( iErrorCode )
00867       log_printf(&(pRSP->pWD->ErrLog),"Program %s terminated with error %d",szInputFile,iErrorCode);
00868     scriba_destroy(pProgram);
00869     if( ! pRSP->iRestart )return;
00870     }
00871   } 
00872 
00873 static void ExecuteProgram(pWebData pWD,
00874                            char *pszProgramFileName,
00875                            int iRestart ){
00876   struct _RunServiceProgram *pRSP;
00877   THREADHANDLE T;
00878 
00879   pRSP = (struct _RunServiceProgram *)malloc( sizeof(struct _RunServiceProgram) );
00880   if( pRSP == NULL ){
00881     log_printf(&(pRSP->pWD->ErrLog),
00882        "No memory to allocate RSP structure when trying to run %s",pszProgramFileName);
00883     return;
00884     }
00885   pRSP->pszProgramFileName = (char *)malloc(strlen(pszProgramFileName) + 1);
00886   if( pRSP->pszProgramFileName == NULL ){
00887     log_printf(&(pRSP->pWD->ErrLog),
00888        "No memory to allocate pszProgramFileName when trying to run %s",pszProgramFileName);
00889     return;
00890     }
00891   strcpy(pRSP->pszProgramFileName,pszProgramFileName);
00892   pRSP->iRestart = iRestart;
00893   pRSP->pWD = pWD;
00894   thread_CreateThread(&T,ExecuteProgramThread,pRSP);
00895   }
00896 
00897 int AppStart(void **AppData){
00898   void *pM_HitLog,*pM_StatLog,*pM_AppLog,*pM_ErrLog;
00899   pWebData pWD;
00900   CFT_NODE ConfNode,Node;
00901   int iError;
00902   FILE *fp;
00903   THREADHANDLE hThread;
00904   char *s;
00905   int iRestart;
00906 #ifndef WIN32
00907   uid_t uid;
00908   struct passwd *pw;
00909   char *pszEffectiveUser;
00910 #endif
00911 
00912   iError = 0; /* read comment on the variable of the same name in AppInit */
00913   pWD = *AppData;
00914 
00915   if( pWD->nolog ){
00916     log_init(&(pWD->HitLog),NULL,NULL,NULL,NULL,LOGTYPE_NORMAL);
00917     log_init(&(pWD->StatLog),NULL,NULL,NULL,NULL,LOGTYPE_NORMAL);
00918     log_init(&(pWD->AppLog),NULL,NULL,NULL,NULL,LOGTYPE_NORMAL);
00919     log_init(&(pWD->ErrLog),NULL,NULL,NULL,NULL,LOGTYPE_NORMAL);
00920     }else{
00921     /* allocate memory segments for each log. Memory allocation is serious enough not to go on. */
00922     pM_HitLog = alloc_InitSegment(malloc,free);
00923     if( pM_HitLog == NULL ){
00924       log_printf(&(pWD->PanicLog),"Memory error allocating pM_HitLog");
00925       return 1;
00926       }
00927     pM_StatLog = alloc_InitSegment(malloc,free);
00928     if( pM_StatLog == NULL ){
00929       log_printf(&(pWD->PanicLog),"Memory error allocating pM_StatLog");
00930       return 1;
00931       }
00932     pM_AppLog = alloc_InitSegment(malloc,free);
00933     if( pM_AppLog == NULL ){
00934       log_printf(&(pWD->PanicLog),"Memory error allocating pM_AppLog");
00935       return 1;
00936       }
00937     pM_ErrLog = alloc_InitSegment(malloc,free);
00938     if( pM_ErrLog == NULL ){
00939       log_printf(&(pWD->PanicLog),"Memory error allocating pM_ErrLog");
00940       return 1;
00941       }
00942 
00943 #ifndef WIN32
00944   pszEffectiveUser = CONFIG("servers.user");
00945   if( pszEffectiveUser ){
00946     pw = getpwnam(pszEffectiveUser);
00947     if( pw ){
00948       if( setuid(pw->pw_uid) ){
00949         log_printf(&(pWD->PanicLog),"ESBAE configured to run as user (%s/%d). I can not set this uid for some reason.",
00950                   pszEffectiveUser,uid);
00951         iError = 1;
00952         }
00953       }else{
00954       log_printf(&(pWD->PanicLog),"ESBAE configured to run as user (%s). This user does not exists on this machine.",pszEffectiveUser);
00955       iError = 1;
00956       }
00957     }
00958 #endif
00959 
00960     if( log_init(&(pWD->ErrLog),alloc_Alloc,alloc_Free,pM_ErrLog,CONFIG("servers.log.err.file"),LOGTYPE_NORMAL) ){
00961       log_printf(&(pWD->PanicLog),"Can not initialize error log.");
00962       return 1;
00963       }
00964     if( cft_GetEx(pWD->pProgramConfig->pCONF,"servers.log.err.span",&ConfNode,NULL,&(pWD->ErrLog.TimeSpan),NULL,NULL) )
00965     pWD->ErrLog.TimeSpan = 0;
00966 
00967     if( log_init(&(pWD->HitLog),alloc_Alloc,alloc_Free,pM_HitLog,CONFIG("servers.log.hit.file"),LOGTYPE_NORMAL) ){
00968       log_printf(&(pWD->PanicLog),"HitLog (%s) cannot be opened.",CONFIG("servers.log.hit.file"));
00969       return 1;
00970       }
00971     if( cft_GetEx(pWD->pProgramConfig->pCONF,"servers.log.hit.span",&ConfNode,NULL,&(pWD->HitLog.TimeSpan),NULL,NULL) )
00972       pWD->HitLog.TimeSpan = 0;
00973   
00974     if( log_init(&(pWD->StatLog),alloc_Alloc,alloc_Free,pM_StatLog,CONFIG("servers.log.stat.file"),LOGTYPE_NORMAL) ){
00975       log_printf(&(pWD->PanicLog),"StatLog (%s) cannot be opened.",CONFIG("servers.log.stat.file"));
00976       return 1;
00977       }
00978     if( cft_GetEx(pWD->pProgramConfig->pCONF,"servers.log.stat.span",&ConfNode,NULL,&(pWD->StatLog.TimeSpan),NULL,NULL) )
00979       pWD->StatLog.TimeSpan = 0;
00980   
00981     if( log_init(&(pWD->AppLog),alloc_Alloc,alloc_Free,pM_AppLog,CONFIG("servers.log.app.file"),LOGTYPE_NORMAL) ){
00982       log_printf(&(pWD->PanicLog),"AppLog (%s) cannot be opened.",CONFIG("servers.log.app.file"));
00983     return 1;
00984     }
00985     if( cft_GetEx(pWD->pProgramConfig->pCONF,"servers.log.app.span",&ConfNode,NULL,&(pWD->AppLog.TimeSpan),NULL,NULL) )
00986       pWD->AppLog.TimeSpan = 0;
00987 
00988     log_printf(&(pWD->AppLog),"All logs successfully intialized.");
00989     }
00990 
00991   pWD->pszPid = CONFIG("servers.pid.file");
00992   fp = NULL;
00993   if( pWD->pszPid )fp = fopen(pWD->pszPid,"w");
00994   if( fp == NULL ){
00995     log_printf(&(pWD->PanicLog),"Pid file (%s) cannot be opened.",pWD->pszPid);
00996     if( ! pWD->nolog )iError = 1;
00997     pWD->pszPid = NULL;
00998     }else{
00999     fprintf(fp,"%d\n",getpid());
01000     fclose(fp);
01001     fp = NULL;
01002     }
01003 
01004   thread_InitMutex(&(pWD->pHT->mxState));
01005   pWD->pHT->iState = STATE_NORMAL;
01006 
01007   if( cft_GetEx(pWD->pProgramConfig->pCONF,"servers.pid.delay",&ConfNode,NULL,&(pWD->lWaitLoop),NULL,NULL) )
01008     pWD->lWaitLoop  = 5; /* five seconds delay */
01009 
01010   if( !iError && pWD->pszPid )
01011     thread_CreateThread(&hThread,GuardThread,pWD->pHT);
01012 
01013 #ifdef WIN32
01014   pHT_Service = pWD->pHT;
01015 #endif
01016 
01017   ConfNode = cft_FindNode(pWD->pProgramConfig->pCONF,CFT_ROOT_NODE,"servers.run");
01018   if( ConfNode )ConfNode = cft_EnumFirst(pWD->pProgramConfig->pCONF,ConfNode);
01019   if( ConfNode ){/* if there is any servers.run command configured */
01020     for( Node = ConfNode ;  Node ; Node = cft_EnumNext(pWD->pProgramConfig->pCONF,Node) ){
01021       s = cft_GetKey(pWD->pProgramConfig->pCONF,Node);
01022       if( ! strcmp(s,"start") )iRestart = 0;
01023       else if( ! strcmp(s,"restart") )iRestart = 1;
01024       else{
01025         log_printf(&(pWD->ErrLog),"Unknow RUN command in the config file %s",s);
01026         continue;
01027         }
01028       cft_GetEx(pWD->pProgramConfig->pCONF,NULL,&Node,&s,NULL,NULL,NULL);
01029       ExecuteProgram(pWD,s,iRestart);
01030       }
01031     }
01032 
01033 
01034   log_printf(&(pWD->AppLog),"AppStart returns %d",iError);
01035   return iError;
01036   }
01037 
01038 static void pfFtpOut(int ch,
01039                      void *pE){
01040   pThreadData pT = pE;
01041 
01042   ch = (char)ch;
01043 
01044   WriteClient(&ch,1);
01045   return;
01046   }
01047 static int pfFtpIn(void *pE){
01048   return EOF;
01049   }
01050 
01051 static void pfStdOut(int ch,
01052                      void *pE){
01053   pThreadData pT;
01054   pApplicationThreadData pATD;
01055 
01056   ch = (char)ch;
01057 
01058   pT = pE;
01059   pATD = pT->AppThreadData;
01060   if( ! pATD->FirstHeaderLine ){
01061     WriteClient(&ch,1);
01062     return;
01063     }
01064 
01065   if( pATD->cbBuffer == OBLEN ){
01066     WriteClient(pATD->szBuffer,pATD->cbBuffer);
01067     pATD->cbBuffer = 0;
01068     pATD->FirstHeaderLine = 0;
01069     WriteClient(&ch,1);
01070     return;
01071     }
01072 
01073   pATD->szBuffer[pATD->cbBuffer++] = ch;
01074   /* if this is the first header line convert 'Status:' to 'HTTP/1.0' */
01075   if( ch == '\n' ){
01076     pATD->FirstHeaderLine = 0;
01077     if( pATD->cbBuffer > 7 && ! strncmp(pATD->szBuffer,"Status:",7) ){
01078       WriteClient("HTTP/1.0",8);
01079       WriteClient(pATD->szBuffer+7,pATD->cbBuffer-7);
01080       pATD->cbBuffer = 0;
01081       return;
01082       }else{
01083       WriteClient(pATD->szBuffer,pATD->cbBuffer);
01084       pATD->cbBuffer = 0;
01085       }
01086     }
01087 
01088   }
01089 
01090 static int pfStdIn(void *pE){
01091   pThreadData pT;
01092   pApplicationThreadData pATD;  
01093 
01094   pT = pE;
01095   if( pT->cbAvailable ){
01096     pT->cbAvailable--;
01097     return (unsigned int)*(pT->pszData++);
01098     }
01099 
01100   pATD = pT->AppThreadData;
01101 
01102   if( pATD->cbInBuffer ){
01103     pATD->cbInBuffer--;
01104     return (unsigned int)*pATD->pszInBuffer++;
01105     }
01106 
01107   /* if there is no available bytes we have to fill the buffer */
01108   pATD->cbInBuffer = ReadClient(pATD->szInBuffer,INBLEN);
01109   pATD->pszInBuffer = pATD->szInBuffer;
01110   if( pATD->cbInBuffer ){
01111     pATD->cbInBuffer--;
01112     return (unsigned int)*(pATD->pszInBuffer++);
01113     }else return EOF;
01114   }
01115 
01116 static char *pfFtpEnv(void *pE, char *pszEVN, long lEVSN){
01117   pThreadData pT;
01118   pApplicationThreadData pATD;
01119   int isLong;
01120   char *pszRet;
01121 
01122   pT = pE;
01123   pATD = pT->AppThreadData;
01124 
01125   if( isLong = (pszEVN == NULL) )
01126     switch( lEVSN ){
01127 #define X(a,b) case a: pszEVN = b; strcpy(pATD->szEnvBuf,b); strcat(pATD->szEnvBuf,"=");break;
01128 X(0,"FTP_COMMAND")
01129 X(1,"THREAD_INDEX")
01130       default: return NULL;
01131       }
01132 #define envRETURN(X) do{ pszRet=X;\
01133                       if( isLong ){\
01134                         if( pszRet && strlen(pszRet) < ENVLEN - strlen(pATD->szEnvBuf) -1 )\
01135                           strcat(pATD->szEnvBuf,pszRet);\
01136                         return pATD->szEnvBuf;\
01137                         }else return pszRet;\
01138                      }while(0)
01139 
01140   if( !strcmp(pszEVN,"FTP_COMMAND") ){
01141     envRETURN( pATD->pszFtpCommand );
01142     }
01143   if( !strcmp(pszEVN,"THREAD_INDEX") ){
01144     envRETURN( pATD->szThreadIndex );
01145     }
01146 
01147   return NULL;
01148   }
01149 
01150 static char *pfEnv(void *pE, char *pszEVN, long lEVSN){
01151   pThreadData pT;
01152   pApplicationThreadData pATD;
01153   pWebData pWD;
01154   char *s;
01155   int isLong;
01156   char *pszRet;
01157 
01158   pT = pE;
01159   pATD = pT->AppThreadData;
01160   pWD = pT->pHT->AppData;
01161 
01162   if( isLong = (pszEVN == NULL) )
01163     switch( lEVSN ){
01164 #define X(a,b) case a: pszEVN = b; strcpy(pATD->szEnvBuf,b); strcat(pATD->szEnvBuf,"=");break;
01165 X(0,"HTTP_COOKIE")
01166 X(1,"SERVER_SOFTWARE")
01167 X(2,"SERVER_NAME")
01168 X(3,"GATEWAY_INTERFACE")
01169 X(4,"SERVER_PROTOCOL")
01170 X(5,"SERVER_PORT")
01171 X(6,"REQUEST_METHOD")
01172 X(7,"PATH_INFO")
01173 X(8,"PATH_TRANSLATED")
01174 X(9,"SCRIPT_NAME")
01175 X(10,"QUERY_STRING")
01176 X(11,"REMOTE_HOST")
01177 X(12,"REMOTE_ADDR")
01178 X(13,"AUTH_TYPE")
01179 X(14,"REMOTE_USER")
01180 X(15,"REMOTE_IDENT")
01181 X(16,"CONTENT_TYPE")
01182 X(17,"CONTENT_LENGTH")
01183 X(18,"HTTP_USER_AGENT")
01184 X(19,"HTTP_REFERER")
01185 X(20,"HTTP_PASSWORD")
01186 X(21,"HTTP_AUTHORIZATION")
01187 #undef X
01188       default: return NULL;
01189       }
01190 
01191 #define envRETURN(X) do{ pszRet=X;\
01192                       if( isLong ){\
01193                         if( pszRet && strlen(pszRet) < ENVLEN - strlen(pATD->szEnvBuf) -1 )\
01194                           strcat(pATD->szEnvBuf,pszRet);\
01195                         return pATD->szEnvBuf;\
01196                         }else return pszRet;\
01197                      }while(0)
01198 
01199   if( !strcmp(pszEVN,"HTTP_COOKIE") ){
01200     envRETURN( GetServerVariable("Cookie") );
01201     }
01202   if( !strcmp(pszEVN,"SERVER_SOFTWARE") ){
01203     envRETURN( "Eszter SB Engine 1.0" );
01204     }
01205   if( !strcmp(pszEVN,"SERVER_NAME") ){
01206     if( isLong )return "SERVER_NAME=";
01207     return NULL;
01208     }
01209   if( !strcmp(pszEVN,"GATEWAY_INTERFACE") ){
01210     envRETURN( "CGI/1.1" );
01211     }
01212   if( !strcmp(pszEVN,"SERVER_PROTOCOL") ){
01213     envRETURN( "HTTP/1.1" );
01214     }
01215   if( !strcmp(pszEVN,"SERVER_PORT") ){
01216     
01217     envRETURN( pWD->szPort );
01218     }
01219   if( !strcmp(pszEVN,"REQUEST_METHOD") ){
01220     envRETURN( pT->pszMethod );
01221     }
01222   if( !strcmp(pszEVN,"PATH_INFO") ){
01223     if( isLong )return "PATH_INFO=";
01224     return NULL;
01225     }
01226   if( !strcmp(pszEVN,"PATH_TRANSLATED") ){
01227     envRETURN( pATD->pszPathTranslated );
01228     }
01229   if( !strcmp(pszEVN,"SCRIPT_NAME") ){
01230     envRETURN( ScriptName() );
01231     }
01232   if( !strcmp(pszEVN,"QUERY_STRING") ){
01233     s = pT->pszQueryString;
01234     while( *s && *s != '?' )s++;
01235     if( *s )s++;
01236     envRETURN( s );
01237     }
01238   if( !strcmp(pszEVN,"REMOTE_HOST") ){
01239     envRETURN( pATD->pszClientIP );
01240     }
01241   if( !strcmp(pszEVN,"REMOTE_ADDR") ){
01242     envRETURN( pATD->pszClientIP );
01243     }
01244   if( !strcmp(pszEVN,"AUTH_TYPE") ){
01245     envRETURN( GetServerVariable("Authorization") );
01246     }
01247   if( !strcmp(pszEVN,"REMOTE_USER") ){
01248     envRETURN( pATD->pszRemoteUser );
01249     }
01250   if( !strcmp(pszEVN,"REMOTE_IDENT") ){
01251     if( isLong )return "REMOTE_IDENT=";
01252     return NULL;
01253     }
01254   if( !strcmp(pszEVN,"CONTENT_TYPE") ){
01255     envRETURN( GetServerVariable("Content-Type") );
01256     }
01257   if( !strcmp(pszEVN,"CONTENT_LENGTH") ){
01258     envRETURN( GetServerVariable("Content-Length") );
01259     }
01260   if( !strcmp(pszEVN,"HTTP_USER_AGENT") ){
01261     envRETURN( GetServerVariable("User-Agent") );
01262     }
01263   if( !strcmp(pszEVN,"HTTP_REFERER") ){
01264     envRETURN( GetServerVariable("Referer") );
01265     }
01266   if( !strcmp(pszEVN,"HTTP_PASSWORD") ){
01267     envRETURN( pATD->pszPassword );
01268     }
01269   if( !strcmp(pszEVN,"HTTP_AUTHORIZATION") ){
01270     envRETURN( GetServerVariable("Authorization") );
01271     }
01272 
01273   return NULL;
01274   }
01275 
01276 /* send the 404 error page to the client */
01277 static void send404(pHttpdThread pHT,pThreadData pT){
01278   pWebData pWD;
01279 
01280   pWD = pHT->AppData;
01281   if( pWD->code404 ){
01282     WriteClientText("HTTP/1.0 ");
01283     WriteClientText(pWD->code404);
01284     WriteClientText("\nContent-Type: text/html\n\n");
01285     }else{
01286     WriteClientText("HTTP/1.0 404 Page not found\nContent-Type: text/html\n\n");
01287     }
01288   if( pWD->msg404 ){
01289     WriteClientText(pWD->msg404);
01290     }else{
01291     /* The shortest possible correct error message that we can send to the client. */
01292     WriteClientText(
01293 "<HTML><HEAD><TITLE>Page not found error 404</TITLE></HEAD>"
01294 "<BODY>The requested page is not found on this server.</BODY></HTML>"
01295 );
01296     }
01297   
01298   }
01299 
01300 int FtpProc(pHttpdThread pHT,pThreadData pT,char *Buffer){
01301   char *s,*r,last_c;
01302   int inpfnlen;
01303   pSbProgram pProgram;
01304   char szInputFile[FULL_PATH_BUFFER_LENGTH];
01305   int binarycode;
01306   pWebData pWD;
01307   pApplicationThreadData pATD;
01308   unsigned long iErrorCode;
01309   FILE *fp;
01310 
01311   pWD = pHT->AppData;
01312   if( NULL == pT->AppThreadData ){
01313     pT->AppThreadData = malloc( sizeof(ApplicationThreadData) );
01314     if( NULL == pT->AppThreadData )return 1;
01315     }
01316   pATD = pT->AppThreadData;
01317   pT->pThreadLocalData = pHT;
01318   
01319   s = NULL;
01320 #define GET_BAS_P_NAME(X,Y) if( ! strnicmp(Buffer,#X,Y) )s = pHT->server[pT->server_index].X;
01321   GET_BAS_P_NAME(USER,4)
01322   GET_BAS_P_NAME(PASS,4)
01323   GET_BAS_P_NAME(ACCT,4)
01324   GET_BAS_P_NAME(CWD,3)
01325   GET_BAS_P_NAME(CDUP,4)
01326   GET_BAS_P_NAME(SMNT,4)
01327   GET_BAS_P_NAME(REIN,4)
01328   GET_BAS_P_NAME(QUIT,4)
01329   GET_BAS_P_NAME(PORT,4)
01330   GET_BAS_P_NAME(PASV,4)
01331   GET_BAS_P_NAME(TYPE,4)
01332   GET_BAS_P_NAME(STRU,4)
01333   GET_BAS_P_NAME(MODE,4)
01334   GET_BAS_P_NAME(RETR,4)
01335   GET_BAS_P_NAME(STOR,4)
01336   GET_BAS_P_NAME(STOU,4)
01337   GET_BAS_P_NAME(APPE,4)
01338   GET_BAS_P_NAME(ALLO,4)
01339   GET_BAS_P_NAME(REST,4)
01340   GET_BAS_P_NAME(RNFR,4)
01341   GET_BAS_P_NAME(RNTO,4)
01342   GET_BAS_P_NAME(ABOR,4)
01343   GET_BAS_P_NAME(DELE,4)
01344   GET_BAS_P_NAME(MKD,3)
01345   GET_BAS_P_NAME(PWD,3)
01346   GET_BAS_P_NAME(LIST,4)
01347   GET_BAS_P_NAME(NLST,4)
01348   GET_BAS_P_NAME(SITE,4)
01349   GET_BAS_P_NAME(SYST,4)
01350   GET_BAS_P_NAME(STAT,4)
01351   GET_BAS_P_NAME(HELP,4)
01352   GET_BAS_P_NAME(NOOP,4)
01353 
01354   if( NULL == s ){
01355     /* If there is no program name configured then the name of the command is used
01356        in lower case value.
01357 
01358        In this case codebase should be defined for the server.
01359     */
01360     if( NULL == pHT->server[pT->server_index].codebase ){
01361       if( pT->AppThreadData ){ free(pT->AppThreadData);pT->AppThreadData = NULL;}
01362       log_printf(&(pWD->ErrLog),"no code base is defined for server %d and the command \"%s\" is not handled",pT->server_index,Buffer);
01363       return 1;
01364       }
01365     if( strlen(pHT->server[pT->server_index].codebase) >= FULL_PATH_BUFFER_LENGTH ){
01366       if( pT->AppThreadData ){ free(pT->AppThreadData);pT->AppThreadData = NULL;}
01367       log_printf(&(pWD->ErrLog),"code base for server %d is too long, max %d is allowed",pT->server_index,FULL_PATH_BUFFER_LENGTH);
01368       return 1;
01369       }
01370     strcpy(szInputFile,pHT->server[pT->server_index].codebase);
01371     inpfnlen=strlen(szInputFile);
01372     r = szInputFile+inpfnlen;
01373     if( inpfnlen )
01374       last_c = *( r-1 );
01375     else
01376       last_c = (char)0;
01377     if( inpfnlen >= FULL_PATH_BUFFER_LENGTH ){
01378       if( pT->AppThreadData ){ free(pT->AppThreadData);pT->AppThreadData = NULL;}
01379       log_printf(&(pWD->ErrLog),"file name becomes too long server %d, max %d chars are allowed",pT->server_index,FULL_PATH_BUFFER_LENGTH);
01380       return 1;
01381       }
01382     if( '\\' != last_c && '/' != last_c )strcat(szInputFile,"/");
01383     s = Buffer;
01384     while( *s && !isspace(*s) ){
01385       inpfnlen++;
01386       if( inpfnlen >= FULL_PATH_BUFFER_LENGTH-4 ){
01387         if( pT->AppThreadData ){ free(pT->AppThreadData);pT->AppThreadData = NULL;}
01388         log_printf(&(pWD->ErrLog),"file name becomes too long server %d, max %d chars are allowed",pT->server_index,FULL_PATH_BUFFER_LENGTH);
01389         return 1;
01390         }
01391       *r++ = isupper(*s) ? tolower(*s) : *s ;
01392       *r = (char)0;
01393       s++;
01394       }
01395     strcpy(r,".bas");
01396     }else{
01397     if( strlen(s) >= FULL_PATH_BUFFER_LENGTH ){
01398         if( pT->AppThreadData ){ free(pT->AppThreadData);pT->AppThreadData = NULL;}
01399         log_printf(&(pWD->ErrLog),"Configured file name for basic program is too long for server %d, max %d chars are allowed.",pT->server_index,FULL_PATH_BUFFER_LENGTH);
01400         return 1;
01401         }
01402     strcpy(szInputFile,s);
01403     }
01404 
01405   /* check that the file exists and readable */
01406   if( NULL == (fp = file_fopen(szInputFile,"r")) ){
01407     WriteClientText("500 Syntax error, command unrecognized really.\r\n");
01408     return 0;
01409     }
01410   file_fclose(fp);
01411 
01412   pProgram = scriba_new(malloc,free);
01413   if( pProgram == NULL ){
01414     log_printf(&(pWD->ErrLog),"scriba_new returned null");
01415     if( pT->AppThreadData ){ free(pT->AppThreadData);pT->AppThreadData = NULL;}
01416     return 1;
01417     }
01418 
01419   scriba_SetProcessSbObject(pProgram,pWD->pProgramConfig);
01420   scriba_SetStdin(pProgram,pfFtpIn);
01421   scriba_SetStdout(pProgram,pfFtpOut);
01422 
01423   pATD->pszFtpCommand = Buffer;
01424   sprintf(pATD->szThreadIndex,"%d",pT->ThreadIndex);
01425   scriba_SetEnvironment(pProgram,pfFtpEnv);
01426   scriba_SetEmbedPointer(pProgram,pT);
01427   scriba_SetReportPointer(pProgram,pT);
01428   scriba_SetReportFunction(pProgram,ftp_report);
01429 
01430   scriba_SetFileName(pProgram,szInputFile);
01431 
01432   binarycode = 0;
01433   if( scriba_UseCacheFile(pProgram) == SCRIBA_ERROR_SUCCESS )binarycode = 1;
01434   if( binarycode || scriba_IsFileBinaryFormat(pProgram) ){
01435     scriba_LoadBinaryProgram(pProgram);
01436     }else{
01437     if( scriba_RunExternalPreprocessor(pProgram,NULL) ){
01438       log_printf(&(pWD->ErrLog),"External preprocessor failed for %s",szInputFile);
01439       if( pT->AppThreadData ){ free(pT->AppThreadData);pT->AppThreadData = NULL;}
01440       return 1;
01441       }
01442 
01443     if( scriba_LoadSourceProgram(pProgram) ){/* if there is some error loading the program */
01444       scriba_destroy(pProgram);
01445       if( pT->AppThreadData ){ free(pT->AppThreadData);pT->AppThreadData = NULL;}
01446       log_printf(&(pWD->ErrLog),"There was error loading the program \"%s\"",szInputFile);
01447       return 1; /* error was already reported, just return */
01448       }
01449     scriba_SaveCacheFile(pProgram);
01450     }
01451   log_printf(&(pWD->HitLog),"Executing %s",szInputFile);
01452   iErrorCode = scriba_Run(pProgram,NULL);
01453   scriba_destroy(pProgram);
01454   if( iErrorCode && pT->AppThreadData ){ free(pT->AppThreadData);pT->AppThreadData = NULL;}
01455   return iErrorCode;
01456   }
01457 
01458 void HttpProc(pHttpdThread pHT,pThreadData pT){
01459   char *sn,*s;
01460   pSbProgram pProgram;
01461   char szInputFile[FULL_PATH_BUFFER_LENGTH];
01462   char szOriginalInputFile[FULL_PATH_BUFFER_LENGTH]; /* to store PathTranslated when 404 code is executed */
01463   char szAuthStringBuffer[FULL_PATH_BUFFER_LENGTH];
01464   char szClientIP[16]; /* xxx.xxx.xxx.xxx\0 */
01465   int binarycode;
01466   pWebData pWD;
01467   ApplicationThreadData ATD;
01468   unsigned long i,iErrorCode;
01469   int iErrorCounter;
01470   FILE *fProgramSource;
01471 
01472   pWD = pHT->AppData;
01473   pT->AppThreadData = &ATD;
01474   pT->pThreadLocalData = pHT;
01475   
01476   if( pWD->XForwarded ){
01477     ATD.pszClientIP = GetServerVariable("X-Forwarded-For");
01478     }else{
01479     sprintf(szClientIP,"%d.%d.%d.%d",pT->ClientIP[0],pT->ClientIP[1],pT->ClientIP[2],pT->ClientIP[3]);
01480     ATD.pszClientIP = szClientIP;
01481     }
01482   ATD.cbBuffer = 0;
01483   ATD.FirstHeaderLine = 1;
01484   ATD.cbInBuffer = 0;
01485 
01486   /*
01487    *  Get the BASIC authentication parameters
01488    */
01489   s = GetServerVariable("Authorization");
01490   if( s ){
01491     while( *s && isspace(*s) )s++;    /* step over the space after the :   */
01492     while( *s && ! isspace(*s) )s++;  /* step over the word 'Basic'        */
01493     while( *s && isspace(*s) )s++;    /* step over the space after 'Basic' */
01494     uudecode(s,szAuthStringBuffer,FULL_PATH_BUFFER_LENGTH);
01495     }else *szAuthStringBuffer = (char)0;
01496   ATD.pszRemoteUser = szAuthStringBuffer;
01497   s = szAuthStringBuffer;
01498   while( *s && *s != ':' )s++;
01499   if( *s )*s++ = (char)0;
01500   ATD.pszPassword = s;
01501 
01502   /* get the name of the BASIC program */
01503   sn = ScriptName();
01504 
01505   pProgram = scriba_new(malloc,free);
01506   if( pProgram == NULL )return;
01507 
01508   scriba_SetProcessSbObject(pProgram,pWD->pProgramConfig);
01509   scriba_SetCgiFlag(pProgram);
01510   scriba_SetStdin(pProgram,pfStdIn);
01511   scriba_SetStdout(pProgram,pfStdOut);
01512   scriba_SetEnvironment(pProgram,pfEnv);
01513   scriba_SetEmbedPointer(pProgram,pT);
01514   scriba_SetReportPointer(pProgram,pT);
01515   scriba_SetReportFunction(pProgram,httpd_report);
01516 
01517   s = NULL;
01518   for( i = 0 ; i < pWD->cVdir ; i++ ){
01519     if( s = prefix(pT->pszQueryString,pWD->ppszVdir[i]) )
01520       break;
01521     }
01522 
01523   if( s ){
01524     strcpy(szInputFile,s);
01525     strcat(szInputFile,sn);
01526     }else{
01527     strcpy(szInputFile,pWD->pszHome);
01528     s = sn;
01529     if( *s == '/' )s++;
01530     strcat(szInputFile,s);
01531     }
01532 
01533   scriba_SetFileName(pProgram,szInputFile);
01534   ATD.pszPathTranslated = szInputFile;
01535   binarycode = 0;
01536   if( scriba_UseCacheFile(pProgram) == SCRIBA_ERROR_SUCCESS )binarycode = 1;
01537   if( binarycode || scriba_IsFileBinaryFormat(pProgram) ){
01538     scriba_LoadBinaryProgram(pProgram);
01539     }else{
01540     if( scriba_RunExternalPreprocessor(pProgram,NULL) ){
01541       log_printf(&(pWD->ErrLog),"External preprocessor failed for %s",szInputFile);
01542       return;
01543       }
01544 
01545     /* open the program source code to test that we can open the file (readable and exists) */
01546     if( NULL == (fProgramSource = file_fopen(pProgram->pszFileName,"r")) ){
01547       if( ! (pWD->bErrMsgDest & ERRMSGERRLOG) )
01548         log_printf(&(pWD->ErrLog),"Source program loading error %s",szInputFile);
01549       if( pWD->run404 ){/* if the program can not be loaded and there is a run404 BASIC program */
01550         strcpy(szOriginalInputFile,szInputFile);
01551         strcpy(szInputFile,pWD->run404);
01552         scriba_SetFileName(pProgram,szInputFile);
01553         ATD.pszPathTranslated = szOriginalInputFile; /* WE LET THE 404 PROGRAM HAVE THE ORIGINAL PATH TO SEE */
01554         binarycode = 0;
01555         if( scriba_UseCacheFile(pProgram) == SCRIBA_ERROR_SUCCESS )binarycode = 1;
01556         if( binarycode || scriba_IsFileBinaryFormat(pProgram) ){
01557           scriba_LoadBinaryProgram(pProgram);
01558           }else{
01559           if( scriba_RunExternalPreprocessor(pProgram,NULL) ){
01560             log_printf(&(pWD->ErrLog),"External preprocessor failed for \"%s\"",szInputFile);
01561             scriba_destroy(pProgram);
01562             return;
01563             }
01564           if( scriba_LoadSourceProgram(pProgram) ){
01565             if( ! (pWD->bErrMsgDest & ERRMSGERRLOG) ){
01566               log_printf(&(pWD->ErrLog),"404 program loading error \"%s\"",szInputFile);
01567               send404(pHT,pT);
01568               scriba_destroy(pProgram);
01569               return;
01570               }
01571             }
01572           }
01573         }else{/* if there is no run404 program configured */
01574           if( ! (pWD->bErrMsgDest & ERRMSGCLIENT) ){
01575             log_printf(&(pWD->ErrLog),"404 program loading error \"%s\"",szInputFile);
01576             }
01577           send404(pHT,pT);
01578           return;
01579           }
01580         }
01581     /* close the file handle that was opened for testing purpose only */
01582     if( fProgramSource )file_fclose(fProgramSource);
01583     if( scriba_LoadSourceProgram(pProgram) ){/* if there is some error loading the program */
01584       scriba_destroy(pProgram);
01585       return; /* error was already reported, just return */
01586       }
01587     scriba_SaveCacheFile(pProgram);
01588     }
01589   log_printf(&(pWD->HitLog),"Executing %s",szInputFile);
01590   iErrorCode = scriba_Run(pProgram,NULL);
01591   if( iErrorCode )
01592     httpd_report(pT,szInputFile,0,iErrorCode,REPORT_ERROR,&iErrorCounter,
01593                  pProgram->pEXE->pszModuleError ? pProgram->pEXE->pszModuleError : "program terminated with error",&iErrorCode);
01594   scriba_destroy(pProgram);
01595   }
01596 
01597 #if BCC32
01598 char *_pgmptr;
01599 #endif
01600 
01601 main(int argc, char *argv[]){
01602   int do_fork, do_safe;
01603   int i;
01604 #ifdef WIN32
01605   SERVICE_TABLE_ENTRY dispatchTable[] ={
01606         { "sbhttpd", (LPSERVICE_MAIN_FUNCTION)service_main },
01607         { NULL, NULL }
01608     };
01609 #else
01610   int cpid;
01611 #endif
01612 
01613   /* Because the command CHDIR calls the system function that changes the current directory
01614      of the process, and because this application implements several ScriptBasic interpreters
01615      in several threads thus it is better to disable the command for all programs that
01616      runs in this application. */
01617   CommandFunction[CMD_CHDIR - START_CMD ] = NULL;
01618 
01619 #ifdef WIN32
01620 
01621 #if BCC32
01622   _pgmptr = argv[0];
01623 #endif
01624   if( argc > 1 && !strcmp(argv[1],"-install")){
01625     CmdInstallService();
01626     return 0;
01627     }
01628 
01629   if( argc > 1 && !strcmp(argv[1],"-remove")){
01630     CmdRemoveService();
01631     return 0;
01632     }
01633 
01634   /* if the program was loaded as a service then this function
01635      registers the service_main entry point and returns TRUE */
01636   if( (argc > 1 && ! strcmp(argv[1],"-start")) || AmIService() )
01637     if( StartServiceCtrlDispatcher(dispatchTable) )return 0;
01638 
01639 #endif
01640 
01641   scriba_InitStaticModules();
01642 
01643   do_fork = argc > 1 && !strcmp(argv[1],"-start");
01644   do_safe = argc > 1 && !strcmp(argv[1],"-safe");
01645   if( do_safe )do_fork = 1;
01646 
01647 #ifndef WIN32
01648   /* we have to do the fork here before calling AppInit, because AppInit
01649      starts threads and fork does NOT duplicate the threads of the parent
01650      process except the thread calling fork() .*/
01651   if( do_fork ){
01652     if( fork() )exit(0);
01653     }
01654   if( do_safe ){
01655     while( cpid = fork() ){
01656       waitpid( cpid , NULL , WUNTRACED );
01657       }
01658     }
01659 #endif
01660 
01661   /* if -start or -safe was specified then delete them from the command line and the rest of the command line
01662      is passed to the function httpd */
01663   if( argc > 1 && ( !strcmp(argv[1],"-start") || !strcmp(argv[1],"-safe") ) ){
01664     for( i = 1 ; i < argc - 1 ; i++ )argv[i] = argv[i+1];
01665       argc--;
01666     }
01667 
01668   httpd(argc,argv,AppInit,AppStart,HttpProc,FtpProc);
01669   return 0;
01670   }
01671 
01672 #ifdef WIN32
01673 VOID ServiceStart(DWORD dwArgc, LPTSTR *lpszArgv){
01674   char *argv[2] = { "sbhttpd","-start" };
01675 
01676   if( ReportStatusToSCMgr(SERVICE_RUNNING,NO_ERROR,0) ){
01677     main(2,argv);
01678     }
01679 }
01680 VOID ServiceStop(){
01681   pHttpdThread pHT;
01682   pWebData pWD;  
01683   SOCKET Client;
01684   char buf[80];
01685   int i;
01686 
01687   pHT = pHT_Service;
01688   pWD = pHT->AppData;
01689 
01690   thread_LockMutex(&(pHT->mxState));
01691   pHT->iState = STATE_SHUT;
01692   thread_UnlockMutex(&(pHT->mxState));
01693   /* we have to connect to the web server port to help it out of the
01694      waiting loop. For the purpose I use this quick&dirty solution.
01695      It works. */
01696   log_printf(&(pWD->AppLog),"Shutting down %d servers",pHT->c_servers);
01697   for( i=0 ; i < pHT->c_servers ; i++ ){
01698      struct in_addr sip;
01699      memcpy(&sip,&(pHT->server[i].ip),sizeof(struct in_addr));
01700      sprintf(buf,"%s:%d",inet_ntoa(sip),pHT->server[i].port);
01701      log_printf(&(pWD->AppLog),"Connecting to server %s",buf);
01702      file_tcpconnect(&Client,buf);
01703      }
01704   }
01705 #endif
01706 

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