/*################################################################################### # # Embperl - Copyright (c) 1997-2008 Gerald Richter / ecos gmbh www.ecos.de # Embperl - Copyright (c) 2008-2015 Gerald Richter # Embperl - Copyright (c) 2015-2023 actevy.io # # 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" #include "crypto/epcrypto.h" #ifndef PerlIO #define FILEIOTYPE "StdIO" /* 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_seek fseek #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 FILEIOTYPE "PerlIO" #define PerlIO_stdinF PerlIO_stdin () #define PerlIO_stdoutF PerlIO_stdout () #define PerlIO_stderrF PerlIO_stderr () #endif /* Some helper macros for tied handles, taken from mod_perl 2.0 :-) */ /* * bleedperl change #11639 switch tied handle magic * from living in the gv to the GvIOp(gv), so we have to deal * with both to support 5.6.x */ #if ((PERL_REVISION == 5) && (PERL_VERSION >= 7)) # define TIEHANDLE_SV(handle) (SV*)GvIOp((SV*)handle) #else # define TIEHANDLE_SV(handle) (SV*)handle #endif #define HANDLE_GV(name) gv_fetchpv(name, TRUE, SVt_PVIO) //#define HANDLE_GV(name) gv_fetchpv(name, GV_ADD, SVt_PVIO) #ifdef APACHE #define DefaultLog "/tmp/embperl.log" static request_rec * pAllocReq = NULL ; #endif /* ------------------------------------------------------------------------------------- * * begin output transaction * -------------------------------------------------------------------------------------- */ struct tBuf * oBegin (/*i/o*/ register req * r) { EPENTRY1N (oBegin, r -> Component.pOutput -> nMarker) ; r -> Component.pOutput -> nMarker++ ; return r -> Component.pOutput -> pLastBuf ; } /* ------------------------------------------------------------------------------------- * * rollback output transaction (throw away all the output since corresponding begin) * -------------------------------------------------------------------------------------- */ void oRollbackOutput (/*i/o*/ register req * r, struct tBuf * pBuf) { EPENTRY1N (oRollback, r -> Component.pOutput -> nMarker) ; if (pBuf == NULL) { if (r -> Component.pOutput -> pLastFreeBuf) r -> Component.pOutput -> pLastFreeBuf -> pNext = r -> Component.pOutput -> pFirstBuf ; else r -> Component.pOutput -> pFreeBuf = r -> Component.pOutput -> pFirstBuf ; r -> Component.pOutput -> pLastFreeBuf = r -> Component.pOutput -> pLastBuf ; r -> Component.pOutput -> pFirstBuf = NULL ; r -> Component.pOutput -> nMarker = 0 ; } else { if (r -> Component.pOutput -> pLastBuf == pBuf || pBuf -> pNext == NULL) r -> Component.pOutput -> nMarker-- ; else { r -> Component.pOutput -> nMarker = pBuf -> pNext -> nMarker - 1 ; if (r -> Component.pOutput -> pLastFreeBuf) r -> Component.pOutput -> pLastFreeBuf -> pNext = pBuf -> pNext ; else r -> Component.pOutput -> pFreeBuf = pBuf -> pNext ; r -> Component.pOutput -> pLastFreeBuf = r -> Component.pOutput -> pLastBuf ; } pBuf -> pNext = NULL ; } r -> Component.pOutput -> pLastBuf = pBuf ; } /* ------------------------------------------------------------------------------------- * * rollback output transaction and errors(throw away all the output since corresponding * begin) * -------------------------------------------------------------------------------------- */ void oRollback (/*i/o*/ register req * r, struct tBuf * pBuf) { oRollbackOutput (r, pBuf) ; /* RollbackError (r) ; */ } /* ---------------------------------------------------------------------------- */ /* */ /* commit output transaction (all the output since corresponding begin is vaild)*/ /* */ /* ---------------------------------------------------------------------------- */ void oCommitToMem (/*i/o*/ register req * r, struct tBuf * pBuf, char * pOut) { EPENTRY1N (oCommit, r -> Component.pOutput -> nMarker) ; if (pBuf == NULL) r -> Component.pOutput -> nMarker = 0 ; else if (r -> Component.pOutput -> pLastBuf == pBuf) r -> Component.pOutput -> nMarker-- ; else r -> Component.pOutput -> nMarker = pBuf -> pNext -> nMarker - 1 ; if (r -> Component.pOutput -> nMarker == 0) { if (pBuf == NULL) pBuf = r -> Component.pOutput -> 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 (r, pBuf + 1, pBuf -> nSize) ; pBuf = pBuf -> pNext ; } } } /* CommitError (r) ; */ } /* ---------------------------------------------------------------------------- */ /* */ /* commit output transaction (all the output since corresponding begin is vaild)*/ /* */ /* ---------------------------------------------------------------------------- */ void oCommit (/*i/o*/ register req * r, struct tBuf * pBuf) { EPENTRY1N (oCommit, r -> Component.pOutput -> nMarker) ; oCommitToMem (r, pBuf, NULL) ; } /* ---------------------------------------------------------------------------- */ /* */ /* write to a buffer */ /* */ /* we will alloc a new buffer for every write */ /* this is fast with ep_palloc */ /* */ /* ---------------------------------------------------------------------------- */ static int bufwrite (/*i/o*/ register req * r, /*in*/ const void * ptr, size_t size) { struct tBuf * pBuf ; EPENTRY1N (bufwrite, r -> Component.pOutput -> nMarker) ; pBuf = (struct tBuf *)ep_palloc (r -> Component.pOutput -> pPool, size + sizeof (struct tBuf)) ; if (pBuf == NULL) return 0 ; memcpy (pBuf + 1, ptr, size) ; pBuf -> pNext = NULL ; pBuf -> nSize = size ; pBuf -> nMarker = r -> Component.pOutput -> nMarker ; if (r -> Component.pOutput -> pLastBuf) { r -> Component.pOutput -> pLastBuf -> pNext = pBuf ; pBuf -> nCount = r -> Component.pOutput -> pLastBuf -> nCount + size ; } else pBuf -> nCount = size ; if (r -> Component.pOutput -> pFirstBuf == NULL) r -> Component.pOutput -> pFirstBuf = pBuf ; r -> Component.pOutput -> pLastBuf = pBuf ; return size ; } #if 0 /* ---------------------------------------------------------------------------- */ /* */ /* 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 (/*i/o*/ register req * r) { struct tBuf * pNext = NULL ; struct tBuf * pBuf ; #ifdef APACHE if ((r -> Component.Config.bDebug & dbgMem) == 0 && pAllocReq != NULL) { r -> Component.pOutput -> pFirstBuf = NULL ; r -> Component.pOutput -> pLastBuf = NULL ; r -> Component.pOutput -> pFreeBuf = NULL ; r -> Component.pOutput -> pLastFreeBuf = NULL ; return ; /* no need for apache to free memory */ } #endif /* first walk thru the used buffers */ pBuf = r -> Component.pOutput -> pFirstBuf ; while (pBuf) { pNext = pBuf -> pNext ; _free (r, pBuf) ; pBuf = pNext ; } r -> Component.pOutput -> pFirstBuf = NULL ; r -> Component.pOutput -> pLastBuf = NULL ; /* now walk thru the unused buffers */ pBuf = r -> Component.pOutput -> pFreeBuf ; while (pBuf) { pNext = pBuf -> pNext ; _free (r, pBuf) ; pBuf = pNext ; } r -> Component.pOutput -> pFreeBuf = NULL ; r -> Component.pOutput -> pLastFreeBuf = NULL ; } #endif /* ---------------------------------------------------------------------------- */ /* */ /* get the length outputed to buffers so far */ /* */ /* ---------------------------------------------------------------------------- */ int GetContentLength (/*i/o*/ register req * r) { if (r -> Component.pOutput -> pLastBuf) return r -> Component.pOutput -> pLastBuf -> nCount ; else return 0 ; } /* ---------------------------------------------------------------------------- */ /* */ /* set the name of the input file and open it */ /* */ /* ---------------------------------------------------------------------------- */ int OpenInput (/*i/o*/ register req * r, /*in*/ const char * sFilename) { MAGIC *mg; GV *handle ; epTHX ; #ifdef APACHE if (r -> pApacheReq) return ok ; #endif handle = HANDLE_GV("STDIN") ; if (handle) { SV *iohandle = TIEHANDLE_SV(handle) ; if (iohandle && SvMAGICAL(iohandle) && (mg = mg_find((SV*)iohandle, 'q')) && mg->mg_obj) { r -> Component.ifdobj = mg->mg_obj ; if (r -> Component.Config.bDebug) { char *package = HvNAME(SvSTASH((SV*)SvRV(mg->mg_obj))); lprintf (r -> pApp, "[%d]Open TIED STDIN %s...\n", r -> pThread -> nPid, package) ; } return ok ; } } if (r -> Component.ifd && r -> Component.ifd != PerlIO_stdinF) PerlIO_close (r -> Component.ifd) ; r -> Component.ifd = NULL ; if (sFilename == NULL || *sFilename == '\0') { /* GV * io = gv_fetchpv("STDIN", TRUE, SVt_PVIO) ; if (io == NULL || (r -> Component.ifd = IoIFP(io)) == NULL) { if (r -> Component.Config.bDebug) lprintf (r -> pApp, "[%d]Cannot get Perl STDIN, open os stdin\n", r -> pThread -> nPid) ; r -> Component.ifd = PerlIO_stdinF ; } */ r -> Component.ifd = PerlIO_stdinF ; return ok ; } if ((r -> Component.ifd = PerlIO_open (sFilename, "r")) == NULL) { strncpy (r -> errdat1, sFilename, sizeof (r -> errdat1) - 1) ; strncpy (r -> errdat2, Strerror(errno), sizeof (r -> errdat2) - 1) ; return rcFileOpenErr ; } return ok ; } /* ---------------------------------------------------------------------------- */ /* */ /* close input file */ /* */ /* ---------------------------------------------------------------------------- */ int CloseInput (/*i/o*/ register req * r) { epTHX ; #if 0 if (0) /* r -> Component.ifdobj) */ { dSP; ENTER; SAVETMPS; PUSHMARK(sp); XPUSHs(r -> Component.ifdobj); PUTBACK; perl_call_method ("CLOSE", G_VOID | G_EVAL) ; SPAGAIN ; FREETMPS; LEAVE; r -> Component.ifdobj = NULL ; } #endif #ifdef APACHE if (r -> pApacheReq) return ok ; #endif if (r -> Component.ifd && r -> Component.ifd != PerlIO_stdinF) PerlIO_close (r -> Component.ifd) ; r -> Component.ifd = NULL ; return ok ; } /* ---------------------------------------------------------------------------- */ /* */ /* read block of data from input (web client) */ /* */ /* ---------------------------------------------------------------------------- */ int iread (/*i/o*/ register req * r, /*in*/ void * ptr, size_t size) { char * p = (char *)ptr ; /* workaround for aix c complier */ epTHX ; if (size == 0) return 0 ; if (r -> Component.ifdobj) { int num ; int n ; SV * pBufSV ; dSP; ENTER; SAVETMPS; PUSHMARK(sp); XPUSHs(r -> Component.ifdobj); XPUSHs(sv_2mortal(pBufSV = NEWSV(0, 0))); XPUSHs(sv_2mortal(newSViv (size))); PUTBACK; num = perl_call_method ("READ", G_SCALAR) ; SPAGAIN; n = 0 ; if (num > 0) { STRLEN n = POPu ; char * p ; STRLEN l ; if (n >= 0) { p = SvPV (pBufSV, l) ; if (l > size) l = size ; if (l > n) l = n ; memcpy (ptr, p, l) ; } } PUTBACK; FREETMPS; LEAVE; return n ; } #if defined (APACHE) if (r -> pApacheReq) { ap_setup_client_block(r -> pApacheReq, REQUEST_CHUNKED_ERROR); if(ap_should_client_block(r -> pApacheReq)) { int c ; int n = 0 ; while (1) { c = ap_get_client_block(r -> pApacheReq, p, size); if (c < 0 || c == 0) return n ; n += c ; p += c ; size -= c ; } } else return 0 ; } #endif return PerlIO_read (r -> Component.ifd, p, size) ; } /* ---------------------------------------------------------------------------- */ /* */ /* read line of data from input (web client) */ /* */ /* ---------------------------------------------------------------------------- */ char * igets (/*i/o*/ register req * r, /*in*/ char * s, int size) { #if defined (APACHE) if (r -> pApacheReq) return NULL ; #endif #ifdef PerlIO { /* FILE * f = PerlIO_exportFILE (r -> Component.ifd, 0) ; char * p = fgets (s, size, f) ; PerlIO_releaseFILE (r -> Component.ifd, f) ; return p ; */ return NULL ; } #else return fgets (s, size, r -> Component.ifd) ; #endif } /* ---------------------------------------------------------------------------- */ /* */ /* read HTML File into pBuf */ /* */ /* ---------------------------------------------------------------------------- */ int ReadHTML (/*i/o*/ register req * r, /*in*/ char * sInputfile, /*in*/ size_t * nFileSize, /*out*/ SV * * ppBuf) { SV * pBufSV ; char * pData ; #ifdef PerlIO PerlIO * ifd ; #else FILE * ifd ; #endif epTHX ; if (r -> Component.Config.bDebug) lprintf (r -> pApp, "[%d]Reading %s as input using %s (%d Bytes)...\n", r -> pThread -> nPid, sInputfile, FILEIOTYPE, *nFileSize) ; #ifdef WIN32 if ((ifd = PerlIO_open (sInputfile, "rb")) == NULL) #else if ((ifd = PerlIO_open (sInputfile, "r")) == NULL) #endif { strncpy (r -> errdat1, sInputfile, sizeof (r -> errdat1) - 1) ; strncpy (r -> errdat2, Strerror(errno), sizeof (r -> errdat2) - 1) ; if (errno == EACCES) return rcForbidden ; else if (errno == ENOENT) return rcNotFound ; return rcFileOpenErr ; } if ((long)*nFileSize < 0) return rcFileOpenErr ; pBufSV = sv_2mortal (newSV(*nFileSize + 1)) ; pData = SvPVX(pBufSV) ; #if EPC_ENABLE if (*nFileSize) { int rc ; char * syntax ; int fileno = PerlIO_fileno (ifd) ; FILE * ifile = fdopen(fileno, "r") ; if (!ifile) { strncpy (r -> errdat1, sInputfile, sizeof (r -> errdat1) - 1) ; strncpy (r -> errdat2, Strerror(errno), sizeof (r -> errdat2) - 1) ; return rcFileOpenErr ; } #ifndef EP2 syntax = (r -> Component.pTokenTable && strcmp ((char *)r -> Component.pTokenTable, "Text") == 0)?"Text":"Embperl" ; #else syntax = r -> Component.Config.sSyntax ; #endif if ((rc = do_crypt_file (ifile, NULL, pData, *nFileSize, 0, syntax, EPC_HEADER)) <= 0) { if (rc < -1 || !EPC_UNENCYRPTED) { sprintf (r -> errdat1, "%d", rc) ; return rcCryptoWrongHeader + -rc - 1; } PerlIO_seek (ifd, 0, SEEK_SET) ; *nFileSize = PerlIO_read (ifd, pData, *nFileSize) ; } else *nFileSize = rc ; fclose (ifile) ; } #else if (*nFileSize) *nFileSize = PerlIO_read (ifd, pData, *nFileSize) ; #endif 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 (/*i/o*/ register req * r, /*in*/ const char * sFilename) { MAGIC *mg; GV *handle ; epTHX ; r -> Component.pOutput -> pFirstBuf = NULL ; r -> Component.pOutput -> pLastBuf = NULL ; r -> Component.pOutput -> nMarker = 0 ; r -> Component.pOutput -> pMemBuf = NULL ; r -> Component.pOutput -> nMemBufSize = 0 ; r -> Component.pOutput -> pFreeBuf = NULL ; r -> Component.pOutput -> pLastFreeBuf = NULL ; if (r -> Component.pOutput -> ofd && r -> Component.pOutput -> ofd != PerlIO_stdoutF && !r -> Component.pOutput -> no_ofd_close) PerlIO_close (r -> Component.pOutput -> ofd) ; r -> Component.pOutput -> ofd = NULL ; r -> Component.pOutput -> no_ofd_close = 0 ; if (sFilename == NULL || *sFilename == '\0') { #if defined (APACHE) if (r -> pApacheReq) { if (r -> Component.Config.bDebug) lprintf (r -> pApp, "[%d]Using APACHE for output...\n", r -> pThread -> nPid) ; return ok ; } #endif handle = HANDLE_GV("STDOUT") ; if (handle) { SV *iohandle = TIEHANDLE_SV(handle) ; if (iohandle && SvMAGICAL(iohandle) && (mg = mg_find((SV*)iohandle, 'q')) && mg->mg_obj) { r -> Component.pOutput -> ofdobj = mg->mg_obj ; if (r -> Component.Config.bDebug) { char *package = HvNAME(SvSTASH((SV*)SvRV(mg->mg_obj))); lprintf (r -> pApp, "[%d]Open TIED STDOUT %s for output...\n", r -> pThread -> nPid, package) ; } return ok ; } r -> Component.pOutput -> ofd = IoOFP(GvIOn(handle)) ; if (r -> Component.pOutput -> ofd) { r -> Component.pOutput -> no_ofd_close = 1 ; return ok ; } } r -> Component.pOutput -> ofd = PerlIO_stdoutF ; if (r -> Component.Config.bDebug) { #ifdef APACHE if (r -> pApacheReq) lprintf (r -> pApp, "[%d]Open STDOUT to Apache for output...\n", r -> pThread -> nPid) ; else #endif lprintf (r -> pApp, "[%d]Open STDOUT for output...\n", r -> pThread -> nPid) ; } return ok ; } if (r -> Component.Config.bDebug) lprintf (r -> pApp, "[%d]Open %s for output...\n", r -> pThread -> nPid, sFilename) ; #ifdef WIN32 if ((r -> Component.pOutput -> ofd = PerlIO_open (sFilename, "wb")) == NULL) #else if ((r -> Component.pOutput -> ofd = PerlIO_open (sFilename, "w")) == NULL) #endif { strncpy (r -> errdat1, sFilename, sizeof (r -> errdat1) - 1) ; strncpy (r -> errdat2, Strerror(errno), sizeof (r -> errdat2) - 1) ; return rcFileOpenErr ; } return ok ; } /* ---------------------------------------------------------------------------- */ /* */ /* close the output file */ /* */ /* ---------------------------------------------------------------------------- */ int CloseOutput (/*in*/ tReq * r, tComponentOutput * pOutput) { epTHX ; if (!pOutput) return ok ; #if 0 if (0) /* r -> Component.pOutput -> ofdobj) */ { dSP; ENTER; SAVETMPS; PUSHMARK(sp); XPUSHs(pOutput -> ofdobj); PUTBACK; perl_call_method ("CLOSE", G_VOID | G_EVAL) ; SPAGAIN ; FREETMPS; LEAVE; pOutput -> ofdobj = NULL ; } #endif if (pOutput -> ofd && pOutput -> ofd != PerlIO_stdoutF && !pOutput -> no_ofd_close) PerlIO_close (pOutput -> ofd) ; pOutput -> ofd = NULL ; return ok ; } /* ---------------------------------------------------------------------------- */ /* */ /* set output to memory buffer */ /* */ /* ---------------------------------------------------------------------------- */ void OutputToMemBuf (/*i/o*/ register req * r, /*in*/ char * pBuf, /*in*/ size_t nBufSize) { if (pBuf == NULL) pBuf = ep_palloc (r -> Component.pOutput -> pPool, nBufSize) ; *pBuf = '\0' ; r -> Component.pOutput -> pMemBuf = pBuf ; r -> Component.pOutput -> pMemBufPtr = pBuf ; r -> Component.pOutput -> nMemBufSize = nBufSize ; r -> Component.pOutput -> nMemBufSizeFree = nBufSize ; } /* ---------------------------------------------------------------------------- */ /* */ /* set output to standard */ /* */ /* ---------------------------------------------------------------------------- */ char * OutputToStd (/*i/o*/ register req * r) { char * p = r -> Component.pOutput -> pMemBuf ; r -> Component.pOutput -> pMemBuf = NULL ; r -> Component.pOutput -> nMemBufSize = 0 ; r -> Component.pOutput -> nMemBufSizeFree = 0 ; return p ; } /* ---------------------------------------------------------------------------- */ /* */ /* puts to output (web client) */ /* */ /* ---------------------------------------------------------------------------- */ int oputs (/*i/o*/ register req * r, /*in*/ const char * str) { return owrite (r, str, strlen (str)) ; } /* ---------------------------------------------------------------------------- */ /* */ /* write block of data to output (web client) */ /* */ /* ---------------------------------------------------------------------------- */ int owrite (/*i/o*/ register req * r, /*in*/ const void * ptr, size_t size) { size_t n = size ; epTHX ; if (n == 0 || r -> Component.pOutput -> bDisableOutput) return 0 ; if (r -> Component.pOutput -> pMemBuf) { char * p ; size_t s = r -> Component.pOutput -> nMemBufSize ; if (n >= r -> Component.pOutput -> nMemBufSizeFree) { size_t oldsize = s ; if (s < n) s = n + r -> Component.pOutput -> nMemBufSize ; r -> Component.pOutput -> nMemBufSize += s ; r -> Component.pOutput -> nMemBufSizeFree += s ; /*lprintf (r -> pApp, "[%d]MEM: Realloc pMemBuf, nMemSize = %d\n", nPid, nMemBufSize) ; */ p = ep_palloc (r -> Component.pOutput -> pPool, r -> Component.pOutput -> nMemBufSize) ; if (p == NULL) { r -> Component.pOutput -> nMemBufSize -= s ; r -> Component.pOutput -> nMemBufSizeFree -= s ; return 0 ; } memcpy (p, r -> Component.pOutput -> pMemBuf, oldsize) ; r -> Component.pOutput -> pMemBufPtr = p + (r -> Component.pOutput -> pMemBufPtr - r -> Component.pOutput -> pMemBuf) ; r -> Component.pOutput -> pMemBuf = p ; } memcpy (r -> Component.pOutput -> pMemBufPtr, ptr, n) ; r -> Component.pOutput -> pMemBufPtr += n ; *(r -> Component.pOutput -> pMemBufPtr) = '\0' ; r -> Component.pOutput -> nMemBufSizeFree -= n ; return n ; } if (r -> Component.pOutput -> nMarker) return bufwrite (r, ptr, n) ; if (r -> Component.pOutput -> ofdobj) { dSP; ENTER; SAVETMPS; PUSHMARK(sp); XPUSHs(r -> Component.pOutput -> ofdobj); XPUSHs(sv_2mortal(newSVpv((char *)ptr,size))); PUTBACK; perl_call_method ("PRINT", G_SCALAR) ; SPAGAIN ; FREETMPS; LEAVE; return size ; } #if defined (APACHE) if (r -> pApacheReq && r -> Component.pOutput -> ofd == NULL) { if (n > 0) { n = ap_rwrite (ptr, n, r -> pApacheReq) ; if (r -> Component.Config.bDebug & dbgFlushOutput) ap_rflush (r -> pApacheReq) ; return n ; } else return 0 ; } #endif if (n > 0 && r -> Component.pOutput -> ofd) { n = PerlIO_write (r -> Component.pOutput -> ofd, (void *)ptr, size) ; if (r -> Component.Config.bDebug & dbgFlushOutput) PerlIO_flush (r -> Component.pOutput -> ofd) ; } return n ; } /* ---------------------------------------------------------------------------- */ /* */ /* flush output */ /* */ /* ---------------------------------------------------------------------------- */ void oflush (/*i/o*/ register req * r) { epTHX_ #if defined (APACHE) if (r -> pApacheReq && r -> Component.pOutput -> ofd == NULL) { ap_rflush (r -> pApacheReq) ; return ; } #endif if (r -> Component.pOutput -> ofd) { PerlIO_flush (r -> Component.pOutput -> ofd) ; } return ; } /* ---------------------------------------------------------------------------- */ /* */ /* write one char to output (web client) */ /* */ /* ---------------------------------------------------------------------------- */ void oputc (/*i/o*/ register req * r, /*in*/ char c) { epTHX ; if (r -> Component.pOutput -> nMarker || r -> Component.pOutput -> pMemBuf || r -> Component.pOutput -> ofdobj) { owrite (r, &c, 1) ; return ; } #if defined (APACHE) if (r -> pApacheReq && r -> Component.pOutput -> ofd == NULL) { ap_rputc (c, r -> pApacheReq) ; if (r -> Component.Config.bDebug & dbgFlushOutput) ap_rflush (r -> pApacheReq) ; return ; } #endif PerlIO_putc (r -> Component.pOutput -> ofd, c) ; if (r -> Component.Config.bDebug & dbgFlushOutput) PerlIO_flush (r -> Component.pOutput -> ofd) ; } /* ---------------------------------------------------------------------------- */ /* */ /* log file open */ /* */ /* ---------------------------------------------------------------------------- */ int OpenLog (/*i/o*/ tApp * a) { epaTHX ; if (a -> lfd) return ok ; /*already open */ if (a -> lfd && a -> lfd != PerlIO_stdoutF) PerlIO_close (a -> lfd) ; /* close old logfile */ a -> lfd = NULL ; if (a -> Config.bDebug == 0) return ok ; /* never write to logfile if debugging is disabled */ if (!a -> Config.sLog && a -> Config.sLog[0] == '\0') { a -> lfd = PerlIO_stdoutF ; return ok ; } if ((a -> lfd = PerlIO_open (a -> Config.sLog, "a")) == NULL) { tReq * r = a -> pThread -> pCurrReq ; if (r) { strncpy (r -> errdat1, a -> Config.sLog, sizeof (r -> errdat1) - 1) ; strncpy (r -> errdat2, Strerror(errno), sizeof (r -> errdat2) - 1) ; } return rcLogFileOpenErr ; } return ok ; } /* ---------------------------------------------------------------------------- */ /* */ /* return the handle of the log file */ /* */ /* ---------------------------------------------------------------------------- */ int GetLogHandle (/*i/o*/ tApp * a) { epaTHX ; if (a -> lfd) return PerlIO_fileno (a -> lfd) ; return 0 ; } /* ---------------------------------------------------------------------------- */ /* */ /* return the current posittion of the log file */ /* */ /* ---------------------------------------------------------------------------- */ long GetLogFilePos (/*i/o*/ tApp * a) { epaTHX ; if (a -> lfd) return PerlIO_tell (a -> lfd) ; return 0 ; } /* ---------------------------------------------------------------------------- */ /* */ /* close the log file */ /* */ /* ---------------------------------------------------------------------------- */ int CloseLog (/*i/o*/ tApp * a) { epaTHX ; if (a -> lfd && a -> lfd != PerlIO_stdoutF) PerlIO_close (a -> lfd) ; a -> lfd = NULL ; return ok ; } /* ---------------------------------------------------------------------------- */ /* */ /* flush the log file */ /* */ /* ---------------------------------------------------------------------------- */ int FlushLog (/*i/o*/ tApp * a) { epaTHX ; if (a -> lfd != NULL) PerlIO_flush (a -> lfd) ; return ok ; } /* ---------------------------------------------------------------------------- */ /* */ /* printf to log file */ /* */ /* ---------------------------------------------------------------------------- */ int lprintf (/*i/o*/ tApp * a, /*in*/ const char * sFormat, /*in*/ ...) { va_list ap ; int n ; epaTHX ; if (a -> lfd == NULL) return 0 ; va_start (ap, sFormat) ; { n = PerlIO_vprintf (a -> lfd, sFormat, ap) ; if (a -> Config.bDebug & dbgFlushLog) PerlIO_flush (a -> lfd) ; } va_end (ap) ; return n ; } /* ---------------------------------------------------------------------------- */ /* */ /* write block of data to log file */ /* */ /* ---------------------------------------------------------------------------- */ int lwrite (/*i/o*/ tApp * a, /*in*/ const void * ptr, /*in*/ size_t size) { int n ; epaTHX ; if (a -> lfd == NULL) return 0 ; n = PerlIO_write (a -> lfd, (void *)ptr, size) ; if (a -> Config.bDebug & dbgFlushLog) PerlIO_flush (a -> lfd) ; return n ; } /* ---------------------------------------------------------------------------- */ /* */ /* Memory Allocation */ /* */ /* ---------------------------------------------------------------------------- */ void _free (/*i/o*/ register req * r, void * p) { #ifdef APACHE if (pAllocReq && !(r -> Component.Config.bDebug & dbgMem)) return ; #endif #ifdef ALLOCSIZE if (r -> Component.Config.bDebug & dbgMem) { size_t size ; size_t * ps ; /* we do it a bit complicted so it compiles also on aix */ ps = (size_t *)p ; ps-- ; size = *ps ; p = ps ; r -> nAllocSize -= size ; lprintf (r -> pApp, "[%d]MEM: Free %d Bytes at %08x Allocated so far %d Bytes\n" ,r -> pThread -> nPid, size, p, r -> nAllocSize) ; } #endif #ifdef APACHE if (r -> pApacheReq == NULL) #endif { epTHX ; free (p) ; } } void * _malloc (/*i/o*/ register req * r, size_t size) { void * p ; #ifdef APACHE pAllocReq = r -> pApacheReq ; if (r -> pApacheReq) { p = apr_palloc (r -> pApacheReq -> pool, size + sizeof (size)) ; } else #endif { epTHX ; p = malloc (size + sizeof (size)) ; } #ifdef ALLOCSIZE if (r -> Component.Config.bDebug & dbgMem) { size_t * ps ; /* we do it a bit complicted so it compiles also on aix */ ps = (size_t *)p ; *ps = size ; p = ps + 1 ; r -> nAllocSize += size ; lprintf (r -> pApp, "[%d]MEM: Alloc %d Bytes at %08x Allocated so far %d Bytes\n" ,r -> pThread -> nPid, size, p, r -> nAllocSize) ; } #endif return p ; } void * _realloc (/*i/o*/ register req * r, void * ptr, size_t oldsize, size_t size) { void * p ; #ifdef APACHE if (r -> pApacheReq) { p = apr_palloc (r -> pApacheReq -> pool, size + sizeof (size)) ; if (p == NULL) return NULL ; #ifdef ALLOCSIZE if (r -> Component.Config.bDebug & dbgMem) { size_t * ps ; size_t sizeold ; /* 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 ; r -> nAllocSize += size - sizeold ; lprintf (r -> pApp, "[%d]MEM: ReAlloc %d Bytes at %08x Allocated so far %d Bytes\n" ,r -> pThread -> nPid, size, p, r -> nAllocSize) ; } #endif memcpy (p, ptr, oldsize) ; } else #endif #ifdef ALLOCSIZE if (r -> Component.Config.bDebug & dbgMem) { size_t * ps ; ps = (size_t *)ptr ; ps-- ; r -> nAllocSize -= *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; r -> nAllocSize += size ; lprintf (r -> pApp, "[%d]MEM: ReAlloc %d Bytes at %08x Allocated so far %d Bytes\n" ,r -> pThread -> nPid, size, p, r -> nAllocSize) ; } else #endif { epTHX ; p = realloc (ptr, size + sizeof (size)) ; } return p ; } char * _memstrcat (/*i/o*/ register req * r, const char *s, ...) { va_list ap ; char * p ; char * str ; char * sp ; int l ; int sum ; EPENTRY(_memstrcat) ; va_start(ap, s) ; p = (char *)s ; sum = 0 ; while (p) { sum += strlen (p) ; lprintf (r -> pApp, "sum = %d p = %s\n", sum, p) ; p = va_arg (ap, char *) ; } sum++ ; va_end (ap) ; sp = str = _malloc (r, sum+1) ; va_start(ap, s) ; p = (char *)s ; while (p) { l = strlen (p) ; lprintf (r -> pApp, "l = %d p = %s\n", l, p) ; memcpy (str, p, l) ; str += l ; p = va_arg (ap, char *) ; } *str = '\0' ; va_end (ap) ; return sp ; } char * _ep_strdup (/*i/o*/ register req * r, /*in*/ const char * str) { char * p ; int len = strlen (str) ; p = (char *)_malloc (r, len + 1) ; if (p) strcpy (p, str) ; return p ; } char * _ep_strndup (/*i/o*/ register req * r, /*in*/ const char * str, /*in*/ int len) { char * p ; p = (char *)_malloc (r, len + 1) ; if (p) { strncpy (p, str, len) ; p[len] = '\0' ; } return p ; } char * _ep_memdup (/*i/o*/ register req * r, /*in*/ const char * str, /*in*/ int len) { char * p ; p = (char *)_malloc (r, len + 1) ; if (p) { memcpy (p, str, len) ; p[len] = '\0' ; } return p ; }