/*################################################################################### # # Embperl - Copyright (c) 1997-1998 Gerald Richter / ECOS # # You may distribute under the terms of either the GNU General Public # License or the Artistic License, as specified in the Perl README file. # For use with Apache httpd and mod_perl, see also Apache copyright. # # THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED # WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. # ###################################################################################*/ #include "ep.h" #include "epmacro.h" /* * Files */ #ifdef PerlIO #define FILEIOTYPE "PerlIO" static PerlIO * ifd = NULL ; /* input file */ static PerlIO * ofd = NULL ; /* output file */ static PerlIO * lfd = NULL ; /* log file */ #else #define FILEIOTYPE "StdIO" static FILE * ifd = NULL ; /* input file */ static FILE * ofd = NULL ; /* output file */ static FILE * lfd = NULL ; /* log file */ #endif static char sLogFilename [512] = "" ; #ifndef PerlIO /* define same helper macros to let it run with plain perl 5.003 */ /* where no PerlIO is present */ #define PerlIO_stdinF stdin #define PerlIO_stdoutF stdout #define PerlIO_stderrF stderr #define PerlIO_close fclose #define PerlIO_open fopen #define PerlIO_flush fflush #define PerlIO_vprintf vfprintf #define PerlIO_fileno fileno #define PerlIO_tell ftell #define PerlIO_read(f,buf,cnt) fread(buf,1,cnt,f) #define PerlIO_write(f,buf,cnt) fwrite(buf,1,cnt,f) #define PerlIO_putc(f,c) fputc(c,f) #else #define PerlIO_stdinF PerlIO_stdin () #define PerlIO_stdoutF PerlIO_stdout () #define PerlIO_stderrF PerlIO_stderr () #endif #ifdef APACHE #define DefaultLog "/tmp/embperl.log" #endif /* * Alloced memory for debugging */ size_t nAllocSize = 0 ; /* * Datastructure for buffering output */ static struct tBuf * pFirstBuf = NULL ; /* First buffer */ static struct tBuf * pLastBuf = NULL ; /* Last written buffer */ static struct tBuf * pFreeBuf = NULL ; /* List of unused buffers */ static struct tBuf * pLastFreeBuf = NULL ; /* End of list of unused buffers */ static char * pMemBuf ; /* temporary output */ static char * pMemBufPtr ; /* temporary output */ static size_t nMemBufSize ; /* size of pMemBuf */ static size_t nMemBufSizeFree ; /* remaining space in pMemBuf */ /* * Makers for rollback output */ int nMarker ; /* ------------------------------------------------------------------------------------- * * begin output transaction * -------------------------------------------------------------------------------------- */ struct tBuf * oBegin () { EPENTRY1N (oBegin, nMarker) ; nMarker++ ; return pLastBuf ; } /* ------------------------------------------------------------------------------------- * * rollback output transaction (throw away all the output since corresponding begin) * -------------------------------------------------------------------------------------- */ void oRollbackOutput (struct tBuf * pBuf) { EPENTRY1N (oRollback, nMarker) ; if (pBuf == NULL) { if (pLastFreeBuf) pLastFreeBuf -> pNext = pFirstBuf ; else pFreeBuf = pFirstBuf ; pLastFreeBuf = pLastBuf ; pFirstBuf = NULL ; nMarker = 0 ; } else { if (pLastBuf == pBuf || pBuf -> pNext == NULL) nMarker-- ; else { nMarker = pBuf -> pNext -> nMarker - 1 ; if (pLastFreeBuf) pLastFreeBuf -> pNext = pBuf -> pNext ; else pFreeBuf = pBuf -> pNext ; pLastFreeBuf = pLastBuf ; } pBuf -> pNext = NULL ; } pLastBuf = pBuf ; } /* ------------------------------------------------------------------------------------- * * rollback output transaction and errors(throw away all the output since corresponding * begin) * -------------------------------------------------------------------------------------- */ void oRollback (struct tBuf * pBuf) { oRollbackOutput (pBuf) ; RollbackError () ; } /* ---------------------------------------------------------------------------- */ /* */ /* commit output transaction (all the output since corresponding begin is vaild)*/ /* */ /* ---------------------------------------------------------------------------- */ void oCommitToMem (struct tBuf * pBuf, char * pOut) { EPENTRY1N (oCommit, nMarker) ; if (pBuf == NULL) nMarker = 0 ; else if (pLastBuf == pBuf) nMarker-- ; else nMarker = pBuf -> pNext -> nMarker - 1 ; if (nMarker == 0) { if (pBuf == NULL) pBuf = pFirstBuf ; else pBuf = pBuf -> pNext ; if (pOut) { while (pBuf) { memmove (pOut, pBuf + 1, pBuf -> nSize) ; pOut += pBuf -> nSize ; pBuf = pBuf -> pNext ; } *pOut = '\0' ; } else { while (pBuf) { owrite (pBuf + 1, 1, pBuf -> nSize) ; pBuf = pBuf -> pNext ; } } } CommitError () ; } /* ---------------------------------------------------------------------------- */ /* */ /* commit output transaction (all the output since corresponding begin is vaild)*/ /* */ /* ---------------------------------------------------------------------------- */ void oCommit (struct tBuf * pBuf) { EPENTRY1N (oCommit, nMarker) ; oCommitToMem (pBuf, NULL) ; } /* ---------------------------------------------------------------------------- */ /* */ /* write to a buffer */ /* */ /* we will alloc a new buffer for every write */ /* this is fast with apache palloc or for malloc if no free is call in between */ /* */ /* ---------------------------------------------------------------------------- */ static int bufwrite (/*in*/ const void * ptr, size_t size) { struct tBuf * pBuf ; EPENTRY1N (bufwrite, nMarker) ; pBuf = (struct tBuf *)_malloc (size + sizeof (struct tBuf)) ; if (pBuf == NULL) return 0 ; memcpy (pBuf + 1, ptr, size) ; pBuf -> pNext = NULL ; pBuf -> nSize = size ; pBuf -> nMarker = nMarker ; if (pLastBuf) { pLastBuf -> pNext = pBuf ; pBuf -> nCount = pLastBuf -> nCount + size ; } else pBuf -> nCount = size ; if (pFirstBuf == NULL) pFirstBuf = pBuf ; pLastBuf = pBuf ; return size ; } /* ---------------------------------------------------------------------------- */ /* */ /* free buffers */ /* */ /* free all buffers */ /* note: this is not nessecary for apache palloc, because all buffers are freed */ /* at the end of the request */ /* */ /* ---------------------------------------------------------------------------- */ static void buffree () { struct tBuf * pNext = NULL ; struct tBuf * pBuf ; #ifdef APACHE if ((bDebug & dbgMem) == 0 && pReq != NULL) { pFirstBuf = NULL ; pLastBuf = NULL ; pFreeBuf = NULL ; pLastFreeBuf = NULL ; return ; /* no need for apache to free memory */ } #endif /* first walk thru the used buffers */ pBuf = pFirstBuf ; while (pBuf) { pNext = pBuf -> pNext ; _free (pBuf) ; pBuf = pNext ; } pFirstBuf = NULL ; pLastBuf = NULL ; /* now walk thru the unused buffers */ pBuf = pFreeBuf ; while (pBuf) { pNext = pBuf -> pNext ; _free (pBuf) ; pBuf = pNext ; } pFreeBuf = NULL ; pLastFreeBuf = NULL ; } /* ---------------------------------------------------------------------------- */ /* */ /* get the length outputed to buffers so far */ /* */ /* ---------------------------------------------------------------------------- */ int GetContentLength () { if (pLastBuf) return pLastBuf -> nCount ; else return 0 ; } /* ---------------------------------------------------------------------------- */ /* */ /* set the name of the input file and open it */ /* */ /* ---------------------------------------------------------------------------- */ int OpenInput (/*in*/ const char * sFilename) { #ifdef APACHE if (pReq) return ok ; #endif if (ifd && ifd != PerlIO_stdinF) PerlIO_close (ifd) ; ifd = NULL ; if (sFilename == NULL || *sFilename == '\0') { /* GV * io = gv_fetchpv("STDIN", TRUE, SVt_PVIO) ; if (io == NULL || (ifd = IoIFP(io)) == NULL) { if (bDebug) lprintf ("[%d]Cannot get Perl STDIN, open os stdin\n", nPid) ; ifd = PerlIO_stdinF ; } */ ifd = PerlIO_stdinF ; return ok ; } if ((ifd = PerlIO_open (sFilename, "r")) == NULL) { strncpy (errdat1, sFilename, sizeof (errdat1) - 1) ; strncpy (errdat2, Strerror(errno), sizeof (errdat2) - 1) ; return rcFileOpenErr ; } return ok ; } /* ---------------------------------------------------------------------------- */ /* */ /* close input file */ /* */ /* ---------------------------------------------------------------------------- */ int CloseInput () { #ifdef APACHE if (pReq) return ok ; #endif if (ifd && ifd != PerlIO_stdinF) PerlIO_close (ifd) ; ifd = NULL ; return ok ; } /* ---------------------------------------------------------------------------- */ /* */ /* read block of data from input (web client) */ /* */ /* ---------------------------------------------------------------------------- */ int iread (/*in*/ void * ptr, size_t size, size_t nmemb) { int n = size * nmemb ; if (n == 0) return 0 ; #if defined (APACHE) if (pReq) { setup_client_block(pReq, REQUEST_CHUNKED_ERROR); if(should_client_block(pReq)) { int c = get_client_block(pReq, ptr, n); return c / size ; } else return 0 ; } #endif return PerlIO_read (ifd, ptr, n) ; } /* ---------------------------------------------------------------------------- */ /* */ /* read line of data from input (web client) */ /* */ /* ---------------------------------------------------------------------------- */ char * igets (/*in*/ char * s, int size) { #if defined (APACHE) if (pReq) return NULL ; #endif #ifdef PerlIO { /* FILE * f = PerlIO_exportFILE (ifd, 0) ; char * p = fgets (s, size, f) ; PerlIO_releaseFILE (ifd, f) ; return p ; */ return NULL ; } #else return fgets (s, size, ifd) ; #endif } /* ---------------------------------------------------------------------------- */ /* */ /* read HTML File into pBuf */ /* */ /* ---------------------------------------------------------------------------- */ int ReadHTML (/*in*/ char * sInputfile, /*in*/ size_t * nFileSize, /*out*/ SV * * ppBuf) { SV * pBufSV ; char * pData ; #ifdef PerlIO PerlIO * ifd ; #else FILE * ifd ; #endif if (bDebug) lprintf ("[%d]Reading %s as input using %s ...\n", nPid, sInputfile, FILEIOTYPE) ; #ifdef WIN32 if ((ifd = PerlIO_open (sInputfile, "rb")) == NULL) #else if ((ifd = PerlIO_open (sInputfile, "r")) == NULL) #endif { strncpy (errdat1, sInputfile, sizeof (errdat1) - 1) ; strncpy (errdat2, Strerror(errno), sizeof (errdat2) - 1) ; return rcFileOpenErr ; } pBufSV = sv_2mortal (newSV(*nFileSize + 1)) ; pData = SvPVX(pBufSV) ; *nFileSize = PerlIO_read (ifd, pData, *nFileSize) ; PerlIO_close (ifd) ; pData [*nFileSize] = '\0' ; SvCUR_set (pBufSV, *nFileSize) ; SvTEMP_off (pBufSV) ; SvPOK_on (pBufSV) ; *ppBuf = pBufSV ; return ok ; } /* ---------------------------------------------------------------------------- */ /* */ /* set the name of the output file and open it */ /* */ /* ---------------------------------------------------------------------------- */ int OpenOutput (/*in*/ const char * sFilename) { pFirstBuf = NULL ; pLastBuf = NULL ; nMarker = 0 ; pMemBuf = NULL ; nMemBufSize = 0 ; /* make sure all old buffers are freed */ buffree () ; #if defined (APACHE) if (pReq) { if (bDebug) lprintf ("[%d]Using APACHE for output...\n", nPid) ; return ok ; } #endif if (ofd && ofd != PerlIO_stdoutF) PerlIO_close (ofd) ; ofd = NULL ; if (sFilename == NULL || *sFilename == '\0') { /* GV * io = gv_fetchpv("STDOUT", TRUE, SVt_PVIO) ; if (io == NULL || (ofd = IoOFP(io)) == NULL) { if (bDebug) lprintf ("[%d]Cannot get Perl STDOUT, open os stdout\n", nPid) ; ofd = PerlIO_stdoutF ; } */ ofd = PerlIO_stdoutF ; if (bDebug) { #ifdef APACHE if (pReq) lprintf ("[%d]Open STDOUT to Apache for output...\n", nPid) ; else #endif lprintf ("[%d]Open STDOUT for output...\n", nPid) ; } return ok ; } if (bDebug) lprintf ("[%d]Open %s for output...\n", nPid, sFilename) ; #ifdef WIN32 if ((ofd = PerlIO_open (sFilename, "wb")) == NULL) #else if ((ofd = PerlIO_open (sFilename, "w")) == NULL) #endif { strncpy (errdat1, sFilename, sizeof (errdat1) - 1) ; strncpy (errdat2, Strerror(errno), sizeof (errdat2) - 1) ; return rcFileOpenErr ; } return ok ; } /* ---------------------------------------------------------------------------- */ /* */ /* close the output file */ /* */ /* ---------------------------------------------------------------------------- */ int CloseOutput () { /* make sure all buffers are freed */ buffree () ; #if defined (APACHE) if (pReq) return ok ; #endif if (ofd && ofd != PerlIO_stdoutF) PerlIO_close (ofd) ; ofd = NULL ; return ok ; } /* ---------------------------------------------------------------------------- */ /* */ /* set output to memory buffer */ /* */ /* ---------------------------------------------------------------------------- */ void OutputToMemBuf (/*in*/ char * pBuf, /*in*/ size_t nBufSize) { pMemBuf = pBuf ; pMemBufPtr = pBuf ; nMemBufSize = nBufSize ; nMemBufSizeFree = nBufSize ; } /* ---------------------------------------------------------------------------- */ /* */ /* set output to standard */ /* */ /* ---------------------------------------------------------------------------- */ char * OutputToStd () { char * p = pMemBuf ; pMemBuf = NULL ; nMemBufSize = 0 ; nMemBufSizeFree = 0 ; return p ; } /* ---------------------------------------------------------------------------- */ /* */ /* puts to output (web client) */ /* */ /* ---------------------------------------------------------------------------- */ int oputs (/*in*/ const char * str) { return owrite (str, 1, strlen (str)) ; } /* ---------------------------------------------------------------------------- */ /* */ /* write block of data to output (web client) */ /* */ /* ---------------------------------------------------------------------------- */ int owrite (/*in*/ const void * ptr, size_t size, size_t nmemb) { int n = size * nmemb ; if (n == 0) return 0 ; if (pMemBuf) { char * p ; int s = nMemBufSize ; if (n >= nMemBufSizeFree) { if (s < n) s = n + nMemBufSize ; nMemBufSize += s ; nMemBufSizeFree += s ; /*lprintf ("[%d]MEM: Realloc pMemBuf, nMemSize = %d\n", nPid, nMemBufSize) ; */ p = _realloc (pMemBuf, nMemBufSize) ; if (p == NULL) { nMemBufSize -= s ; nMemBufSizeFree -= s ; return 0 ; } pMemBufPtr = p + (pMemBufPtr - pMemBuf) ; pMemBuf = p ; } memcpy (pMemBufPtr, ptr, n) ; pMemBufPtr += n ; *pMemBufPtr = '\0' ; nMemBufSizeFree -= n ; return n / size ; } if (nMarker) return bufwrite (ptr, n) / size ; #if defined (APACHE) if (pReq) { if (n > 0) { n = rwrite (ptr, n, pReq) ; if (bDebug & dbgFlushOutput) rflush (pReq) ; return n / size ; } else return 0 ; } #endif if (n > 0) { n = PerlIO_write (ofd, (void *)ptr, size * nmemb) ; if (bDebug & dbgFlushOutput) PerlIO_flush (ofd) ; } return n / size ; } /* ---------------------------------------------------------------------------- */ /* */ /* write one char to output (web client) */ /* */ /* ---------------------------------------------------------------------------- */ void oputc (/*in*/ char c) { if (nMarker || pMemBuf) { owrite (&c, 1, 1) ; return ; } #if defined (APACHE) if (pReq) { rputc (c, pReq) ; if (bDebug & dbgFlushOutput) rflush (pReq) ; return ; } #endif PerlIO_putc (ofd, c) ; if (bDebug & dbgFlushOutput) PerlIO_flush (ofd) ; } /* ---------------------------------------------------------------------------- */ /* */ /* set the name of the log file and open it */ /* */ /* nMode = 0 open later, save filename only */ /* nMode = 1 open now */ /* nMode = 2 open with saved filename */ /* */ /* ---------------------------------------------------------------------------- */ int OpenLog (/*in*/ const char * sFilename, /*in*/ int nMode) { if (sFilename == NULL) sFilename = "" ; if (lfd && (nMode == 2 || strcmp (sLogFilename, sFilename) == 0)) return ok ; /*already open */ if (lfd && lfd != PerlIO_stdoutF) PerlIO_close (lfd) ; /* close old logfile */ lfd = NULL ; if (nMode != 2) { strncpy (sLogFilename, sFilename, sizeof (sLogFilename) - 1) ; sLogFilename[sizeof (sLogFilename) - 1] = '\0' ; } if (*sLogFilename == '\0') { sLogFilename[0] = '\0' ; lfd = PerlIO_stdoutF ; return ok ; } if (nMode == 0) return ok ; if ((lfd = PerlIO_open (sLogFilename, "a")) == NULL) { strncpy (errdat1, sLogFilename, sizeof (errdat1) - 1) ; strncpy (errdat2, Strerror(errno), sizeof (errdat2) - 1) ; return rcLogFileOpenErr ; } return ok ; } /* ---------------------------------------------------------------------------- */ /* */ /* return the handle of the log file */ /* */ /* ---------------------------------------------------------------------------- */ int GetLogHandle () { if (lfd) return PerlIO_fileno (lfd) ; return 0 ; } /* ---------------------------------------------------------------------------- */ /* */ /* return the current posittion of the log file */ /* */ /* ---------------------------------------------------------------------------- */ long GetLogFilePos () { if (lfd) return PerlIO_tell (lfd) ; return 0 ; } /* ---------------------------------------------------------------------------- */ /* */ /* close the log file */ /* */ /* ---------------------------------------------------------------------------- */ int CloseLog () { if (lfd && lfd != PerlIO_stdoutF) PerlIO_close (lfd) ; lfd = NULL ; return ok ; } /* ---------------------------------------------------------------------------- */ /* */ /* flush the log file */ /* */ /* ---------------------------------------------------------------------------- */ int FlushLog () { if (lfd != NULL) PerlIO_flush (lfd) ; return ok ; } /* ---------------------------------------------------------------------------- */ /* */ /* printf to log file */ /* */ /* ---------------------------------------------------------------------------- */ int lprintf (/*in*/ const char * sFormat, /*in*/ ...) { va_list ap ; int n ; if (lfd == NULL) return 0 ; va_start (ap, sFormat) ; { n = PerlIO_vprintf (lfd, sFormat, ap) ; if (bDebug & dbgFlushLog) PerlIO_flush (lfd) ; } va_end (ap) ; return n ; } /* ---------------------------------------------------------------------------- */ /* */ /* write block of data to log file */ /* */ /* ---------------------------------------------------------------------------- */ int lwrite (/*in*/ const void * ptr, size_t size, size_t nmemb) { int n ; if (lfd == NULL) return 0 ; n = PerlIO_write (lfd, (void *)ptr, size * nmemb) ; if (bDebug & dbgFlushLog) PerlIO_flush (lfd) ; return n ; } /* ---------------------------------------------------------------------------- */ /* */ /* Memory Allocation */ /* */ /* ---------------------------------------------------------------------------- */ void _free (void * p) { size_t size ; size_t * ps ; #ifdef APACHE if (pReq && !(bDebug & dbgMem)) return ; #endif /* we do it a bit complicted so it compiles also on aix */ ps = (size_t *)p ; ps-- ; size = *ps ; p = ps ; if (bDebug & dbgMem) { nAllocSize -= size ; lprintf ("[%d]MEM: Free %d Bytes at %08x Allocated so far %d Bytes\n" ,nPid, size, p, nAllocSize) ; } #ifdef APACHE if (pReq == NULL) #endif free (p) ; } void * _malloc (size_t size) { void * p ; size_t * ps ; #ifdef APACHE if (pReq) { p = palloc (pReq -> pool, size + sizeof (size)) ; } else #endif p = malloc (size + sizeof (size)) ; /* we do it a bit complicted so it compiles also on aix */ ps = (size_t *)p ; *ps = size ; p = ps + 1 ; if (bDebug & dbgMem) { nAllocSize += size ; lprintf ("[%d]MEM: Alloc %d Bytes at %08x Allocated so far %d Bytes\n" ,nPid, size, p, nAllocSize) ; } return p ; } void * _realloc (void * ptr, size_t size) { void * p ; size_t * ps ; size_t sizeold ; #ifdef APACHE if (pReq) { p = palloc (pReq -> pool, size + sizeof (size)) ; if (p == NULL) return NULL ; /* we do it a bit complicted so it compiles also on aix */ ps = (size_t *)p ; *ps = size ; p = ps + 1; ps = (size_t *)ptr ; ps-- ; sizeold = *ps ; memcpy (p, ptr, sizeold) ; } else #endif { ps = (size_t *)ptr ; ps-- ; p = realloc (ps, size + sizeof (size)) ; if (p == NULL) return NULL ; /* we do it a bit complicted so it compiles also on aix */ ps = (size_t *)p ; *ps = size ; p = ps + 1; } if (bDebug & dbgMem) { nAllocSize += size ; lprintf ("[%d]MEM: ReAlloc %d Bytes at %08x Allocated so far %d Bytes\n" ,nPid, size, p, nAllocSize) ; } return p ; } char * _memstrcat (const char *s, ...) { va_list ap ; char * p ; char * str ; char * sp ; int l ; int sum ; EPENTRY(_memstrcat) ; va_start(ap, s) ; p = s ; sum = 0 ; while (p) { sum += va_arg (ap, int) ; p = va_arg (ap, char *) ; } sum++ ; va_end (ap) ; sp = str = _malloc (sum+1) ; va_start(ap, s) ; p = s ; while (p) { l = va_arg (ap, int) ; memcpy (str, p, l) ; str += l ; p = va_arg (ap, char *) ; } *str = '\0' ; va_end (ap) ; return sp ; }