FCGI-0.74/0000711000175000017500000000000011637307650010606 5ustar raflraflFCGI-0.74/version.pm0000644000175000017500000000004211637307546012641 0ustar raflraflpackage FCGI; $VERSION = '0.74'; FCGI-0.74/README0000644000175000017500000000501211417356077011477 0ustar raflrafl$Id: README,v 1.7 2001/10/04 08:08:34 skimo Exp $ Copyright (c) 1996 Open Market, Inc. See the file "LICENSE.TERMS" for information on usage and redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES. Copyright (c) 1996-1998 Sven Verdoolaege No additional restrictions/warranties. This is a Fast CGI module for perl. It's based on the FCGI module that comes with Open Market's FastCGI Developer's Kit, but does not require you to recompile perl. It even no longer requires perl to be compiled with sfio. To compile with sfio you'll need at least perl 5.003_02 and you'll have to have configured it with eg './Configure -Duseperlio -Dusesfio'. (See the INSTALL file that comes with the perl distribution.) To compile without sfio you'll need an even more recent perl version. (perl 5.004 and up should be fine.) See http://www.fastcgi.com/ for more information about fastcgi. Lincoln D. Stein's perl CGI module also contains some information about fastcgi programming. See echo.fpl for an example on how to use this module. To install, do the usual perl Makefile.PL make make install If you want to use the (experimental) pure perl version, that doesn't require a compiler and currently only works on Unix, you have to pass the --pure-perl option as in "perl Makefile.PL --pure-perl". Note that the pure version does not support Window's Named Pipes. Support for Named Pipes is not a requirement of the FastCGI specification. Named Pipes are used by mod_fastcgi and the FastCGI application library as a replacement for Unix sockets. mod_fastcgi uses Named Pipes on Windows (Unix sockets on Unix) by default (see the mod_fastcgi docs for more information). If you want the module to use a previously installed fcgi library instead of the included files, use the --use-installed option, optionally followed by the name of the directory in which it can be found. To configure the library Makefile.PL will run ./configure . You may want to run it yourself beforehand because its findings may not always be correct. The configure.readme file describes how to run ./configure (and only that). If you're on a solaris system and your installed fcgi library is 2.02b or earlier, you'll probably want to use the included files. The old interface of the FCGI module installs die and warn handlers that merely print the error/warning to STDERR (the default handlers print directly to stderr, which isn't redirected in the non sfio case). I'm not very happy with the result. Suggestions welcome. Sven Verdoolaege skimo@kotnet.org FCGI-0.74/echo.PL0000644000175000017500000000331211417356077011773 0ustar raflrafluse Config; open OUT, ">echo.fpl"; print OUT "#!$Config{perlpath}\n"; print OUT while ; close OUT; chmod 0755, "echo.fpl"; __END__ # # echo-perl -- # # Produce a page containing all FastCGI inputs # # Copyright (c) 1996 Open Market, Inc. # # See the file "LICENSE.TERMS" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # $Id: echo.PL,v 1.2 2000/12/14 13:46:23 skimo Exp $ # # Changed by skimo to demostrate autoflushing 1997/02/19 # use FCGI; use strict; sub print_env { my($label, $envp) = @_; print("$label:
\n
\n");
    my @keys = sort keys(%$envp);
    foreach my $key (@keys) {
        print("$key=$$envp{$key}\n");
    }
    print("

\n"); } my %env; my $req = FCGI::Request(\*STDIN, \*STDOUT, \*STDERR, \%env); my $count = 0; while($req->Accept() >= 0) { print("Content-type: text/html\r\n\r\n", "FastCGI echo (Perl)\n", "

FastCGI echo (Perl)

\n", "Request number ", ++$count, "

\n"); my $len = 0 + $env{'CONTENT_LENGTH'}; if($len == 0) { print("No data from standard input.

\n"); } else { print("Standard input:
\n

\n");
        for(my $i = 0; $i < $len; $i++) {
            my $ch = getc(STDIN);
            if($ch eq "") {
                print("Error: Not enough bytes received ",
                      "on standard input

\n"); last; } print($ch); } print("\n

\n"); } print_env("Request environment", \%env); print "More on its way ... wait a few seconds\n
\n
"; $req->Flush(); sleep(3); print_env("Initial environment", \%ENV); $req->Finish(); } FCGI-0.74/fcgiapp.c0000600000175000017500000021526411637307650012375 0ustar raflrafl/* * fcgiapp.c -- * * FastCGI application library: request-at-a-time * * * Copyright (c) 1996 Open Market, Inc. * * See the file "LICENSE.TERMS" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * */ #ifndef lint static const char rcsid[] = "$Id: fcgiapp.c,v 1.35 2003/06/22 00:16:43 robs Exp $"; #endif /* not lint */ #include #include #include /* for fcntl */ #include #include /* for memchr() */ #include #include #include #include #include #include "fcgi_config.h" #ifdef HAVE_SYS_SOCKET_H #include /* for getpeername */ #endif #ifdef HAVE_SYS_TIME_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_LIMITS_H #include #endif #ifdef _WIN32 #define DLLAPI __declspec(dllexport) #endif #include "fcgimisc.h" #include "fastcgi.h" #include "fcgios.h" #include "fcgiapp.h" /* * This is a workaround for one version of the HP C compiler * (c89 on HP-UX 9.04, also Stratus FTX), which will dump core * if given 'long double' for varargs. */ #ifdef HAVE_VA_ARG_LONG_DOUBLE_BUG #define LONG_DOUBLE double #else #define LONG_DOUBLE long double #endif /* * Globals */ static int libInitialized = 0; static int isFastCGI = -1; static char *webServerAddressList = NULL; static FCGX_Request the_request; void FCGX_ShutdownPending(void) { OS_ShutdownPending(); } static void *Malloc(size_t size) { void *result = malloc(size); ASSERT(size == 0 || result != NULL); return result; } static char *StringCopy(char *str) { int strLen = strlen(str); char *newString = (char *)Malloc(strLen + 1); memcpy(newString, str, strLen); newString[strLen] = '\000'; return newString; } /* *---------------------------------------------------------------------- * * FCGX_GetChar -- * * Reads a byte from the input stream and returns it. * * Results: * The byte, or EOF (-1) if the end of input has been reached. * *---------------------------------------------------------------------- */ int FCGX_GetChar(FCGX_Stream *stream) { if (stream->isClosed || ! stream->isReader) return EOF; if (stream->rdNext != stream->stop) return *stream->rdNext++; stream->fillBuffProc(stream); if (stream->isClosed) return EOF; stream->stopUnget = stream->rdNext; if (stream->rdNext != stream->stop) return *stream->rdNext++; ASSERT(stream->isClosed); /* bug in fillBufProc if not */ return EOF; } /* *---------------------------------------------------------------------- * * FCGX_GetStr -- * * Reads up to n consecutive bytes from the input stream * into the character array str. Performs no interpretation * of the input bytes. * * Results: * Number of bytes read. If result is smaller than n, * the end of input has been reached. * *---------------------------------------------------------------------- */ int FCGX_GetStr(char *str, int n, FCGX_Stream *stream) { int m, bytesMoved; if (stream->isClosed || ! stream->isReader || n <= 0) { return 0; } /* * Fast path: n bytes are already available */ if(n <= (stream->stop - stream->rdNext)) { memcpy(str, stream->rdNext, n); stream->rdNext += n; return n; } /* * General case: stream is closed or buffer fill procedure * needs to be called */ bytesMoved = 0; for (;;) { if(stream->rdNext != stream->stop) { m = min(n - bytesMoved, stream->stop - stream->rdNext); memcpy(str, stream->rdNext, m); bytesMoved += m; stream->rdNext += m; if(bytesMoved == n) return bytesMoved; str += m; } if(stream->isClosed || !stream->isReader) return bytesMoved; stream->fillBuffProc(stream); if (stream->isClosed) return bytesMoved; stream->stopUnget = stream->rdNext; } } /* *---------------------------------------------------------------------- * * FCGX_GetLine -- * * Reads up to n-1 consecutive bytes from the input stream * into the character array str. Stops before n-1 bytes * have been read if '\n' or EOF is read. The terminating '\n' * is copied to str. After copying the last byte into str, * stores a '\0' terminator. * * Results: * NULL if EOF is the first thing read from the input stream, * str otherwise. * *---------------------------------------------------------------------- */ char *FCGX_GetLine(char *str, int n, FCGX_Stream *stream) { int c; char *p = str; n--; while (n > 0) { c = FCGX_GetChar(stream); if(c == EOF) { if(p == str) return NULL; else break; } *p++ = (char) c; n--; if(c == '\n') break; } *p = '\0'; return str; } /* *---------------------------------------------------------------------- * * FCGX_UnGetChar -- * * Pushes back the character c onto the input stream. One * character of pushback is guaranteed once a character * has been read. No pushback is possible for EOF. * * Results: * Returns c if the pushback succeeded, EOF if not. * *---------------------------------------------------------------------- */ int FCGX_UnGetChar(int c, FCGX_Stream *stream) { if(c == EOF || stream->isClosed || !stream->isReader || stream->rdNext == stream->stopUnget) return EOF; --(stream->rdNext); *stream->rdNext = (unsigned char) c; return c; } /* *---------------------------------------------------------------------- * * FCGX_HasSeenEOF -- * * Returns EOF if end-of-file has been detected while reading * from stream; otherwise returns 0. * * Note that FCGX_HasSeenEOF(s) may return 0, yet an immediately * following FCGX_GetChar(s) may return EOF. This function, like * the standard C stdio function feof, does not provide the * ability to peek ahead. * * Results: * EOF if end-of-file has been detected, 0 if not. * *---------------------------------------------------------------------- */ int FCGX_HasSeenEOF(FCGX_Stream *stream) { return (stream->isClosed) ? EOF : 0; } /* *---------------------------------------------------------------------- * * FCGX_PutChar -- * * Writes a byte to the output stream. * * Results: * The byte, or EOF (-1) if an error occurred. * *---------------------------------------------------------------------- */ int FCGX_PutChar(int c, FCGX_Stream *stream) { if(stream->wrNext != stream->stop) return (*stream->wrNext++ = (unsigned char) c); if(stream->isClosed || stream->isReader) return EOF; stream->emptyBuffProc(stream, FALSE); if(stream->wrNext != stream->stop) return (*stream->wrNext++ = (unsigned char) c); ASSERT(stream->isClosed); /* bug in emptyBuffProc if not */ return EOF; } /* *---------------------------------------------------------------------- * * FCGX_PutStr -- * * Writes n consecutive bytes from the character array str * into the output stream. Performs no interpretation * of the output bytes. * * Results: * Number of bytes written (n) for normal return, * EOF (-1) if an error occurred. * *---------------------------------------------------------------------- */ int FCGX_PutStr(const char *str, int n, FCGX_Stream *stream) { int m, bytesMoved; /* * Fast path: room for n bytes in the buffer */ if(n <= (stream->stop - stream->wrNext)) { memcpy(stream->wrNext, str, n); stream->wrNext += n; return n; } /* * General case: stream is closed or buffer empty procedure * needs to be called */ bytesMoved = 0; for (;;) { if(stream->wrNext != stream->stop) { m = min(n - bytesMoved, stream->stop - stream->wrNext); memcpy(stream->wrNext, str, m); bytesMoved += m; stream->wrNext += m; if(bytesMoved == n) return bytesMoved; str += m; } if(stream->isClosed || stream->isReader) return -1; stream->emptyBuffProc(stream, FALSE); } } /* *---------------------------------------------------------------------- * * FCGX_PutS -- * * Writes a character string to the output stream. * * Results: * number of bytes written for normal return, * EOF (-1) if an error occurred. * *---------------------------------------------------------------------- */ int FCGX_PutS(const char *str, FCGX_Stream *stream) { return FCGX_PutStr(str, strlen(str), stream); } /* *---------------------------------------------------------------------- * * FCGX_FPrintF -- * * Performs output formatting and writes the results * to the output stream. * * Results: * number of bytes written for normal return, * EOF (-1) if an error occurred. * *---------------------------------------------------------------------- */ int FCGX_FPrintF(FCGX_Stream *stream, const char *format, ...) { int result; va_list ap; va_start(ap, format); result = FCGX_VFPrintF(stream, format, ap); va_end(ap); return result; } /* *---------------------------------------------------------------------- * * FCGX_VFPrintF -- * * Performs output formatting and writes the results * to the output stream. * * Results: * number of bytes written for normal return, * EOF (-1) if an error occurred. * *---------------------------------------------------------------------- */ #define PRINTF_BUFFLEN 100 /* * More than sufficient space for all unmodified conversions * except %s and %f. */ #define FMT_BUFFLEN 25 /* * Max size of a format specifier is 1 + 5 + 7 + 7 + 2 + 1 + slop */ static void CopyAndAdvance(char **destPtr, char **srcPtr, int n); int FCGX_VFPrintF(FCGX_Stream *stream, const char *format, va_list arg) { char *f, *fStop, *percentPtr, *p, *fmtBuffPtr, *buffPtr; int op, performedOp, sizeModifier, buffCount = 0, buffLen, specifierLength; int fastPath, n, auxBuffLen = 0, buffReqd, minWidth, precision, exp; char *auxBuffPtr = NULL; int streamCount = 0; char fmtBuff[FMT_BUFFLEN]; char buff[PRINTF_BUFFLEN]; int intArg; short shortArg; long longArg; unsigned unsignedArg; unsigned long uLongArg; unsigned short uShortArg; char *charPtrArg = NULL; void *voidPtrArg; int *intPtrArg; long *longPtrArg; short *shortPtrArg; double doubleArg = 0.0; LONG_DOUBLE lDoubleArg = 0.0L; fmtBuff[0] = '%'; f = (char *) format; fStop = f + strlen(f); while (f != fStop) { percentPtr = (char *)memchr(f, '%', fStop - f); if(percentPtr == NULL) percentPtr = fStop; if(percentPtr != f) { if(FCGX_PutStr(f, percentPtr - f, stream) < 0) goto ErrorReturn; streamCount += percentPtr - f; f = percentPtr; if(f == fStop) break; } fastPath = TRUE; /* * The following loop always executes either once or twice. */ for (;;) { if(fastPath) { /* * Fast path: Scan optimistically, hoping that no flags, * minimum field width, or precision are specified. * Use the preallocated buffer, which is large enough * for all fast path cases. If the conversion specifier * is really more complex, run the loop a second time * using the slow path. * Note that fast path execution of %s bypasses the buffer * and %f is not attempted on the fast path due to * its large buffering requirements. */ op = *(percentPtr + 1); switch(op) { case 'l': case 'L': case 'h': sizeModifier = op; op = *(percentPtr + 2); fmtBuff[1] = (char) sizeModifier; fmtBuff[2] = (char) op; fmtBuff[3] = '\0'; specifierLength = 3; break; default: sizeModifier = ' '; fmtBuff[1] = (char) op; fmtBuff[2] = '\0'; specifierLength = 2; break; } buffPtr = buff; buffLen = PRINTF_BUFFLEN; } else { /* * Slow path: Scan the conversion specifier and construct * a new format string, compute an upper bound on the * amount of buffering that sprintf will require, * and allocate a larger buffer if necessary. */ p = percentPtr + 1; fmtBuffPtr = &fmtBuff[1]; /* * Scan flags */ n = strspn(p, "-0+ #"); if(n > 5) goto ErrorReturn; CopyAndAdvance(&fmtBuffPtr, &p, n); /* * Scan minimum field width */ n = strspn(p, "0123456789"); if(n == 0) { if(*p == '*') { minWidth = va_arg(arg, int); if(abs(minWidth) > 999999) goto ErrorReturn; /* * The following use of strlen rather than the * value returned from sprintf is because SUNOS4 * returns a char * instead of an int count. */ sprintf(fmtBuffPtr, "%d", minWidth); fmtBuffPtr += strlen(fmtBuffPtr); p++; } else { minWidth = 0; } } else if(n <= 6) { minWidth = strtol(p, NULL, 10); CopyAndAdvance(&fmtBuffPtr, &p, n); } else { goto ErrorReturn; } /* * Scan precision */ if(*p == '.') { CopyAndAdvance(&fmtBuffPtr, &p, 1); n = strspn(p, "0123456789"); if(n == 0) { if(*p == '*') { precision = va_arg(arg, int); if(precision < 0) precision = 0; if(precision > 999999) goto ErrorReturn; /* * The following use of strlen rather than the * value returned from sprintf is because SUNOS4 * returns a char * instead of an int count. */ sprintf(fmtBuffPtr, "%d", precision); fmtBuffPtr += strlen(fmtBuffPtr); p++; } else { precision = 0; } } else if(n <= 6) { precision = strtol(p, NULL, 10); CopyAndAdvance(&fmtBuffPtr, &p, n); } else { goto ErrorReturn; } } else { precision = -1; } /* * Scan size modifier and conversion operation */ switch(*p) { case 'l': case 'L': case 'h': sizeModifier = *p; CopyAndAdvance(&fmtBuffPtr, &p, 1); break; default: sizeModifier = ' '; break; } op = *p; CopyAndAdvance(&fmtBuffPtr, &p, 1); ASSERT(fmtBuffPtr - fmtBuff < FMT_BUFFLEN); *fmtBuffPtr = '\0'; specifierLength = p - percentPtr; /* * Bound the required buffer size. For s and f * conversions this requires examining the argument. */ switch(op) { case 'd': case 'i': case 'u': case 'o': case 'x': case 'X': case 'c': case 'p': buffReqd = max(precision, 46); break; case 's': charPtrArg = va_arg(arg, char *); if (!charPtrArg) charPtrArg = "(null)"; if(precision == -1) { buffReqd = strlen(charPtrArg); } else { p = (char *)memchr(charPtrArg, '\0', precision); buffReqd = (p == NULL) ? precision : p - charPtrArg; } break; case 'f': switch(sizeModifier) { case ' ': doubleArg = va_arg(arg, double); frexp(doubleArg, &exp); break; case 'L': lDoubleArg = va_arg(arg, LONG_DOUBLE); /* XXX Need to check for the presence of * frexpl() and use it if available */ frexp((double) lDoubleArg, &exp); break; default: goto ErrorReturn; } if(precision == -1) precision = 6; buffReqd = precision + 3 + ((exp > 0) ? exp/3 : 0); break; case 'e': case 'E': case 'g': case 'G': if(precision == -1) precision = 6; buffReqd = precision + 8; break; case 'n': case '%': default: goto ErrorReturn; break; } buffReqd = max(buffReqd + 10, minWidth); /* * Allocate the buffer */ if(buffReqd <= PRINTF_BUFFLEN) { buffPtr = buff; buffLen = PRINTF_BUFFLEN; } else { if(auxBuffPtr == NULL || buffReqd > auxBuffLen) { if(auxBuffPtr != NULL) free(auxBuffPtr); auxBuffPtr = (char *)Malloc(buffReqd); auxBuffLen = buffReqd; if(auxBuffPtr == NULL) goto ErrorReturn; } buffPtr = auxBuffPtr; buffLen = auxBuffLen; } } /* * This giant switch statement requires the following variables * to be set up: op, sizeModifier, arg, buffPtr, fmtBuff. * When fastPath == FALSE and op == 's' or 'f', the argument * has been read into charPtrArg, doubleArg, or lDoubleArg. * The statement produces the boolean performedOp, TRUE iff * the op/sizeModifier were executed and argument consumed; * if performedOp, the characters written into buffPtr[] * and the character count buffCount (== EOF meaning error). * * The switch cases are arranged in the same order as in the * description of fprintf in section 15.11 of Harbison and Steele. */ performedOp = TRUE; switch(op) { case 'd': case 'i': switch(sizeModifier) { case ' ': intArg = va_arg(arg, int); sprintf(buffPtr, fmtBuff, intArg); buffCount = strlen(buffPtr); break; case 'l': longArg = va_arg(arg, long); sprintf(buffPtr, fmtBuff, longArg); buffCount = strlen(buffPtr); break; case 'h': shortArg = (short) va_arg(arg, int); sprintf(buffPtr, fmtBuff, shortArg); buffCount = strlen(buffPtr); break; default: goto ErrorReturn; } break; case 'u': case 'o': case 'x': case 'X': switch(sizeModifier) { case ' ': unsignedArg = va_arg(arg, unsigned); sprintf(buffPtr, fmtBuff, unsignedArg); buffCount = strlen(buffPtr); break; case 'l': uLongArg = va_arg(arg, unsigned long); sprintf(buffPtr, fmtBuff, uLongArg); buffCount = strlen(buffPtr); break; case 'h': uShortArg = (unsigned short) va_arg(arg, int); sprintf(buffPtr, fmtBuff, uShortArg); buffCount = strlen(buffPtr); break; default: goto ErrorReturn; } break; case 'c': switch(sizeModifier) { case ' ': intArg = va_arg(arg, int); sprintf(buffPtr, fmtBuff, intArg); buffCount = strlen(buffPtr); break; case 'l': /* * XXX: Allowed by ISO C Amendment 1, but * many platforms don't yet support wint_t */ goto ErrorReturn; default: goto ErrorReturn; } break; case 's': switch(sizeModifier) { case ' ': if(fastPath) { buffPtr = va_arg(arg, char *); buffCount = strlen(buffPtr); buffLen = buffCount + 1; } else { sprintf(buffPtr, fmtBuff, charPtrArg); buffCount = strlen(buffPtr); } break; case 'l': /* * XXX: Don't know how to convert a sequence * of wide characters into a byte stream, or * even how to predict the buffering required. */ goto ErrorReturn; default: goto ErrorReturn; } break; case 'p': if(sizeModifier != ' ') goto ErrorReturn; voidPtrArg = va_arg(arg, void *); sprintf(buffPtr, fmtBuff, voidPtrArg); buffCount = strlen(buffPtr); break; case 'n': switch(sizeModifier) { case ' ': intPtrArg = va_arg(arg, int *); *intPtrArg = streamCount; break; case 'l': longPtrArg = va_arg(arg, long *); *longPtrArg = streamCount; break; case 'h': shortPtrArg = (short *) va_arg(arg, short *); *shortPtrArg = (short) streamCount; break; default: goto ErrorReturn; } buffCount = 0; break; case 'f': if(fastPath) { performedOp = FALSE; break; } switch(sizeModifier) { case ' ': sprintf(buffPtr, fmtBuff, doubleArg); buffCount = strlen(buffPtr); break; case 'L': sprintf(buffPtr, fmtBuff, lDoubleArg); buffCount = strlen(buffPtr); break; default: goto ErrorReturn; } break; case 'e': case 'E': case 'g': case 'G': switch(sizeModifier) { case ' ': doubleArg = va_arg(arg, double); sprintf(buffPtr, fmtBuff, doubleArg); buffCount = strlen(buffPtr); break; case 'L': lDoubleArg = va_arg(arg, LONG_DOUBLE); sprintf(buffPtr, fmtBuff, lDoubleArg); buffCount = strlen(buffPtr); break; default: goto ErrorReturn; } break; case '%': if(sizeModifier != ' ') goto ErrorReturn; buff[0] = '%'; buffCount = 1; break; case '\0': goto ErrorReturn; default: performedOp = FALSE; break; } /* switch(op) */ if(performedOp) break; if(!fastPath) goto ErrorReturn; fastPath = FALSE; } /* for (;;) */ ASSERT(buffCount < buffLen); if(buffCount > 0) { if(FCGX_PutStr(buffPtr, buffCount, stream) < 0) goto ErrorReturn; streamCount += buffCount; } else if(buffCount < 0) { goto ErrorReturn; } f += specifierLength; } /* while(f != fStop) */ goto NormalReturn; ErrorReturn: streamCount = -1; NormalReturn: if(auxBuffPtr != NULL) free(auxBuffPtr); return streamCount; } /* * Copy n characters from *srcPtr to *destPtr, then increment * both *srcPtr and *destPtr by n. */ static void CopyAndAdvance(char **destPtr, char **srcPtr, int n) { char *dest = *destPtr; char *src = *srcPtr; int i; for (i = 0; i < n; i++) *dest++ = *src++; *destPtr = dest; *srcPtr = src; } /* *---------------------------------------------------------------------- * * FCGX_FFlush -- * * Flushes any buffered output. * * Server-push is a legitimate application of FCGX_FFlush. * Otherwise, FCGX_FFlush is not very useful, since FCGX_Accept * does it implicitly. FCGX_FFlush may reduce performance * by increasing the total number of operating system calls * the application makes. * * Results: * EOF (-1) if an error occurred. * *---------------------------------------------------------------------- */ int FCGX_FFlush(FCGX_Stream *stream) { if(stream->isClosed || stream->isReader) return 0; stream->emptyBuffProc(stream, FALSE); return (stream->isClosed) ? -1 : 0; } /* *---------------------------------------------------------------------- * * FCGX_FClose -- * * Performs FCGX_FFlush and closes the stream. * * This is not a very useful operation, since FCGX_Accept * does it implicitly. Closing the out stream before the * err stream results in an extra write if there's nothing * in the err stream, and therefore reduces performance. * * Results: * EOF (-1) if an error occurred. * *---------------------------------------------------------------------- */ int FCGX_FClose(FCGX_Stream *stream) { if (stream == NULL) return 0; if(!stream->wasFCloseCalled) { if(!stream->isReader) { stream->emptyBuffProc(stream, TRUE); } stream->wasFCloseCalled = TRUE; stream->isClosed = TRUE; if(stream->isReader) { stream->wrNext = stream->stop = stream->rdNext; } else { stream->rdNext = stream->stop = stream->wrNext; } } return (stream->FCGI_errno == 0) ? 0 : EOF; } /* *---------------------------------------------------------------------- * * SetError -- * * An error has occurred; save the error code in the stream * for diagnostic purposes and set the stream state so that * reads return EOF and writes have no effect. * *---------------------------------------------------------------------- */ static void SetError(FCGX_Stream *stream, int FCGI_errno) { /* * Preserve only the first error. */ if(stream->FCGI_errno == 0) { stream->FCGI_errno = FCGI_errno; } stream->isClosed = TRUE; } /* *---------------------------------------------------------------------- * * FCGX_GetError -- * * Return the stream error code. 0 means no error, > 0 * is an errno(2) error, < 0 is an FCGX_errno error. * *---------------------------------------------------------------------- */ int FCGX_GetError(FCGX_Stream *stream) { return stream->FCGI_errno; } /* *---------------------------------------------------------------------- * * FCGX_ClearError -- * * Clear the stream error code and end-of-file indication. * *---------------------------------------------------------------------- */ void FCGX_ClearError(FCGX_Stream *stream) { stream->FCGI_errno = 0; /* * stream->isClosed = FALSE; * XXX: should clear isClosed but work is needed to make it safe * to do so. For example, if an application calls FClose, gets * an I/O error on the write, calls ClearError and retries * the FClose, FClose (really EmptyBuffProc) will write a second * EOF record. If an application calls PutChar instead of FClose * after the ClearError, the application will write more data. * The stream's state must discriminate between various states * of the stream that are now all lumped under isClosed. */ } /* *====================================================================== * Parameters *====================================================================== */ /* * A vector of pointers representing the parameters received * by a FastCGI application server, with the vector's length * and last valid element so adding new parameters is efficient. */ typedef struct Params { FCGX_ParamArray vec; /* vector of strings */ int length; /* number of string vec can hold */ char **cur; /* current item in vec; *cur == NULL */ } Params; typedef Params *ParamsPtr; /* *---------------------------------------------------------------------- * * NewParams -- * * Creates a new Params structure. * * Results: * Pointer to the new structure. * *---------------------------------------------------------------------- */ static ParamsPtr NewParams(int length) { ParamsPtr result; result = (Params *)Malloc(sizeof(Params)); result->vec = (char **)Malloc(length * sizeof(char *)); result->length = length; result->cur = result->vec; *result->cur = NULL; return result; } /* *---------------------------------------------------------------------- * * FreeParams -- * * Frees a Params structure and all the parameters it contains. * * Side effects: * env becomes invalid. * *---------------------------------------------------------------------- */ static void FreeParams(ParamsPtr *paramsPtrPtr) { ParamsPtr paramsPtr = *paramsPtrPtr; char **p; if(paramsPtr == NULL) { return; } for (p = paramsPtr->vec; p < paramsPtr->cur; p++) { free(*p); } free(paramsPtr->vec); free(paramsPtr); *paramsPtrPtr = NULL; } /* *---------------------------------------------------------------------- * * PutParam -- * * Add a name/value pair to a Params structure. * * Results: * None. * * Side effects: * Parameters structure updated. * *---------------------------------------------------------------------- */ static void PutParam(ParamsPtr paramsPtr, char *nameValue) { int size; *paramsPtr->cur++ = nameValue; size = paramsPtr->cur - paramsPtr->vec; if(size >= paramsPtr->length) { paramsPtr->length *= 2; paramsPtr->vec = (FCGX_ParamArray)realloc(paramsPtr->vec, paramsPtr->length * sizeof(char *)); paramsPtr->cur = paramsPtr->vec + size; } *paramsPtr->cur = NULL; } /* *---------------------------------------------------------------------- * * FCGX_GetParam -- obtain value of FCGI parameter in environment * * * Results: * Value bound to name, NULL if name not present in the * environment envp. Caller must not mutate the result * or retain it past the end of this request. * *---------------------------------------------------------------------- */ char *FCGX_GetParam(const char *name, FCGX_ParamArray envp) { int len; char **p; if (name == NULL || envp == NULL) return NULL; len = strlen(name); for (p = envp; *p; ++p) { if((strncmp(name, *p, len) == 0) && ((*p)[len] == '=')) { return *p+len+1; } } return NULL; } /* *---------------------------------------------------------------------- * * Start of FastCGI-specific code * *---------------------------------------------------------------------- */ /* *---------------------------------------------------------------------- * * ReadParams -- * * Reads FastCGI name-value pairs from stream until EOF. Converts * each pair to name=value format and adds it to Params structure. * *---------------------------------------------------------------------- */ static int ReadParams(Params *paramsPtr, FCGX_Stream *stream) { int nameLen, valueLen; unsigned char lenBuff[3]; char *nameValue; while((nameLen = FCGX_GetChar(stream)) != EOF) { /* * Read name length (one or four bytes) and value length * (one or four bytes) from stream. */ if((nameLen & 0x80) != 0) { if(FCGX_GetStr((char *) &lenBuff[0], 3, stream) != 3) { SetError(stream, FCGX_PARAMS_ERROR); return -1; } nameLen = ((nameLen & 0x7f) << 24) + (lenBuff[0] << 16) + (lenBuff[1] << 8) + lenBuff[2]; } if((valueLen = FCGX_GetChar(stream)) == EOF) { SetError(stream, FCGX_PARAMS_ERROR); return -1; } if((valueLen & 0x80) != 0) { if(FCGX_GetStr((char *) &lenBuff[0], 3, stream) != 3) { SetError(stream, FCGX_PARAMS_ERROR); return -1; } valueLen = ((valueLen & 0x7f) << 24) + (lenBuff[0] << 16) + (lenBuff[1] << 8) + lenBuff[2]; } /* * nameLen and valueLen are now valid; read the name and value * from stream and construct a standard environment entry. */ nameValue = (char *)Malloc(nameLen + valueLen + 2); if(FCGX_GetStr(nameValue, nameLen, stream) != nameLen) { SetError(stream, FCGX_PARAMS_ERROR); free(nameValue); return -1; } *(nameValue + nameLen) = '='; if(FCGX_GetStr(nameValue + nameLen + 1, valueLen, stream) != valueLen) { SetError(stream, FCGX_PARAMS_ERROR); free(nameValue); return -1; } *(nameValue + nameLen + valueLen + 1) = '\0'; PutParam(paramsPtr, nameValue); } return 0; } /* *---------------------------------------------------------------------- * * MakeHeader -- * * Constructs an FCGI_Header struct. * *---------------------------------------------------------------------- */ static FCGI_Header MakeHeader( int type, int requestId, int contentLength, int paddingLength) { FCGI_Header header; ASSERT(contentLength >= 0 && contentLength <= FCGI_MAX_LENGTH); ASSERT(paddingLength >= 0 && paddingLength <= 0xff); header.version = FCGI_VERSION_1; header.type = (unsigned char) type; header.requestIdB1 = (unsigned char) ((requestId >> 8) & 0xff); header.requestIdB0 = (unsigned char) ((requestId ) & 0xff); header.contentLengthB1 = (unsigned char) ((contentLength >> 8) & 0xff); header.contentLengthB0 = (unsigned char) ((contentLength ) & 0xff); header.paddingLength = (unsigned char) paddingLength; header.reserved = 0; return header; } /* *---------------------------------------------------------------------- * * MakeEndRequestBody -- * * Constructs an FCGI_EndRequestBody struct. * *---------------------------------------------------------------------- */ static FCGI_EndRequestBody MakeEndRequestBody( int appStatus, int protocolStatus) { FCGI_EndRequestBody body; body.appStatusB3 = (unsigned char) ((appStatus >> 24) & 0xff); body.appStatusB2 = (unsigned char) ((appStatus >> 16) & 0xff); body.appStatusB1 = (unsigned char) ((appStatus >> 8) & 0xff); body.appStatusB0 = (unsigned char) ((appStatus ) & 0xff); body.protocolStatus = (unsigned char) protocolStatus; memset(body.reserved, 0, sizeof(body.reserved)); return body; } /* *---------------------------------------------------------------------- * * MakeUnknownTypeBody -- * * Constructs an FCGI_MakeUnknownTypeBody struct. * *---------------------------------------------------------------------- */ static FCGI_UnknownTypeBody MakeUnknownTypeBody( int type) { FCGI_UnknownTypeBody body; body.type = (unsigned char) type; memset(body.reserved, 0, sizeof(body.reserved)); return body; } /* *---------------------------------------------------------------------- * * AlignInt8 -- * * Returns the smallest integer greater than or equal to n * that's a multiple of 8. * *---------------------------------------------------------------------- */ static int AlignInt8(unsigned n) { return (n + 7) & (UINT_MAX - 7); } /* *---------------------------------------------------------------------- * * AlignPtr8 -- * * Returns the smallest pointer greater than or equal to p * that's a multiple of 8. * *---------------------------------------------------------------------- */ static unsigned char *AlignPtr8(unsigned char *p) { unsigned long u = (unsigned long) p; u = ((u + 7) & (ULONG_MAX - 7)) - u; return p + u; } /* * State associated with a stream */ typedef struct FCGX_Stream_Data { unsigned char *buff; /* buffer after alignment */ int bufflen; /* number of bytes buff can store */ unsigned char *mBuff; /* buffer as returned by Malloc */ unsigned char *buffStop; /* reader: last valid byte + 1 of entire buffer. * stop generally differs from buffStop for * readers because of record structure. * writer: buff + bufflen */ int type; /* reader: FCGI_PARAMS or FCGI_STDIN * writer: FCGI_STDOUT or FCGI_STDERR */ int eorStop; /* reader: stop stream at end-of-record */ int skip; /* reader: don't deliver content bytes */ int contentLen; /* reader: bytes of unread content */ int paddingLen; /* reader: bytes of unread padding */ int isAnythingWritten; /* writer: data has been written to ipcFd */ int rawWrite; /* writer: write data without stream headers */ FCGX_Request *reqDataPtr; /* request data not specific to one stream */ } FCGX_Stream_Data; /* *---------------------------------------------------------------------- * * WriteCloseRecords -- * * Writes an EOF record for the stream content if necessary. * If this is the last writer to close, writes an FCGI_END_REQUEST * record. * *---------------------------------------------------------------------- */ static void WriteCloseRecords(struct FCGX_Stream *stream) { FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data; /* * Enter rawWrite mode so final records won't be encapsulated as * stream data. */ data->rawWrite = TRUE; /* * Generate EOF for stream content if needed. */ if(!(data->type == FCGI_STDERR && stream->wrNext == data->buff && !data->isAnythingWritten)) { FCGI_Header header; header = MakeHeader(data->type, data->reqDataPtr->requestId, 0, 0); FCGX_PutStr((char *) &header, sizeof(header), stream); }; /* * Generate FCGI_END_REQUEST record if needed. */ if(data->reqDataPtr->nWriters == 1) { FCGI_EndRequestRecord endRequestRecord; endRequestRecord.header = MakeHeader(FCGI_END_REQUEST, data->reqDataPtr->requestId, sizeof(endRequestRecord.body), 0); endRequestRecord.body = MakeEndRequestBody( data->reqDataPtr->appStatus, FCGI_REQUEST_COMPLETE); FCGX_PutStr((char *) &endRequestRecord, sizeof(endRequestRecord), stream); } data->reqDataPtr->nWriters--; } static int write_it_all(int fd, char *buf, int len) { int wrote; while (len) { wrote = OS_Write(fd, buf, len); if (wrote < 0) return wrote; len -= wrote; buf += wrote; } return len; } /* *---------------------------------------------------------------------- * * EmptyBuffProc -- * * Encapsulates any buffered stream content in a FastCGI * record. Writes the data, making the buffer empty. * *---------------------------------------------------------------------- */ static void EmptyBuffProc(struct FCGX_Stream *stream, int doClose) { FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data; int cLen, eLen; /* * If the buffer contains stream data, fill in the header. * Pad the record to a multiple of 8 bytes in length. Padding * can't overflow the buffer because the buffer is a multiple * of 8 bytes in length. If the buffer contains no stream * data, reclaim the space reserved for the header. */ if(!data->rawWrite) { cLen = stream->wrNext - data->buff - sizeof(FCGI_Header); if(cLen > 0) { eLen = AlignInt8(cLen); /* * Giving the padding a well-defined value keeps Purify happy. */ memset(stream->wrNext, 0, eLen - cLen); stream->wrNext += eLen - cLen; *((FCGI_Header *) data->buff) = MakeHeader(data->type, data->reqDataPtr->requestId, cLen, eLen - cLen); } else { stream->wrNext = data->buff; } } if(doClose) { WriteCloseRecords(stream); }; if (stream->wrNext != data->buff) { data->isAnythingWritten = TRUE; if (write_it_all(data->reqDataPtr->ipcFd, (char *)data->buff, stream->wrNext - data->buff) < 0) { SetError(stream, OS_Errno); return; } stream->wrNext = data->buff; } /* * The buffer is empty. */ if(!data->rawWrite) { stream->wrNext += sizeof(FCGI_Header); } } /* * Return codes for Process* functions */ #define STREAM_RECORD 0 #define SKIP 1 #define BEGIN_RECORD 2 #define MGMT_RECORD 3 /* *---------------------------------------------------------------------- * * ProcessManagementRecord -- * * Reads and responds to a management record. The only type of * management record this library understands is FCGI_GET_VALUES. * The only variables that this library's FCGI_GET_VALUES * understands are FCGI_MAX_CONNS, FCGI_MAX_REQS, and FCGI_MPXS_CONNS. * Ignore other FCGI_GET_VALUES variables; respond to other * management records with a FCGI_UNKNOWN_TYPE record. * *---------------------------------------------------------------------- */ static int ProcessManagementRecord(int type, FCGX_Stream *stream) { FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data; ParamsPtr paramsPtr = NewParams(3); char **pPtr; char response[64]; /* 64 = 8 + 3*(1+1+14+1)* + padding */ char *responseP = &response[FCGI_HEADER_LEN]; char *name, value = '\0'; int len, paddedLen; if(type == FCGI_GET_VALUES) { ReadParams(paramsPtr, stream); if((FCGX_GetError(stream) != 0) || (data->contentLen != 0)) { FreeParams(¶msPtr); return FCGX_PROTOCOL_ERROR; } for (pPtr = paramsPtr->vec; pPtr < paramsPtr->cur; pPtr++) { name = *pPtr; *(strchr(name, '=')) = '\0'; if(strcmp(name, FCGI_MAX_CONNS) == 0) { value = '1'; } else if(strcmp(name, FCGI_MAX_REQS) == 0) { value = '1'; } else if(strcmp(name, FCGI_MPXS_CONNS) == 0) { value = '0'; } else { name = NULL; } if(name != NULL) { len = strlen(name); sprintf(responseP, "%c%c%s%c", len, 1, name, value); responseP += len + 3; } } len = responseP - &response[FCGI_HEADER_LEN]; paddedLen = AlignInt8(len); *((FCGI_Header *) response) = MakeHeader(FCGI_GET_VALUES_RESULT, FCGI_NULL_REQUEST_ID, len, paddedLen - len); FreeParams(¶msPtr); } else { paddedLen = len = sizeof(FCGI_UnknownTypeBody); ((FCGI_UnknownTypeRecord *) response)->header = MakeHeader(FCGI_UNKNOWN_TYPE, FCGI_NULL_REQUEST_ID, len, 0); ((FCGI_UnknownTypeRecord *) response)->body = MakeUnknownTypeBody(type); } if (write_it_all(data->reqDataPtr->ipcFd, response, FCGI_HEADER_LEN + paddedLen) < 0) { SetError(stream, OS_Errno); return -1; } return MGMT_RECORD; } /* *---------------------------------------------------------------------- * * ProcessBeginRecord -- * * Reads an FCGI_BEGIN_REQUEST record. * * Results: * BEGIN_RECORD for normal return. FCGX_PROTOCOL_ERROR for * protocol error. SKIP for attempt to multiplex * connection. -1 for error from write (errno in stream). * * Side effects: * In case of BEGIN_RECORD return, stores requestId, role, * keepConnection values, and sets isBeginProcessed = TRUE. * *---------------------------------------------------------------------- */ static int ProcessBeginRecord(int requestId, FCGX_Stream *stream) { FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data; FCGI_BeginRequestBody body; if(requestId == 0 || data->contentLen != sizeof(body)) { return FCGX_PROTOCOL_ERROR; } if(data->reqDataPtr->isBeginProcessed) { /* * The Web server is multiplexing the connection. This library * doesn't know how to handle multiplexing, so respond with * FCGI_END_REQUEST{protocolStatus = FCGI_CANT_MPX_CONN} */ FCGI_EndRequestRecord endRequestRecord; endRequestRecord.header = MakeHeader(FCGI_END_REQUEST, requestId, sizeof(endRequestRecord.body), 0); endRequestRecord.body = MakeEndRequestBody(0, FCGI_CANT_MPX_CONN); if (write_it_all(data->reqDataPtr->ipcFd, (char *)&endRequestRecord, sizeof(endRequestRecord)) < 0) { SetError(stream, OS_Errno); return -1; } return SKIP; } /* * Accept this new request. Read the record body. */ data->reqDataPtr->requestId = requestId; if(FCGX_GetStr((char *) &body, sizeof(body), stream) != sizeof(body)) { return FCGX_PROTOCOL_ERROR; } data->reqDataPtr->keepConnection = (body.flags & FCGI_KEEP_CONN); data->reqDataPtr->role = (body.roleB1 << 8) + body.roleB0; data->reqDataPtr->isBeginProcessed = TRUE; return BEGIN_RECORD; } /* *---------------------------------------------------------------------- * * ProcessHeader -- * * Interprets FCGI_Header. Processes FCGI_BEGIN_REQUEST and * management records here; extracts information from stream * records (FCGI_PARAMS, FCGI_STDIN) into stream. * * Results: * >= 0 for a normal return, < 0 for error * * Side effects: * XXX: Many (more than there used to be). * If !stream->isRequestIdSet, ProcessHeader initializes * stream->requestId from header and sets stream->isRequestIdSet * to TRUE. ProcessHeader also sets stream->contentLen to header's * contentLength, and sets stream->paddingLen to the header's * paddingLength. * *---------------------------------------------------------------------- */ static int ProcessHeader(FCGI_Header header, FCGX_Stream *stream) { FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data; int requestId; if(header.version != FCGI_VERSION_1) { return FCGX_UNSUPPORTED_VERSION; } requestId = (header.requestIdB1 << 8) + header.requestIdB0; data->contentLen = (header.contentLengthB1 << 8) + header.contentLengthB0; data->paddingLen = header.paddingLength; if(header.type == FCGI_BEGIN_REQUEST) { return ProcessBeginRecord(requestId, stream); } if(requestId == FCGI_NULL_REQUEST_ID) { return ProcessManagementRecord(header.type, stream); } if(requestId != data->reqDataPtr->requestId) { return SKIP; } if(header.type != data->type) { return FCGX_PROTOCOL_ERROR; } return STREAM_RECORD; } /* *---------------------------------------------------------------------- * * FillBuffProc -- * * Reads bytes from the ipcFd, supplies bytes to a stream client. * *---------------------------------------------------------------------- */ static void FillBuffProc(FCGX_Stream *stream) { FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data; FCGI_Header header; int headerLen = 0; int status, count; for (;;) { /* * If data->buff is empty, do a read. */ if(stream->rdNext == data->buffStop) { count = OS_Read(data->reqDataPtr->ipcFd, (char *)data->buff, data->bufflen); if(count <= 0) { SetError(stream, (count == 0 ? FCGX_PROTOCOL_ERROR : OS_Errno)); return; } stream->rdNext = data->buff; data->buffStop = data->buff + count; } /* * Now data->buff is not empty. If the current record contains * more content bytes, deliver all that are present in data->buff. */ if(data->contentLen > 0) { count = min(data->contentLen, data->buffStop - stream->rdNext); data->contentLen -= count; if(!data->skip) { stream->wrNext = stream->stop = stream->rdNext + count; return; } else { stream->rdNext += count; if(data->contentLen > 0) { continue; } else { data->skip = FALSE; } } } /* * If the current record (whose content has been fully consumed by * the client) was padded, skip over the padding bytes. */ if(data->paddingLen > 0) { count = min(data->paddingLen, data->buffStop - stream->rdNext); data->paddingLen -= count; stream->rdNext += count; if(data->paddingLen > 0) { continue; } } /* * All done with the current record, including the padding. * If we're in a recursive call from ProcessHeader, deliver EOF. */ if(data->eorStop) { stream->stop = stream->rdNext; stream->isClosed = TRUE; return; } /* * Fill header with bytes from the input buffer. */ count = min((int)sizeof(header) - headerLen, data->buffStop - stream->rdNext); memcpy(((char *)(&header)) + headerLen, stream->rdNext, count); headerLen += count; stream->rdNext += count; if(headerLen < sizeof(header)) { continue; }; headerLen = 0; /* * Interpret header. eorStop prevents ProcessHeader from reading * past the end-of-record when using stream to read content. */ data->eorStop = TRUE; stream->stop = stream->rdNext; status = ProcessHeader(header, stream); data->eorStop = FALSE; stream->isClosed = FALSE; switch(status) { case STREAM_RECORD: /* * If this stream record header marked the end of stream * data deliver EOF to the stream client, otherwise loop * and deliver data. * * XXX: If this is final stream and * stream->rdNext != data->buffStop, buffered * data is next request (server pipelining)? */ if(data->contentLen == 0) { stream->wrNext = stream->stop = stream->rdNext; stream->isClosed = TRUE; return; } break; case SKIP: data->skip = TRUE; break; case BEGIN_RECORD: /* * If this header marked the beginning of a new * request, return role information to caller. */ return; break; case MGMT_RECORD: break; default: ASSERT(status < 0); SetError(stream, status); return; break; } } } /* *---------------------------------------------------------------------- * * NewStream -- * * Creates a stream to read or write from an open ipcFd. * The stream performs reads/writes of up to bufflen bytes. * *---------------------------------------------------------------------- */ static FCGX_Stream *NewStream( FCGX_Request *reqDataPtr, int bufflen, int isReader, int streamType) { /* * XXX: It would be a lot cleaner to have a NewStream that only * knows about the type FCGX_Stream, with all other * necessary data passed in. It appears that not just * data and the two procs are needed for initializing stream, * but also data->buff and data->buffStop. This has implications * for procs that want to swap buffers, too. */ FCGX_Stream *stream = (FCGX_Stream *)Malloc(sizeof(FCGX_Stream)); FCGX_Stream_Data *data = (FCGX_Stream_Data *)Malloc(sizeof(FCGX_Stream_Data)); data->reqDataPtr = reqDataPtr; bufflen = AlignInt8(min(max(bufflen, 32), FCGI_MAX_LENGTH + 1)); data->bufflen = bufflen; data->mBuff = (unsigned char *)Malloc(bufflen); data->buff = AlignPtr8(data->mBuff); if(data->buff != data->mBuff) { data->bufflen -= 8; } if(isReader) { data->buffStop = data->buff; } else { data->buffStop = data->buff + data->bufflen; } data->type = streamType; data->eorStop = FALSE; data->skip = FALSE; data->contentLen = 0; data->paddingLen = 0; data->isAnythingWritten = FALSE; data->rawWrite = FALSE; stream->data = data; stream->isReader = isReader; stream->isClosed = FALSE; stream->wasFCloseCalled = FALSE; stream->FCGI_errno = 0; if(isReader) { stream->fillBuffProc = FillBuffProc; stream->emptyBuffProc = NULL; stream->rdNext = data->buff; stream->stop = stream->rdNext; stream->stopUnget = data->buff; stream->wrNext = stream->stop; } else { stream->fillBuffProc = NULL; stream->emptyBuffProc = EmptyBuffProc; stream->wrNext = data->buff + sizeof(FCGI_Header); stream->stop = data->buffStop; stream->stopUnget = NULL; stream->rdNext = stream->stop; } return stream; } /* *---------------------------------------------------------------------- * * FCGX_FreeStream -- * * Frees all storage allocated when *streamPtr was created, * and nulls out *streamPtr. * *---------------------------------------------------------------------- */ void FCGX_FreeStream(FCGX_Stream **streamPtr) { FCGX_Stream *stream = *streamPtr; FCGX_Stream_Data *data; if(stream == NULL) { return; } data = (FCGX_Stream_Data *)stream->data; data->reqDataPtr = NULL; free(data->mBuff); free(data); free(stream); *streamPtr = NULL; } /* *---------------------------------------------------------------------- * * SetReaderType -- * * Re-initializes the stream to read data of the specified type. * *---------------------------------------------------------------------- */ static FCGX_Stream *SetReaderType(FCGX_Stream *stream, int streamType) { FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data; ASSERT(stream->isReader); data->type = streamType; data->eorStop = FALSE; data->skip = FALSE; data->contentLen = 0; data->paddingLen = 0; stream->wrNext = stream->stop = stream->rdNext; stream->isClosed = FALSE; return stream; } /* *---------------------------------------------------------------------- * * NewReader -- * * Creates a stream to read streamType records for the given * request. The stream performs OS reads of up to bufflen bytes. * *---------------------------------------------------------------------- */ static FCGX_Stream *NewReader(FCGX_Request *reqDataPtr, int bufflen, int streamType) { return NewStream(reqDataPtr, bufflen, TRUE, streamType); } /* *---------------------------------------------------------------------- * * NewWriter -- * * Creates a stream to write streamType FastCGI records, using * the ipcFd and RequestId contained in *reqDataPtr. * The stream performs OS writes of up to bufflen bytes. * *---------------------------------------------------------------------- */ static FCGX_Stream *NewWriter(FCGX_Request *reqDataPtr, int bufflen, int streamType) { return NewStream(reqDataPtr, bufflen, FALSE, streamType); } /* *---------------------------------------------------------------------- * * FCGX_CreateWriter -- * * Creates a stream to write streamType FastCGI records, using * the given ipcFd and request Id. This function is provided * for use by cgi-fcgi. In order to be defensive against misuse, * this function leaks a little storage; cgi-fcgi doesn't care. * *---------------------------------------------------------------------- */ FCGX_Stream *FCGX_CreateWriter( int ipcFd, int requestId, int bufflen, int streamType) { FCGX_Request *reqDataPtr = (FCGX_Request *)Malloc(sizeof(FCGX_Request)); reqDataPtr->ipcFd = ipcFd; reqDataPtr->requestId = requestId; /* * Suppress writing an FCGI_END_REQUEST record. */ reqDataPtr->nWriters = 2; return NewWriter(reqDataPtr, bufflen, streamType); } /* *====================================================================== * Control *====================================================================== */ /* *---------------------------------------------------------------------- * * FCGX_IsCGI -- * * This routine determines if the process is running as a CGI or * FastCGI process. The distinction is made by determining whether * FCGI_LISTENSOCK_FILENO is a listener ipcFd or the end of a * pipe (ie. standard in). * * Results: * TRUE if the process is a CGI process, FALSE if FastCGI. * *---------------------------------------------------------------------- */ int FCGX_IsCGI(void) { if (isFastCGI != -1) { return !isFastCGI; } if (!libInitialized) { int rc = FCGX_Init(); if (rc) { /* exit() isn't great, but hey */ exit((rc < 0) ? rc : -rc); } } isFastCGI = OS_IsFcgi(FCGI_LISTENSOCK_FILENO); return !isFastCGI; } /* *---------------------------------------------------------------------- * * FCGX_Finish -- * * Finishes the current request from the HTTP server. * * Side effects: * * Finishes the request accepted by (and frees any * storage allocated by) the previous call to FCGX_Accept. * * DO NOT retain pointers to the envp array or any strings * contained in it (e.g. to the result of calling FCGX_GetParam), * since these will be freed by the next call to FCGX_Finish * or FCGX_Accept. * *---------------------------------------------------------------------- */ void FCGX_Finish(void) { FCGX_Finish_r(&the_request); } /* *---------------------------------------------------------------------- * * FCGX_Finish_r -- * * Finishes the current request from the HTTP server. * * Side effects: * * Finishes the request accepted by (and frees any * storage allocated by) the previous call to FCGX_Accept. * * DO NOT retain pointers to the envp array or any strings * contained in it (e.g. to the result of calling FCGX_GetParam), * since these will be freed by the next call to FCGX_Finish * or FCGX_Accept. * *---------------------------------------------------------------------- */ void FCGX_Finish_r(FCGX_Request *reqDataPtr) { int close; if (reqDataPtr == NULL) { return; } close = !reqDataPtr->keepConnection; /* This should probably use a 'status' member instead of 'in' */ if (reqDataPtr->in) { close |= FCGX_FClose(reqDataPtr->err); close |= FCGX_FClose(reqDataPtr->out); close |= FCGX_GetError(reqDataPtr->in); /* discard any remaining data in input stream on persistent connections */ if (!close && !reqDataPtr->in->isClosed && reqDataPtr->keepConnection) { FCGX_Stream *stream = reqDataPtr->in; do { stream->rdNext = stream->stop; stream->fillBuffProc(stream); } while (!stream->isClosed); close |= FCGX_GetError(stream); } } FCGX_Free(reqDataPtr, close); } void FCGX_Free(FCGX_Request * request, int close) { if (request == NULL) return; FCGX_FreeStream(&request->in); FCGX_FreeStream(&request->out); FCGX_FreeStream(&request->err); FreeParams(&request->paramsPtr); if (close) { OS_IpcClose(request->ipcFd, ! request->detached); request->ipcFd = -1; request->detached = 0; } } int FCGX_OpenSocket(const char *path, int backlog) { int rc = OS_CreateLocalIpcFd(path, backlog); if (rc == FCGI_LISTENSOCK_FILENO && isFastCGI == 0) { /* XXX probably need to call OS_LibInit() again for Win */ isFastCGI = 1; } return rc; } int FCGX_InitRequest(FCGX_Request *request, int sock, int flags) { memset(request, 0, sizeof(FCGX_Request)); /* @@@ Should check that sock is open and listening */ request->listen_sock = sock; /* @@@ Should validate against "known" flags */ request->flags = flags; request->ipcFd = -1; return 0; } /* *---------------------------------------------------------------------- * * FCGX_Init -- * * Initilize the FCGX library. This is called by FCGX_Accept() * but must be called by the user when using FCGX_Accept_r(). * * Results: * 0 for successful call. * *---------------------------------------------------------------------- */ int FCGX_Init(void) { char *p; if (libInitialized) { return 0; } FCGX_InitRequest(&the_request, FCGI_LISTENSOCK_FILENO, 0); if (OS_LibInit(NULL) == -1) { return OS_Errno ? OS_Errno : -9997; } p = getenv("FCGI_WEB_SERVER_ADDRS"); webServerAddressList = p ? StringCopy(p) : NULL; libInitialized = 1; return 0; } /* *---------------------------------------------------------------------- * * FCGX_Accept -- * * Accepts a new request from the HTTP server. * * Results: * 0 for successful call, -1 for error. * * Side effects: * * Finishes the request accepted by (and frees any * storage allocated by) the previous call to FCGX_Accept. * Creates input, output, and error streams and * assigns them to *in, *out, and *err respectively. * Creates a parameters data structure to be accessed * via getenv(3) (if assigned to environ) or by FCGX_GetParam * and assigns it to *envp. * * DO NOT retain pointers to the envp array or any strings * contained in it (e.g. to the result of calling FCGX_GetParam), * since these will be freed by the next call to FCGX_Finish * or FCGX_Accept. * *---------------------------------------------------------------------- */ int FCGX_Accept( FCGX_Stream **in, FCGX_Stream **out, FCGX_Stream **err, FCGX_ParamArray *envp) { int rc; if (! libInitialized) { rc = FCGX_Init(); if (rc) { return rc; } } rc = FCGX_Accept_r(&the_request); *in = the_request.in; *out = the_request.out; *err = the_request.err; *envp = the_request.envp; return rc; } /* *---------------------------------------------------------------------- * * FCGX_Accept_r -- * * Accepts a new request from the HTTP server. * * Results: * 0 for successful call, -1 for error. * * Side effects: * * Finishes the request accepted by (and frees any * storage allocated by) the previous call to FCGX_Accept. * Creates input, output, and error streams and * assigns them to *in, *out, and *err respectively. * Creates a parameters data structure to be accessed * via getenv(3) (if assigned to environ) or by FCGX_GetParam * and assigns it to *envp. * * DO NOT retain pointers to the envp array or any strings * contained in it (e.g. to the result of calling FCGX_GetParam), * since these will be freed by the next call to FCGX_Finish * or FCGX_Accept. * *---------------------------------------------------------------------- */ int FCGX_Accept_r(FCGX_Request *reqDataPtr) { if (!libInitialized) { return -9998; } /* Finish the current request, if any. */ FCGX_Finish_r(reqDataPtr); for (;;) { /* * If a connection isn't open, accept a new connection (blocking). * If an OS error occurs in accepting the connection, * return -1 to the caller, who should exit. */ if (reqDataPtr->ipcFd < 0) { int fail_on_intr = reqDataPtr->flags & FCGI_FAIL_ACCEPT_ON_INTR; reqDataPtr->ipcFd = OS_Accept(reqDataPtr->listen_sock, fail_on_intr, webServerAddressList); if (reqDataPtr->ipcFd < 0) { return (errno > 0) ? (0 - errno) : -9999; } } /* * A connection is open. Read from the connection in order to * get the request's role and environment. If protocol or other * errors occur, close the connection and try again. */ reqDataPtr->isBeginProcessed = FALSE; reqDataPtr->in = NewReader(reqDataPtr, 8192, 0); FillBuffProc(reqDataPtr->in); if(!reqDataPtr->isBeginProcessed) { goto TryAgain; } { char *roleStr; switch(reqDataPtr->role) { case FCGI_RESPONDER: roleStr = "FCGI_ROLE=RESPONDER"; break; case FCGI_AUTHORIZER: roleStr = "FCGI_ROLE=AUTHORIZER"; break; case FCGI_FILTER: roleStr = "FCGI_ROLE=FILTER"; break; default: goto TryAgain; } reqDataPtr->paramsPtr = NewParams(30); PutParam(reqDataPtr->paramsPtr, StringCopy(roleStr)); } SetReaderType(reqDataPtr->in, FCGI_PARAMS); if(ReadParams(reqDataPtr->paramsPtr, reqDataPtr->in) >= 0) { /* * Finished reading the environment. No errors occurred, so * leave the connection-retry loop. */ break; } /* * Close the connection and try again. */ TryAgain: FCGX_Free(reqDataPtr, 1); } /* for (;;) */ /* * Build the remaining data structures representing the new * request and return successfully to the caller. */ SetReaderType(reqDataPtr->in, FCGI_STDIN); reqDataPtr->out = NewWriter(reqDataPtr, 8192, FCGI_STDOUT); reqDataPtr->err = NewWriter(reqDataPtr, 512, FCGI_STDERR); reqDataPtr->nWriters = 2; reqDataPtr->envp = reqDataPtr->paramsPtr->vec; return 0; } /* *---------------------------------------------------------------------- * * FCGX_StartFilterData -- * * stream is an input stream for a FCGI_FILTER request. * stream is positioned at EOF on FCGI_STDIN. * Repositions stream to the start of FCGI_DATA. * If the preconditions are not met (e.g. FCGI_STDIN has not * been read to EOF) sets the stream error code to * FCGX_CALL_SEQ_ERROR. * * Results: * 0 for a normal return, < 0 for error * *---------------------------------------------------------------------- */ int FCGX_StartFilterData(FCGX_Stream *stream) { FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data; if(data->reqDataPtr->role != FCGI_FILTER || !stream->isReader || !stream->isClosed || data->type != FCGI_STDIN) { SetError(stream, FCGX_CALL_SEQ_ERROR); return -1; } SetReaderType(stream, FCGI_DATA); return 0; } /* *---------------------------------------------------------------------- * * FCGX_SetExitStatus -- * * Sets the exit status for stream's request. The exit status * is the status code the request would have exited with, had * the request been run as a CGI program. You can call * SetExitStatus several times during a request; the last call * before the request ends determines the value. * *---------------------------------------------------------------------- */ void FCGX_SetExitStatus(int status, FCGX_Stream *stream) { FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data; data->reqDataPtr->appStatus = status; } int FCGX_Attach(FCGX_Request * r) { r->detached = FALSE; return 0; } int FCGX_Detach(FCGX_Request * r) { if (r->ipcFd <= 0) { return -1; } r->detached = TRUE; return 0; } FCGI-0.74/typemap0000644000175000017500000000056311417356077012227 0ustar raflraflTYPEMAP FCGI T_PTROBJ FCGI::Stream T_PTROBJ GLOBREF T_GLOBREF HASHREF T_HASHREF INPUT T_GLOBREF if (SvROK($arg) && isGV(SvRV($arg))) { $var = (GV*)SvRV($arg); } else croak(\"$var is not a GLOB reference\"); T_HASHREF if (SvROK($arg) && SvTYPE(SvRV($arg)) == SVt_PVHV) { $var = (HV*)SvRV($arg); } else croak(\"$var is not a reference to a hash\"); FCGI-0.74/ChangeLog0000644000175000017500000002671211637307530012375 0ustar raflraflVersion 0.74 -- 24 Sep 2011 o Stop leaking information across requests when using the deprecated and undocumented old FCGI interface. This is CVE-2011-2766. o Only discard input stream if FCGI_KEEP_CONN is set in FCGI_BeginRequestBody flags. Version 0.73 -- 19 May 2011 o Stop claiming we ship a file called -e in the MANIFEST. Version 0.72 -- 19 May 2011 o Clean up Makefile.PL and restore compatibility with recent ExtUtils::MakeMaker versions. Version 0.71_03 -- 28 Apr 2011 o Remove support for sfio which is an optional (and not enabled by default) compile option to perl that is never used. o Fix FCGI::Stream::READ() to warn() instead of croak() incase of wide characters which cannot be gracefully downgraded. o Fix warnings due to wide characters being mangled to note that accepting them is deprecated and will stop working at some point. o Various fixes to FCGI::Stream::READ() to improve handling of error and edge cases. - croak if called with invalid number of arguments - croak if length is negative - croak if offset is outside string - pad scalar if offset is greater than length o Fix in FCGX_Finish_r to discard any remaining data in input stream which otherwise ends up in next request. This fixes multiple requests being broken if something goes wrong whilst reading the initial request. This discarding is done silently, as RFC 3875 says a script is not obliged to read any of the data. o Fixed indent style and braces to be consistent, swapped tabs for spaces in indenting. Version 0.71_02 -- 28 Apr 2011 o Change the Request function to pass FAIL_ON_INTR into the XS RequestX function. This prevents the fcgi C client code from looping around their accept() call. This change means that when using CGI::Fast, and the process recieves SIGTERM or SIGHUP, the error statusis correctly passed back up, allowing process managers (such as FCGI::ProcManager) to correctly handle cleanly exiting. Version 0.71_01 -- 24 Aug 2010 o Restore old behavior when un-downgradeable uft8 is sent to FCGI. The first time this happens, a warning will be issued, but subsequently the bytes will be sent through raw (causing double encoding etc). If the character string can be downgraded safely, then it will still be. use warnings FATAL => 'utf8'; can be used to make undowngradeable strings throw an exception. o Fix PRINT retval (Closes: RT#57697). Version 0.71 -- 1 Apr 2010 Florian Ragwitz o Fix some more defined(%hash) warnings on perl 5.12. Version 0.70 -- 22 Mar 2010 Tomas Doran o Fix use of defined %hash which becomes deprecated in perl 5.12 Version 0.69 -- 15 Feb 2010 Matt S Trout o No changes since the previous development release. Version 0.68_02 -- 13 Jan 2010 Matt S Trout o Make the PRINT method return a boolean value rather than the number of bytes written, previous patch was incorrect. Version 0.68_01 -- 10 Jan 2010 Matt S Trout o Force signal handler installation so that we correctly install handlers for SIGPIPE. Fixes RT#5100 o Make the PRINT method return the number of bytes written rather than undef to be consistent with the IO:: interface. Fixes RT#24347 o Fix UTF-8 double encoding when FCGI is passed octets by downgrading them into bytes correctly. Fixes RT#52400 Version 0.68 -- 31 Dec 2009 Matt S Trout o No changes since the previous development release. Version 0.67_01 -- 20 Dec 2009 Matt S Trout o Add FILENO method which returns a defined but invalid value to placate things such as IPC::Run which call fileno to check if a filehandle is open. Closes bugs: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=544540 http://rt.cpan.org/Public/Bug/Display.html?id=50972 Removes need for upstream patch in OpenBSD o Call the fcgi lib's attach/detach Version 0.67 -- 22 December 2002 Sven Verdoolaege o Fixes for pure perl version based on report and patch from "Kurtis D. Rader" o FCGI_UndoBinding perl 5.8.0 compatibility Reported by Marko Asplund o Fix problem with fcgi_config.h on win32. Reported by Igor Franchuk o Add minimal tests Version 0.66 -- 5 September 2002 Sven Verdoolaege o perl 5.8.0 compatibility fix by Autrijus o library fixes from Rob Version 0.65 -- 19 February 2002 Sven Verdoolaege o fix perl 5.005 compatibility problem o fix strict warning Version 0.64 -- 25 September 2001 Sven Verdoolaege Version 0.63 -- 24 September 2001 Sven Verdoolaege o Update build process Version 0.62 -- 21 September 2001 Sven Verdoolaege o Move version number to separate file Version 0.61 -- 20 September 2001 Sven Verdoolaege o Fix refcounting bug o Add GetEnvironment for pure version o Add LastCall method o Allow filehandle for Request's socket parameter o library fixes ("Rob Saccoccio" ) Version 0.60 -- 8 July 2001 Sven Verdoolaege o Allow specification of purity on command line (suggested by Rob Brown ) o Fix bug in pure perl implementation o Don't try to compile anything on pure perl build o Add BINMODE method o Add comment on socket permissions Version 0.59 -- 31 December 2000 Sven Verdoolaege o preliminary pure perl implementation o copy win32 configuration file instead of moving it o convert echo.fpl to new interface Version 0.58 -- 15 November 2000 Sven Verdoolaege o fix bug introduced in 0.57 Version 0.57 -- 12 November 2000 Sven Verdoolaege o don't flush unbound request Version 0.56 -- 3 November 2000 Sven Verdoolaege o add example remote.fpl o provide access to the Request parameters o add IsFastCGI method o fix warn handler (Andrew Pimlott ) Version 0.55 -- 18 October 2000 Sven Verdoolaege o small documentation fix o compilation issues with older perls fixed o library initialization when using sockets fixed Version 0.54 -- 8 October 2000 Sven Verdoolaege o library fixes ("Rob Saccoccio" ) o compilation issues with newer gcc o completely untested OPEN and READLINE methods Version 0.53 -- 10 July 2000 Sven Verdoolaege o sfio version compiles again Version 0.52 -- 12 April 2000 Sven Verdoolaege Version 0.51 -- 12 April 2000 Sven Verdoolaege Version 0.50 -- 10 April 2000 Sven Verdoolaege Version 0.49 -- 9 April 2000 Sven Verdoolaege o General clean-ups o Allow attaching/detaching o Changed DESTROY behaviour o Fixed default warn/die handler of old interface o Document new interface Version 0.48 -- 27 August 1999 Sven Verdoolaege o perl 5.005_60 compatibility o locking on platforms that need it o support for remote connections Version 0.47 -- 31 July 1999 Sven Verdoolaege o move PRINTF into correct package o deprecated set_exit_status o general cleanup, moving old non thread safe interface from xs to perl Version 0.46 -- 30 July 1999 Sven Verdoolaege o new thread safe interface o new threaded example program Version 0.45 -- 8 March 1999 Sven Verdoolaege o FCGI.pm now part of the devel kit o library fixes ("Rob Saccoccio" ) o allow bypassing of installation of handlers o ActivePerl compatibility (Murray Nesbitt ) Version 0.43 -- 22 December 1998 Sven Verdoolaege o POST on bigendians (Paul GABORIT ) o Some win32 changes (Monty ) o library fixes ("Rob Saccoccio" ) Version 0.42 -- 28 August 1998 Sven Verdoolaege o environ fixes ? o print NULLs (Ken Alexander ) o PRINTF support o set version in FCGI.pm o library fixes ("Rob Saccoccio" ) Version 0.41 -- 29 July 1998 Sven Verdoolaege o Compiles with perl 5.005 Version 0.40 -- 15 July 1998 Sven Verdoolaege o Added default die hook o Minimal documentation Version 0.39 -- 3 July 1998 Sven Verdoolaege o Fixed read bug Version 0.38 -- 28 June 1998 Sven Verdoolaege o Fixed flush bug o Added default warn hook Version 0.37 -- 27 June 1998 Sven Verdoolaege o More support for tied handles o Added flush function Version 0.36 -- 23 June 1998 Sven Verdoolaege o More support for tied handles (GETC and autoflushing) Version 0.35 -- 22 June 1998 Sven Verdoolaege o Added forgotten typemap Version 0.34 -- 17 June 1998 Sven Verdoolaege o No longer force sfio less compile o Update os_unix.c from fcgi2.0b2.1 o Small documentation changes Version 0.33 -- 16 June 1998 Sven Verdoolaege o More support for tied handles Version 0.32 -- 16 June 1998 Sven Verdoolaege o Preliminary support for tied handles (doesn't require sfio) o Force sfio less compile o Changed protoype of set_exit_status Version 0.31 -- 13 July 1997 Sven Verdoolaege o Applied solaris accept patch from Chip Salzenberg o Preliminary support glibc's cookie mechanism Version 0.30 -- 24 June 1997 Sven Verdoolaege o Added forgotten library files Version 0.29 -- 10 June 1997 Sven Verdoolaege o Updated library files from fastcgi 2.02b o Use installed library/include file if found Version 0.28 -- 24 February 1997 Sven Verdoolaege o Intialization of %ENV did not change environ. Fixed. Problem reported by Jan Drehmer Version 0.26 -- 19 February 1997 Sven Verdoolaege o Flush output when $| is set to eliminate a problem reported by echo@echo.cica.fr Version 0.25 -- 13 October 1996 Sven Verdoolaege o Eliminate some warnings o Check whether perl is compiled with sfio support Version 0.25 -- 25 September 1996 Sven Verdoolaege o First public release o Additional bugfixes Version 0.21 -- 20 September 1996 Sven Verdoolaege o Bugfix Version 0.2 -- 19 September 1996 Sven Verdoolaege o First Version based on sfio Version 0.1 -- 12 June 1996 o Original version from Open Market's FastCGI Developer's Kit FCGI-0.74/remote.PL0000644000175000017500000000167211417356077012357 0ustar raflrafluse Config; open OUT, ">remote.fpl"; print OUT "#!$Config{perlpath}\n"; print OUT while ; close OUT; chmod 0755, "remote.fpl"; __END__ # An example of using a remote script with an Apache webserver. # Run this Perl program on "otherhost" to bind port 8888 and wait # for FCGI requests from the webserver. ## Sample Apache configuration on the webserver to refer to the ## remote script on "otherhost" # # AddHandler fastcgi-script fcgi # FastCgiExternalServer /path-to/cgi-bin/external.fcgi -host otherhost:8888 # # Access the URL: http://webserver/cgi-bin/external.fcgi # Contributed by Don Bindner use FCGI; my $socket = FCGI::OpenSocket( ":8888", 5 ); my $request = FCGI::Request( \*STDIN, \*STDOUT, \*STDERR, \%ENV, $socket ); my $count; while( $request->Accept() >= 0 ) { print "Content-type: text/html\r\n\r\n"; print ++$count; } FCGI::CloseSocket( $socket ); FCGI-0.74/MANIFEST0000644000175000017500000000066711637307650011760 0ustar raflraflChangeLog FCGI.PL FCGI.XL MANIFEST Makefile.PL README configure configure.in configure.readme echo.PL fcgi_config.h.in remote.PL test.pl threaded.PL typemap version.pm META.yml Module YAML meta-data (added by MakeMaker) META.json Module JSON meta-data (added by MakeMaker) LICENSE.TERMS fcgiapp.c os_unix.c os_win32.c fastcgi.h fcgiapp.h fcgimisc.h fcgios.h fcgi_config_x86.h FCGI-0.74/META.yml0000600000175000017500000000102211637307650012052 0ustar raflrafl--- abstract: 'Fast CGI module' author: - 'Sven Verdoolaege (skimo@kotnet.org)' build_requires: ExtUtils::MakeMaker: 0 configure_requires: ExtUtils::MakeMaker: 0 dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 6.59, CPAN::Meta::Converter version 2.112150' license: unknown meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: 1.4 name: FCGI no_index: directory: - t - inc requires: {} resources: repository: git://git.shadowcat.co.uk/catagits/fcgi2.git version: 0.74 FCGI-0.74/os_unix.c0000711000175000017500000010033711637307650012445 0ustar raflrafl/* * os_unix.c -- * * Description of file. * * * Copyright (c) 1995 Open Market, Inc. * All rights reserved. * * This file contains proprietary and confidential information and * remains the unpublished property of Open Market, Inc. Use, * disclosure, or reproduction is prohibited except as permitted by * express written license agreement with Open Market, Inc. * * Bill Snapper * snapper@openmarket.com */ #ifndef lint static const char rcsid[] = "$Id: os_unix.c,v 1.38 2003/06/22 00:16:43 robs Exp $"; #endif /* not lint */ #include "fcgi_config.h" #include #ifdef HAVE_NETINET_IN_H #include #endif #include #include #include #include /* for fcntl */ #include #include /* for memchr() */ #include #include #include #include #include #include #include #include #ifdef HAVE_NETDB_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include /* for getpeername */ #endif #ifdef HAVE_UNISTD_H #include #endif #include "fastcgi.h" #include "fcgimisc.h" #include "fcgios.h" #ifndef INADDR_NONE #define INADDR_NONE ((unsigned long) -1) #endif /* * This structure holds an entry for each oustanding async I/O operation. */ typedef struct { OS_AsyncProc procPtr; /* callout completion procedure */ ClientData clientData; /* caller private data */ int fd; int len; int offset; void *buf; int inUse; } AioInfo; /* * Entries in the async I/O table are allocated 2 per file descriptor. * * Read Entry Index = fd * 2 * Write Entry Index = (fd * 2) + 1 */ #define AIO_RD_IX(fd) (fd * 2) #define AIO_WR_IX(fd) ((fd * 2) + 1) static int asyncIoInUse = FALSE; static int asyncIoTableSize = 16; static AioInfo *asyncIoTable = NULL; static int libInitialized = FALSE; static fd_set readFdSet; static fd_set writeFdSet; static fd_set readFdSetPost; static int numRdPosted = 0; static fd_set writeFdSetPost; static int numWrPosted = 0; static int volatile maxFd = -1; static int shutdownPending = FALSE; static int shutdownNow = FALSE; void OS_ShutdownPending() { shutdownPending = TRUE; } static void OS_Sigusr1Handler(int signo) { OS_ShutdownPending(); } static void OS_SigpipeHandler(int signo) { ; } static void installSignalHandler(int signo, const struct sigaction * act, int force) { struct sigaction sa; sigaction(signo, NULL, &sa); if (force || sa.sa_handler == SIG_DFL) { sigaction(signo, act, NULL); } } static void OS_InstallSignalHandlers(int force) { struct sigaction sa; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sa.sa_handler = OS_SigpipeHandler; installSignalHandler(SIGPIPE, &sa, force); sa.sa_handler = OS_Sigusr1Handler; installSignalHandler(SIGUSR1, &sa, force); } /* *-------------------------------------------------------------- * * OS_LibInit -- * * Set up the OS library for use. * * NOTE: This function is really only needed for application * asynchronous I/O. It will most likely change in the * future to setup the multi-threaded environment. * * Results: * Returns 0 if success, -1 if not. * * Side effects: * Async I/O table allocated and initialized. * *-------------------------------------------------------------- */ int OS_LibInit(int stdioFds[3]) { if(libInitialized) return 0; asyncIoTable = (AioInfo *)malloc(asyncIoTableSize * sizeof(AioInfo)); if(asyncIoTable == NULL) { errno = ENOMEM; return -1; } memset((char *) asyncIoTable, 0, asyncIoTableSize * sizeof(AioInfo)); FD_ZERO(&readFdSet); FD_ZERO(&writeFdSet); FD_ZERO(&readFdSetPost); FD_ZERO(&writeFdSetPost); OS_InstallSignalHandlers(TRUE); libInitialized = TRUE; return 0; } /* *-------------------------------------------------------------- * * OS_LibShutdown -- * * Shutdown the OS library. * * Results: * None. * * Side effects: * Memory freed, fds closed. * *-------------------------------------------------------------- */ void OS_LibShutdown() { if(!libInitialized) return; free(asyncIoTable); asyncIoTable = NULL; libInitialized = FALSE; return; } /* *---------------------------------------------------------------------- * * OS_BuildSockAddrUn -- * * Using the pathname bindPath, fill in the sockaddr_un structure * *servAddrPtr and the length of this structure *servAddrLen. * * The format of the sockaddr_un structure changed incompatibly in * 4.3BSD Reno. Digital UNIX supports both formats, other systems * support one or the other. * * Results: * 0 for normal return, -1 for failure (bindPath too long). * *---------------------------------------------------------------------- */ static int OS_BuildSockAddrUn(const char *bindPath, struct sockaddr_un *servAddrPtr, int *servAddrLen) { int bindPathLen = strlen(bindPath); #ifdef HAVE_SOCKADDR_UN_SUN_LEN /* 4.3BSD Reno and later: BSDI, DEC */ if(bindPathLen >= sizeof(servAddrPtr->sun_path)) { return -1; } #else /* 4.3 BSD Tahoe: Solaris, HPUX, DEC, ... */ if(bindPathLen > sizeof(servAddrPtr->sun_path)) { return -1; } #endif memset((char *) servAddrPtr, 0, sizeof(*servAddrPtr)); servAddrPtr->sun_family = AF_UNIX; memcpy(servAddrPtr->sun_path, bindPath, bindPathLen); #ifdef HAVE_SOCKADDR_UN_SUN_LEN /* 4.3BSD Reno and later: BSDI, DEC */ *servAddrLen = sizeof(servAddrPtr->sun_len) + sizeof(servAddrPtr->sun_family) + bindPathLen + 1; servAddrPtr->sun_len = *servAddrLen; #else /* 4.3 BSD Tahoe: Solaris, HPUX, DEC, ... */ *servAddrLen = sizeof(servAddrPtr->sun_family) + bindPathLen; #endif return 0; } union SockAddrUnion { struct sockaddr_un unixVariant; struct sockaddr_in inetVariant; }; /* * OS_CreateLocalIpcFd -- * * This procedure is responsible for creating the listener socket * on Unix for local process communication. It will create a * domain socket or a TCP/IP socket bound to "localhost" and return * a file descriptor to it to the caller. * * Results: * Listener socket created. This call returns either a valid * file descriptor or -1 on error. * * Side effects: * None. * *---------------------------------------------------------------------- */ int OS_CreateLocalIpcFd(const char *bindPath, int backlog) { int listenSock, servLen; union SockAddrUnion sa; int tcp = FALSE; unsigned long tcp_ia = 0; char *tp; short port = 0; char host[MAXPATHLEN]; strcpy(host, bindPath); if((tp = strchr(host, ':')) != 0) { *tp++ = 0; if((port = atoi(tp)) == 0) { *--tp = ':'; } else { tcp = TRUE; } } if(tcp) { if (!*host || !strcmp(host,"*")) { tcp_ia = htonl(INADDR_ANY); } else { tcp_ia = inet_addr(host); if (tcp_ia == INADDR_NONE) { struct hostent * hep; hep = gethostbyname(host); if ((!hep) || (hep->h_addrtype != AF_INET || !hep->h_addr_list[0])) { fprintf(stderr, "Cannot resolve host name %s -- exiting!\n", host); exit(1); } if (hep->h_addr_list[1]) { fprintf(stderr, "Host %s has multiple addresses ---\n", host); fprintf(stderr, "you must choose one explicitly!!!\n"); exit(1); } tcp_ia = ((struct in_addr *) (hep->h_addr))->s_addr; } } } if(tcp) { listenSock = socket(AF_INET, SOCK_STREAM, 0); if(listenSock >= 0) { int flag = 1; if(setsockopt(listenSock, SOL_SOCKET, SO_REUSEADDR, (char *) &flag, sizeof(flag)) < 0) { fprintf(stderr, "Can't set SO_REUSEADDR.\n"); exit(1001); } } } else { listenSock = socket(AF_UNIX, SOCK_STREAM, 0); } if(listenSock < 0) { return -1; } /* * Bind the listening socket. */ if(tcp) { memset((char *) &sa.inetVariant, 0, sizeof(sa.inetVariant)); sa.inetVariant.sin_family = AF_INET; sa.inetVariant.sin_addr.s_addr = tcp_ia; sa.inetVariant.sin_port = htons(port); servLen = sizeof(sa.inetVariant); } else { unlink(bindPath); if(OS_BuildSockAddrUn(bindPath, &sa.unixVariant, &servLen)) { fprintf(stderr, "Listening socket's path name is too long.\n"); exit(1000); } } if(bind(listenSock, (struct sockaddr *) &sa.unixVariant, servLen) < 0 || listen(listenSock, backlog) < 0) { perror("bind/listen"); exit(errno); } return listenSock; } /* *---------------------------------------------------------------------- * * OS_FcgiConnect -- * * Create the socket and connect to the remote application if * possible. * * This was lifted from the cgi-fcgi application and was abstracted * out because Windows NT does not have a domain socket and must * use a named pipe which has a different API altogether. * * Results: * -1 if fail or a valid file descriptor if connection succeeds. * * Side effects: * Remote connection established. * *---------------------------------------------------------------------- */ int OS_FcgiConnect(char *bindPath) { union SockAddrUnion sa; int servLen, resultSock; int connectStatus; char *tp; char host[MAXPATHLEN]; short port = 0; int tcp = FALSE; strcpy(host, bindPath); if((tp = strchr(host, ':')) != 0) { *tp++ = 0; if((port = atoi(tp)) == 0) { *--tp = ':'; } else { tcp = TRUE; } } if(tcp == TRUE) { struct hostent *hp; if((hp = gethostbyname((*host ? host : "localhost"))) == NULL) { fprintf(stderr, "Unknown host: %s\n", bindPath); exit(1000); } sa.inetVariant.sin_family = AF_INET; memcpy(&sa.inetVariant.sin_addr, hp->h_addr, hp->h_length); sa.inetVariant.sin_port = htons(port); servLen = sizeof(sa.inetVariant); resultSock = socket(AF_INET, SOCK_STREAM, 0); } else { if(OS_BuildSockAddrUn(bindPath, &sa.unixVariant, &servLen)) { fprintf(stderr, "Listening socket's path name is too long.\n"); exit(1000); } resultSock = socket(AF_UNIX, SOCK_STREAM, 0); } ASSERT(resultSock >= 0); connectStatus = connect(resultSock, (struct sockaddr *) &sa.unixVariant, servLen); if(connectStatus >= 0) { return resultSock; } else { /* * Most likely (errno == ENOENT || errno == ECONNREFUSED) * and no FCGI application server is running. */ close(resultSock); return -1; } } /* *-------------------------------------------------------------- * * OS_Read -- * * Pass through to the unix read function. * * Results: * Returns number of byes read, 0, or -1 failure: errno * contains actual error. * * Side effects: * None. * *-------------------------------------------------------------- */ int OS_Read(int fd, char * buf, size_t len) { if (shutdownNow) return -1; return(read(fd, buf, len)); } /* *-------------------------------------------------------------- * * OS_Write -- * * Pass through to unix write function. * * Results: * Returns number of byes read, 0, or -1 failure: errno * contains actual error. * * Side effects: * none. * *-------------------------------------------------------------- */ int OS_Write(int fd, char * buf, size_t len) { if (shutdownNow) return -1; return(write(fd, buf, len)); } /* *---------------------------------------------------------------------- * * OS_SpawnChild -- * * Spawns a new FastCGI listener process. * * Results: * 0 if success, -1 if error. * * Side effects: * Child process spawned. * *---------------------------------------------------------------------- */ int OS_SpawnChild(char *appPath, int listenFd) { int forkResult; forkResult = fork(); if(forkResult < 0) { exit(errno); } if(forkResult == 0) { /* * Close STDIN unconditionally. It's used by the parent * process for CGI communication. The FastCGI applciation * will be replacing this with the FastCGI listenFd IF * STDIN_FILENO is the same as FCGI_LISTENSOCK_FILENO * (which it is on Unix). Regardless, STDIN, STDOUT, and * STDERR will be closed as the FastCGI process uses a * multiplexed socket in their place. */ close(STDIN_FILENO); /* * If the listenFd is already the value of FCGI_LISTENSOCK_FILENO * we're set. If not, change it so the child knows where to * get the listen socket from. */ if(listenFd != FCGI_LISTENSOCK_FILENO) { dup2(listenFd, FCGI_LISTENSOCK_FILENO); close(listenFd); } close(STDOUT_FILENO); close(STDERR_FILENO); /* * We're a child. Exec the application. * * XXX: entire environment passes through */ execl(appPath, appPath, NULL); /* * XXX: Can't do this as we've already closed STDERR!!! * * perror("exec"); */ exit(errno); } return 0; } /* *-------------------------------------------------------------- * * OS_AsyncReadStdin -- * * This initiates an asynchronous read on the standard * input handle. * * The abstraction is necessary because Windows NT does not * have a clean way of "select"ing a file descriptor for * I/O. * * Results: * -1 if error, 0 otherwise. * * Side effects: * Asynchronous bit is set in the readfd variable and * request is enqueued. * *-------------------------------------------------------------- */ int OS_AsyncReadStdin(void *buf, int len, OS_AsyncProc procPtr, ClientData clientData) { int index = AIO_RD_IX(STDIN_FILENO); asyncIoInUse = TRUE; ASSERT(asyncIoTable[index].inUse == 0); asyncIoTable[index].procPtr = procPtr; asyncIoTable[index].clientData = clientData; asyncIoTable[index].fd = STDIN_FILENO; asyncIoTable[index].len = len; asyncIoTable[index].offset = 0; asyncIoTable[index].buf = buf; asyncIoTable[index].inUse = 1; FD_SET(STDIN_FILENO, &readFdSet); if(STDIN_FILENO > maxFd) maxFd = STDIN_FILENO; return 0; } static void GrowAsyncTable(void) { int oldTableSize = asyncIoTableSize; asyncIoTableSize = asyncIoTableSize * 2; asyncIoTable = (AioInfo *)realloc(asyncIoTable, asyncIoTableSize * sizeof(AioInfo)); if(asyncIoTable == NULL) { errno = ENOMEM; exit(errno); } memset((char *) &asyncIoTable[oldTableSize], 0, oldTableSize * sizeof(AioInfo)); } /* *-------------------------------------------------------------- * * OS_AsyncRead -- * * This initiates an asynchronous read on the file * handle which may be a socket or named pipe. * * We also must save the ProcPtr and ClientData, so later * when the io completes, we know who to call. * * We don't look at any results here (the ReadFile may * return data if it is cached) but do all completion * processing in OS_Select when we get the io completion * port done notifications. Then we call the callback. * * Results: * -1 if error, 0 otherwise. * * Side effects: * Asynchronous I/O operation is queued for completion. * *-------------------------------------------------------------- */ int OS_AsyncRead(int fd, int offset, void *buf, int len, OS_AsyncProc procPtr, ClientData clientData) { int index = AIO_RD_IX(fd); ASSERT(asyncIoTable != NULL); asyncIoInUse = TRUE; if(fd > maxFd) maxFd = fd; while (index >= asyncIoTableSize) { GrowAsyncTable(); } ASSERT(asyncIoTable[index].inUse == 0); asyncIoTable[index].procPtr = procPtr; asyncIoTable[index].clientData = clientData; asyncIoTable[index].fd = fd; asyncIoTable[index].len = len; asyncIoTable[index].offset = offset; asyncIoTable[index].buf = buf; asyncIoTable[index].inUse = 1; FD_SET(fd, &readFdSet); return 0; } /* *-------------------------------------------------------------- * * OS_AsyncWrite -- * * This initiates an asynchronous write on the "fake" file * descriptor (which may be a file, socket, or named pipe). * We also must save the ProcPtr and ClientData, so later * when the io completes, we know who to call. * * We don't look at any results here (the WriteFile generally * completes immediately) but do all completion processing * in OS_DoIo when we get the io completion port done * notifications. Then we call the callback. * * Results: * -1 if error, 0 otherwise. * * Side effects: * Asynchronous I/O operation is queued for completion. * *-------------------------------------------------------------- */ int OS_AsyncWrite(int fd, int offset, void *buf, int len, OS_AsyncProc procPtr, ClientData clientData) { int index = AIO_WR_IX(fd); asyncIoInUse = TRUE; if(fd > maxFd) maxFd = fd; while (index >= asyncIoTableSize) { GrowAsyncTable(); } ASSERT(asyncIoTable[index].inUse == 0); asyncIoTable[index].procPtr = procPtr; asyncIoTable[index].clientData = clientData; asyncIoTable[index].fd = fd; asyncIoTable[index].len = len; asyncIoTable[index].offset = offset; asyncIoTable[index].buf = buf; asyncIoTable[index].inUse = 1; FD_SET(fd, &writeFdSet); return 0; } /* *-------------------------------------------------------------- * * OS_Close -- * * Closes the descriptor. This is a pass through to the * Unix close. * * Results: * 0 for success, -1 on failure * * Side effects: * None. * *-------------------------------------------------------------- */ int OS_Close(int fd, int shutdown_ok) { if (fd == -1) return 0; if (asyncIoInUse) { int index = AIO_RD_IX(fd); FD_CLR(fd, &readFdSet); FD_CLR(fd, &readFdSetPost); if (asyncIoTable[index].inUse != 0) { asyncIoTable[index].inUse = 0; } FD_CLR(fd, &writeFdSet); FD_CLR(fd, &writeFdSetPost); index = AIO_WR_IX(fd); if (asyncIoTable[index].inUse != 0) { asyncIoTable[index].inUse = 0; } if (maxFd == fd) { maxFd--; } } /* * shutdown() the send side and then read() from client until EOF * or a timeout expires. This is done to minimize the potential * that a TCP RST will be sent by our TCP stack in response to * receipt of additional data from the client. The RST would * cause the client to discard potentially useful response data. */ if (shutdown_ok) { if (shutdown(fd, 1) == 0) { struct timeval tv; fd_set rfds; int rv; char trash[1024]; FD_ZERO(&rfds); do { FD_SET(fd, &rfds); tv.tv_sec = 2; tv.tv_usec = 0; rv = select(fd + 1, &rfds, NULL, NULL, &tv); } while (rv > 0 && read(fd, trash, sizeof(trash)) > 0); } } return close(fd); } /* *-------------------------------------------------------------- * * OS_CloseRead -- * * Cancel outstanding asynchronous reads and prevent subsequent * reads from completing. * * Results: * Socket or file is shutdown. Return values mimic Unix shutdown: * 0 success, -1 failure * *-------------------------------------------------------------- */ int OS_CloseRead(int fd) { if(asyncIoTable[AIO_RD_IX(fd)].inUse != 0) { asyncIoTable[AIO_RD_IX(fd)].inUse = 0; FD_CLR(fd, &readFdSet); } return shutdown(fd, 0); } /* *-------------------------------------------------------------- * * OS_DoIo -- * * This function was formerly OS_Select. It's purpose is * to pull I/O completion events off the queue and dispatch * them to the appropriate place. * * Results: * Returns 0. * * Side effects: * Handlers are called. * *-------------------------------------------------------------- */ int OS_DoIo(struct timeval *tmo) { int fd, len, selectStatus; OS_AsyncProc procPtr; ClientData clientData; AioInfo *aioPtr; fd_set readFdSetCpy; fd_set writeFdSetCpy; asyncIoInUse = TRUE; FD_ZERO(&readFdSetCpy); FD_ZERO(&writeFdSetCpy); for(fd = 0; fd <= maxFd; fd++) { if(FD_ISSET(fd, &readFdSet)) { FD_SET(fd, &readFdSetCpy); } if(FD_ISSET(fd, &writeFdSet)) { FD_SET(fd, &writeFdSetCpy); } } /* * If there were no completed events from a prior call, see if there's * any work to do. */ if(numRdPosted == 0 && numWrPosted == 0) { selectStatus = select((maxFd+1), &readFdSetCpy, &writeFdSetCpy, NULL, tmo); if(selectStatus < 0) { exit(errno); } for(fd = 0; fd <= maxFd; fd++) { /* * Build up a list of completed events. We'll work off of * this list as opposed to looping through the read and write * fd sets since they can be affected by a callbacl routine. */ if(FD_ISSET(fd, &readFdSetCpy)) { numRdPosted++; FD_SET(fd, &readFdSetPost); FD_CLR(fd, &readFdSet); } if(FD_ISSET(fd, &writeFdSetCpy)) { numWrPosted++; FD_SET(fd, &writeFdSetPost); FD_CLR(fd, &writeFdSet); } } } if(numRdPosted == 0 && numWrPosted == 0) return 0; for(fd = 0; fd <= maxFd; fd++) { /* * Do reads and dispatch callback. */ if(FD_ISSET(fd, &readFdSetPost) && asyncIoTable[AIO_RD_IX(fd)].inUse) { numRdPosted--; FD_CLR(fd, &readFdSetPost); aioPtr = &asyncIoTable[AIO_RD_IX(fd)]; len = read(aioPtr->fd, aioPtr->buf, aioPtr->len); procPtr = aioPtr->procPtr; aioPtr->procPtr = NULL; clientData = aioPtr->clientData; aioPtr->inUse = 0; (*procPtr)(clientData, len); } /* * Do writes and dispatch callback. */ if(FD_ISSET(fd, &writeFdSetPost) && asyncIoTable[AIO_WR_IX(fd)].inUse) { numWrPosted--; FD_CLR(fd, &writeFdSetPost); aioPtr = &asyncIoTable[AIO_WR_IX(fd)]; len = write(aioPtr->fd, aioPtr->buf, aioPtr->len); procPtr = aioPtr->procPtr; aioPtr->procPtr = NULL; clientData = aioPtr->clientData; aioPtr->inUse = 0; (*procPtr)(clientData, len); } } return 0; } /* * Not all systems have strdup(). * @@@ autoconf should determine whether or not this is needed, but for now.. */ static char * str_dup(const char * str) { char * sdup = (char *) malloc(strlen(str) + 1); if (sdup) strcpy(sdup, str); return sdup; } /* *---------------------------------------------------------------------- * * ClientAddrOK -- * * Checks if a client address is in a list of allowed addresses * * Results: * TRUE if address list is empty or client address is present * in the list, FALSE otherwise. * *---------------------------------------------------------------------- */ static int ClientAddrOK(struct sockaddr_in *saPtr, const char *clientList) { int result = FALSE; char *clientListCopy, *cur, *next; if (clientList == NULL || *clientList == '\0') { return TRUE; } clientListCopy = str_dup(clientList); for (cur = clientListCopy; cur != NULL; cur = next) { next = strchr(cur, ','); if (next != NULL) { *next++ = '\0'; } if (inet_addr(cur) == saPtr->sin_addr.s_addr) { result = TRUE; break; } } free(clientListCopy); return result; } /* *---------------------------------------------------------------------- * * AcquireLock -- * * On platforms that implement concurrent calls to accept * on a shared listening ipcFd, returns 0. On other platforms, * acquires an exclusive lock across all processes sharing a * listening ipcFd, blocking until the lock has been acquired. * * Results: * 0 for successful call, -1 in case of system error (fatal). * * Side effects: * This process now has the exclusive lock. * *---------------------------------------------------------------------- */ static int AcquireLock(int sock, int fail_on_intr) { #ifdef USE_LOCKING do { struct flock lock; lock.l_type = F_WRLCK; lock.l_start = 0; lock.l_whence = SEEK_SET; lock.l_len = 0; if (fcntl(sock, F_SETLKW, &lock) != -1) return 0; } while (errno == EINTR && ! fail_on_intr && ! shutdownPending); return -1; #else return 0; #endif } /* *---------------------------------------------------------------------- * * ReleaseLock -- * * On platforms that implement concurrent calls to accept * on a shared listening ipcFd, does nothing. On other platforms, * releases an exclusive lock acquired by AcquireLock. * * Results: * 0 for successful call, -1 in case of system error (fatal). * * Side effects: * This process no longer holds the lock. * *---------------------------------------------------------------------- */ static int ReleaseLock(int sock) { #ifdef USE_LOCKING do { struct flock lock; lock.l_type = F_UNLCK; lock.l_start = 0; lock.l_whence = SEEK_SET; lock.l_len = 0; if (fcntl(sock, F_SETLK, &lock) != -1) return 0; } while (errno == EINTR); return -1; #else return 0; #endif } /********************************************************************** * Determine if the errno resulting from a failed accept() warrants a * retry or exit(). Based on Apache's http_main.c accept() handling * and Stevens' Unix Network Programming Vol 1, 2nd Ed, para. 15.6. */ static int is_reasonable_accept_errno (const int error) { switch (error) { #ifdef EPROTO /* EPROTO on certain older kernels really means ECONNABORTED, so * we need to ignore it for them. See discussion in new-httpd * archives nh.9701 search for EPROTO. Also see nh.9603, search * for EPROTO: There is potentially a bug in Solaris 2.x x<6, and * other boxes that implement tcp sockets in userland (i.e. on top of * STREAMS). On these systems, EPROTO can actually result in a fatal * loop. See PR#981 for example. It's hard to handle both uses of * EPROTO. */ case EPROTO: #endif #ifdef ECONNABORTED case ECONNABORTED: #endif /* Linux generates the rest of these, other tcp stacks (i.e. * bsd) tend to hide them behind getsockopt() interfaces. They * occur when the net goes sour or the client disconnects after the * three-way handshake has been done in the kernel but before * userland has picked up the socket. */ #ifdef ECONNRESET case ECONNRESET: #endif #ifdef ETIMEDOUT case ETIMEDOUT: #endif #ifdef EHOSTUNREACH case EHOSTUNREACH: #endif #ifdef ENETUNREACH case ENETUNREACH: #endif return 1; default: return 0; } } /********************************************************************** * This works around a problem on Linux 2.0.x and SCO Unixware (maybe * others?). When a connect() is made to a Unix Domain socket, but its * not accept()ed before the web server gets impatient and close()s, an * accept() results in a valid file descriptor, but no data to read. * This causes a block on the first read() - which never returns! * * Another approach to this is to write() to the socket to provoke a * SIGPIPE, but this is a pain because of the FastCGI protocol, the fact * that whatever is written has to be universally ignored by all FastCGI * web servers, and a SIGPIPE handler has to be installed which returns * (or SIGPIPE is ignored). * * READABLE_UNIX_FD_DROP_DEAD_TIMEVAL = 2,0 by default. * * Making it shorter is probably safe, but I'll leave that to you. Making * it 0,0 doesn't work reliably. The shorter you can reliably make it, * the faster your application will be able to recover (waiting 2 seconds * may _cause_ the problem when there is a very high demand). At any rate, * this is better than perma-blocking. */ static int is_af_unix_keeper(const int fd) { struct timeval tval = { READABLE_UNIX_FD_DROP_DEAD_TIMEVAL }; fd_set read_fds; FD_ZERO(&read_fds); FD_SET(fd, &read_fds); return select(fd + 1, &read_fds, NULL, NULL, &tval) >= 0 && FD_ISSET(fd, &read_fds); } /* *---------------------------------------------------------------------- * * OS_Accept -- * * Accepts a new FastCGI connection. This routine knows whether * we're dealing with TCP based sockets or NT Named Pipes for IPC. * * Results: * -1 if the operation fails, otherwise this is a valid IPC fd. * * Side effects: * New IPC connection is accepted. * *---------------------------------------------------------------------- */ int OS_Accept(int listen_sock, int fail_on_intr, const char *webServerAddrs) { int socket = -1; union { struct sockaddr_un un; struct sockaddr_in in; } sa; for (;;) { if (AcquireLock(listen_sock, fail_on_intr)) return -1; for (;;) { do { #ifdef HAVE_SOCKLEN socklen_t len = sizeof(sa); #else int len = sizeof(sa); #endif if (shutdownPending) break; /* There's a window here */ socket = accept(listen_sock, (struct sockaddr *)&sa, &len); } while (socket < 0 && errno == EINTR && ! fail_on_intr && ! shutdownPending); if (socket < 0) { if (shutdownPending || ! is_reasonable_accept_errno(errno)) { int errnoSave = errno; ReleaseLock(listen_sock); if (! shutdownPending) { errno = errnoSave; } return (-1); } errno = 0; } else { /* socket >= 0 */ int set = 1; if (sa.in.sin_family != AF_INET) break; #ifdef TCP_NODELAY /* No replies to outgoing data, so disable Nagle */ setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char *)&set, sizeof(set)); #endif /* Check that the client IP address is approved */ if (ClientAddrOK(&sa.in, webServerAddrs)) break; close(socket); } /* socket >= 0 */ } /* for(;;) */ if (ReleaseLock(listen_sock)) return (-1); if (sa.in.sin_family != AF_UNIX || is_af_unix_keeper(socket)) break; close(socket); } /* while(1) - lock */ return (socket); } /* *---------------------------------------------------------------------- * * OS_IpcClose * * OS IPC routine to close an IPC connection. * * Results: * * * Side effects: * IPC connection is closed. * *---------------------------------------------------------------------- */ int OS_IpcClose(int ipcFd, int shutdown) { return OS_Close(ipcFd, shutdown); } /* *---------------------------------------------------------------------- * * OS_IsFcgi -- * * Determines whether this process is a FastCGI process or not. * * Results: * Returns 1 if FastCGI, 0 if not. * * Side effects: * None. * *---------------------------------------------------------------------- */ int OS_IsFcgi(int sock) { union { struct sockaddr_in in; struct sockaddr_un un; } sa; #ifdef HAVE_SOCKLEN socklen_t len = sizeof(sa); #else int len = sizeof(sa); #endif errno = 0; if (getpeername(sock, (struct sockaddr *)&sa, &len) != 0 && errno == ENOTCONN) { return TRUE; } else { return FALSE; } } /* *---------------------------------------------------------------------- * * OS_SetFlags -- * * Sets selected flag bits in an open file descriptor. * *---------------------------------------------------------------------- */ void OS_SetFlags(int fd, int flags) { int val; if((val = fcntl(fd, F_GETFL, 0)) < 0) { exit(errno); } val |= flags; if(fcntl(fd, F_SETFL, val) < 0) { exit(errno); } } FCGI-0.74/fcgiapp.h0000600000175000017500000004462411637307650012402 0ustar raflrafl/* * fcgiapp.h -- * * Definitions for FastCGI application server programs * * * Copyright (c) 1996 Open Market, Inc. * * See the file "LICENSE.TERMS" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * $Id: fcgiapp.h,v 1.14 2003/06/22 00:16:44 robs Exp $ */ #ifndef _FCGIAPP_H #define _FCGIAPP_H /* Hack to see if we are building TCL - TCL needs varargs not stdarg */ #ifndef TCL_LIBRARY #include #else #include #endif #ifndef DLLAPI #ifdef _WIN32 #define DLLAPI __declspec(dllimport) #else #define DLLAPI #endif #endif #if defined (c_plusplus) || defined (__cplusplus) extern "C" { #endif /* * Error codes. Assigned to avoid conflict with EOF and errno(2). */ #define FCGX_UNSUPPORTED_VERSION -2 #define FCGX_PROTOCOL_ERROR -3 #define FCGX_PARAMS_ERROR -4 #define FCGX_CALL_SEQ_ERROR -5 /* * This structure defines the state of a FastCGI stream. * Streams are modeled after the FILE type defined in stdio.h. * (We wouldn't need our own if platform vendors provided a * standard way to subclass theirs.) * The state of a stream is private and should only be accessed * by the procedures defined below. */ typedef struct FCGX_Stream { unsigned char *rdNext; /* reader: first valid byte * writer: equals stop */ unsigned char *wrNext; /* writer: first free byte * reader: equals stop */ unsigned char *stop; /* reader: last valid byte + 1 * writer: last free byte + 1 */ unsigned char *stopUnget; /* reader: first byte of current buffer * fragment, for ungetc * writer: undefined */ int isReader; int isClosed; int wasFCloseCalled; int FCGI_errno; /* error status */ void (*fillBuffProc) (struct FCGX_Stream *stream); void (*emptyBuffProc) (struct FCGX_Stream *stream, int doClose); void *data; } FCGX_Stream; /* * An environment (as defined by environ(7)): A NULL-terminated array * of strings, each string having the form name=value. */ typedef char **FCGX_ParamArray; /* * FCGX_Request Flags * * Setting FCGI_FAIL_ACCEPT_ON_INTR prevents FCGX_Accept() from * restarting upon being interrupted. */ #define FCGI_FAIL_ACCEPT_ON_INTR 1 /* * FCGX_Request -- State associated with a request. * * Its exposed for API simplicity, I expect parts of it to change! */ typedef struct FCGX_Request { int requestId; /* valid if isBeginProcessed */ int role; FCGX_Stream *in; FCGX_Stream *out; FCGX_Stream *err; char **envp; /* Don't use anything below here */ struct Params *paramsPtr; int ipcFd; /* < 0 means no connection */ int isBeginProcessed; /* FCGI_BEGIN_REQUEST seen */ int keepConnection; /* don't close ipcFd at end of request */ int appStatus; int nWriters; /* number of open writers (0..2) */ int flags; int listen_sock; int detached; } FCGX_Request; /* *====================================================================== * Control *====================================================================== */ /* *---------------------------------------------------------------------- * * FCGX_IsCGI -- * * Returns TRUE iff this process appears to be a CGI process * rather than a FastCGI process. * *---------------------------------------------------------------------- */ DLLAPI int FCGX_IsCGI(void); /* *---------------------------------------------------------------------- * * FCGX_Init -- * * Initialize the FCGX library. Call in multi-threaded apps * before calling FCGX_Accept_r(). * * Returns 0 upon success. * *---------------------------------------------------------------------- */ DLLAPI int FCGX_Init(void); /* *---------------------------------------------------------------------- * * FCGX_OpenSocket -- * * Create a FastCGI listen socket. * * path is the Unix domain socket (named pipe for WinNT), or a colon * followed by a port number. e.g. "/tmp/fastcgi/mysocket", ":5000" * * backlog is the listen queue depth used in the listen() call. * * Returns the socket's file descriptor or -1 on error. * *---------------------------------------------------------------------- */ DLLAPI int FCGX_OpenSocket(const char *path, int backlog); /* *---------------------------------------------------------------------- * * FCGX_InitRequest -- * * Initialize a FCGX_Request for use with FCGX_Accept_r(). * * sock is a file descriptor returned by FCGX_OpenSocket() or 0 (default). * The only supported flag at this time is FCGI_FAIL_ON_INTR. * * Returns 0 upon success. *---------------------------------------------------------------------- */ DLLAPI int FCGX_InitRequest(FCGX_Request *request, int sock, int flags); /* *---------------------------------------------------------------------- * * FCGX_Accept_r -- * * Accept a new request (multi-thread safe). Be sure to call * FCGX_Init() first. * * Results: * 0 for successful call, -1 for error. * * Side effects: * * Finishes the request accepted by (and frees any * storage allocated by) the previous call to FCGX_Accept. * Creates input, output, and error streams and * assigns them to *in, *out, and *err respectively. * Creates a parameters data structure to be accessed * via getenv(3) (if assigned to environ) or by FCGX_GetParam * and assigns it to *envp. * * DO NOT retain pointers to the envp array or any strings * contained in it (e.g. to the result of calling FCGX_GetParam), * since these will be freed by the next call to FCGX_Finish * or FCGX_Accept. * * DON'T use the FCGX_Request, its structure WILL change. * *---------------------------------------------------------------------- */ DLLAPI int FCGX_Accept_r(FCGX_Request *request); /* *---------------------------------------------------------------------- * * FCGX_Finish_r -- * * Finish the request (multi-thread safe). * * Side effects: * * Finishes the request accepted by (and frees any * storage allocated by) the previous call to FCGX_Accept. * * DO NOT retain pointers to the envp array or any strings * contained in it (e.g. to the result of calling FCGX_GetParam), * since these will be freed by the next call to FCGX_Finish * or FCGX_Accept. * *---------------------------------------------------------------------- */ DLLAPI void FCGX_Finish_r(FCGX_Request *request); /* *---------------------------------------------------------------------- * * FCGX_Free -- * * Free the memory and, if close is true, * IPC FD associated with the request (multi-thread safe). * *---------------------------------------------------------------------- */ DLLAPI void FCGX_Free(FCGX_Request * request, int close); /* *---------------------------------------------------------------------- * * FCGX_Accept -- * * Accept a new request (NOT multi-thread safe). * * Results: * 0 for successful call, -1 for error. * * Side effects: * * Finishes the request accepted by (and frees any * storage allocated by) the previous call to FCGX_Accept. * Creates input, output, and error streams and * assigns them to *in, *out, and *err respectively. * Creates a parameters data structure to be accessed * via getenv(3) (if assigned to environ) or by FCGX_GetParam * and assigns it to *envp. * * DO NOT retain pointers to the envp array or any strings * contained in it (e.g. to the result of calling FCGX_GetParam), * since these will be freed by the next call to FCGX_Finish * or FCGX_Accept. * *---------------------------------------------------------------------- */ DLLAPI int FCGX_Accept( FCGX_Stream **in, FCGX_Stream **out, FCGX_Stream **err, FCGX_ParamArray *envp); /* *---------------------------------------------------------------------- * * FCGX_Finish -- * * Finish the current request (NOT multi-thread safe). * * Side effects: * * Finishes the request accepted by (and frees any * storage allocated by) the previous call to FCGX_Accept. * * DO NOT retain pointers to the envp array or any strings * contained in it (e.g. to the result of calling FCGX_GetParam), * since these will be freed by the next call to FCGX_Finish * or FCGX_Accept. * *---------------------------------------------------------------------- */ DLLAPI void FCGX_Finish(void); /* *---------------------------------------------------------------------- * * FCGX_StartFilterData -- * * stream is an input stream for a FCGI_FILTER request. * stream is positioned at EOF on FCGI_STDIN. * Repositions stream to the start of FCGI_DATA. * If the preconditions are not met (e.g. FCGI_STDIN has not * been read to EOF) sets the stream error code to * FCGX_CALL_SEQ_ERROR. * * Results: * 0 for a normal return, < 0 for error * *---------------------------------------------------------------------- */ DLLAPI int FCGX_StartFilterData(FCGX_Stream *stream); /* *---------------------------------------------------------------------- * * FCGX_SetExitStatus -- * * Sets the exit status for stream's request. The exit status * is the status code the request would have exited with, had * the request been run as a CGI program. You can call * SetExitStatus several times during a request; the last call * before the request ends determines the value. * *---------------------------------------------------------------------- */ DLLAPI void FCGX_SetExitStatus(int status, FCGX_Stream *stream); /* *====================================================================== * Parameters *====================================================================== */ /* *---------------------------------------------------------------------- * * FCGX_GetParam -- obtain value of FCGI parameter in environment * * * Results: * Value bound to name, NULL if name not present in the * environment envp. Caller must not mutate the result * or retain it past the end of this request. * *---------------------------------------------------------------------- */ DLLAPI char *FCGX_GetParam(const char *name, FCGX_ParamArray envp); /* *====================================================================== * Readers *====================================================================== */ /* *---------------------------------------------------------------------- * * FCGX_GetChar -- * * Reads a byte from the input stream and returns it. * * Results: * The byte, or EOF (-1) if the end of input has been reached. * *---------------------------------------------------------------------- */ DLLAPI int FCGX_GetChar(FCGX_Stream *stream); /* *---------------------------------------------------------------------- * * FCGX_UnGetChar -- * * Pushes back the character c onto the input stream. One * character of pushback is guaranteed once a character * has been read. No pushback is possible for EOF. * * Results: * Returns c if the pushback succeeded, EOF if not. * *---------------------------------------------------------------------- */ DLLAPI int FCGX_UnGetChar(int c, FCGX_Stream *stream); /* *---------------------------------------------------------------------- * * FCGX_GetStr -- * * Reads up to n consecutive bytes from the input stream * into the character array str. Performs no interpretation * of the input bytes. * * Results: * Number of bytes read. If result is smaller than n, * the end of input has been reached. * *---------------------------------------------------------------------- */ DLLAPI int FCGX_GetStr(char *str, int n, FCGX_Stream *stream); /* *---------------------------------------------------------------------- * * FCGX_GetLine -- * * Reads up to n-1 consecutive bytes from the input stream * into the character array str. Stops before n-1 bytes * have been read if '\n' or EOF is read. The terminating '\n' * is copied to str. After copying the last byte into str, * stores a '\0' terminator. * * Results: * NULL if EOF is the first thing read from the input stream, * str otherwise. * *---------------------------------------------------------------------- */ DLLAPI char *FCGX_GetLine(char *str, int n, FCGX_Stream *stream); /* *---------------------------------------------------------------------- * * FCGX_HasSeenEOF -- * * Returns EOF if end-of-file has been detected while reading * from stream; otherwise returns 0. * * Note that FCGX_HasSeenEOF(s) may return 0, yet an immediately * following FCGX_GetChar(s) may return EOF. This function, like * the standard C stdio function feof, does not provide the * ability to peek ahead. * * Results: * EOF if end-of-file has been detected, 0 if not. * *---------------------------------------------------------------------- */ DLLAPI int FCGX_HasSeenEOF(FCGX_Stream *stream); /* *====================================================================== * Writers *====================================================================== */ /* *---------------------------------------------------------------------- * * FCGX_PutChar -- * * Writes a byte to the output stream. * * Results: * The byte, or EOF (-1) if an error occurred. * *---------------------------------------------------------------------- */ DLLAPI int FCGX_PutChar(int c, FCGX_Stream *stream); /* *---------------------------------------------------------------------- * * FCGX_PutStr -- * * Writes n consecutive bytes from the character array str * into the output stream. Performs no interpretation * of the output bytes. * * Results: * Number of bytes written (n) for normal return, * EOF (-1) if an error occurred. * *---------------------------------------------------------------------- */ DLLAPI int FCGX_PutStr(const char *str, int n, FCGX_Stream *stream); /* *---------------------------------------------------------------------- * * FCGX_PutS -- * * Writes a null-terminated character string to the output stream. * * Results: * number of bytes written for normal return, * EOF (-1) if an error occurred. * *---------------------------------------------------------------------- */ DLLAPI int FCGX_PutS(const char *str, FCGX_Stream *stream); /* *---------------------------------------------------------------------- * * FCGX_FPrintF, FCGX_VFPrintF -- * * Performs printf-style output formatting and writes the results * to the output stream. * * Results: * number of bytes written for normal return, * EOF (-1) if an error occurred. * *---------------------------------------------------------------------- */ DLLAPI int FCGX_FPrintF(FCGX_Stream *stream, const char *format, ...); DLLAPI int FCGX_VFPrintF(FCGX_Stream *stream, const char *format, va_list arg); /* *---------------------------------------------------------------------- * * FCGX_FFlush -- * * Flushes any buffered output. * * Server-push is a legitimate application of FCGX_FFlush. * Otherwise, FCGX_FFlush is not very useful, since FCGX_Accept * does it implicitly. Calling FCGX_FFlush in non-push applications * results in extra writes and therefore reduces performance. * * Results: * EOF (-1) if an error occurred. * *---------------------------------------------------------------------- */ DLLAPI int FCGX_FFlush(FCGX_Stream *stream); /* *====================================================================== * Both Readers and Writers *====================================================================== */ /* *---------------------------------------------------------------------- * * FCGX_FClose -- * * Closes the stream. For writers, flushes any buffered * output. * * Close is not a very useful operation since FCGX_Accept * does it implicitly. Closing the out stream before the * err stream results in an extra write if there's nothing * in the err stream, and therefore reduces performance. * * Results: * EOF (-1) if an error occurred. * *---------------------------------------------------------------------- */ DLLAPI int FCGX_FClose(FCGX_Stream *stream); /* *---------------------------------------------------------------------- * * FCGX_GetError -- * * Return the stream error code. 0 means no error, > 0 * is an errno(2) error, < 0 is an FastCGI error. * *---------------------------------------------------------------------- */ DLLAPI int FCGX_GetError(FCGX_Stream *stream); /* *---------------------------------------------------------------------- * * FCGX_ClearError -- * * Clear the stream error code and end-of-file indication. * *---------------------------------------------------------------------- */ DLLAPI void FCGX_ClearError(FCGX_Stream *stream); /* *---------------------------------------------------------------------- * * FCGX_CreateWriter -- * * Create a FCGX_Stream (used by cgi-fcgi). This shouldn't * be needed by a FastCGI applictaion. * *---------------------------------------------------------------------- */ DLLAPI FCGX_Stream *FCGX_CreateWriter( int socket, int requestId, int bufflen, int streamType); /* *---------------------------------------------------------------------- * * FCGX_FreeStream -- * * Free a FCGX_Stream (used by cgi-fcgi). This shouldn't * be needed by a FastCGI applictaion. * *---------------------------------------------------------------------- */ DLLAPI void FCGX_FreeStream(FCGX_Stream **stream); /* ---------------------------------------------------------------------- * * Prevent the lib from accepting any new requests. Signal handler safe. * * ---------------------------------------------------------------------- */ DLLAPI void FCGX_ShutdownPending(void); /* * Attach/Detach an accepted request from its listen socket. * XXX This is not fully implemented at this time (patch welcome). */ DLLAPI int FCGX_Attach(FCGX_Request * r); DLLAPI int FCGX_Detach(FCGX_Request * r); #if defined (__cplusplus) || defined (c_plusplus) } /* terminate extern "C" { */ #endif #endif /* _FCGIAPP_H */ FCGI-0.74/threaded.PL0000644000175000017500000000204511417356077012637 0ustar raflrafluse Config; open OUT, ">threaded.fpl"; print OUT "#!$Config{perlpath}\n"; print OUT while ; close OUT; chmod 0755, "threaded.fpl"; __END__ use FCGI; use Thread; use IO::Handle; use constant THREAD_COUNT => 5; sub doit { my $k = shift; my %env; my $in = new IO::Handle; my $out = new IO::Handle; my $err = new IO::Handle; my $request = FCGI::Request($in, $out, $err, \%env); while ($request->Accept() >= 0) { print $out "Content-type: text/html\r\n", "\r\n", "FastCGI Hello! (multi-threaded perl, fcgiapp library)", "

FastCGI Hello! (multi-threaded perl, fcgiapp library)

", "Request counts for ", THREAD_COUNT ," threads ", "running on host $env{SERVER_NAME}

"; { lock(@count); ++$count[$k]; for(my $i = 0; $i < THREAD_COUNT; ++$i) { print $out $count[$i]; print $out " "; } } $request->Flush(); sleep(1); } } for ($t = 1; $t < THREAD_COUNT; ++$t) { new Thread \&doit, $t; } doit(0); FCGI-0.74/fcgimisc.h0000600000175000017500000000117611637307650012550 0ustar raflrafl/* * fcgimisc.h -- * * Miscellaneous definitions * * * Copyright (c) 1996 Open Market, Inc. * * See the file "LICENSE.TERMS" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * $Id: fcgimisc.h,v 1.3 2001/06/18 14:25:47 robs Exp $ */ #ifndef _FCGIMISC_H #define _FCGIMISC_H #ifndef FALSE #define FALSE (0) #endif #ifndef TRUE #define TRUE (1) #endif #ifndef min #define min(a,b) ((a) < (b) ? (a) : (b)) #endif #ifndef max #define max(a,b) ((a) > (b) ? (a) : (b)) #endif #ifndef ASSERT #define ASSERT(assertion) assert(assertion) #endif #endif /* _FCGIMISC_H */ FCGI-0.74/configure0000755000175000017500000037715711637307640012550 0ustar raflrafl#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.68. # # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, # 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software # Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV export CONFIG_SHELL case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"} fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in #( -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME= PACKAGE_TARNAME= PACKAGE_VERSION= PACKAGE_STRING= PACKAGE_BUGREPORT= PACKAGE_URL= # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='LTLIBOBJS LIBOBJS EGREP GREP CPP OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host. If a cross compiler is detected then cross compile mode will be used" >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures this package to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF _ACEOF fi if test -n "$ac_init_help"; then cat <<\_ACEOF Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF configure generated by GNU Autoconf 2.68 Copyright (C) 2010 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache # variable VAR accordingly. ac_fn_c_check_type () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof ($2)) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof (($2))) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else eval "$3=yes" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by $as_me, which was generated by GNU Autoconf 2.68. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_config_headers="$ac_config_headers fcgi_config.h" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done ac_fn_c_check_type "$LINENO" "ssize_t" "ac_cv_type_ssize_t" "$ac_includes_default" if test "x$ac_cv_type_ssize_t" = xyes; then : else cat >>confdefs.h <<_ACEOF #define ssize_t int _ACEOF fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sun_len in sys/un.h" >&5 $as_echo_n "checking for sun_len in sys/un.h... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "sun_len" >/dev/null 2>&1; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_SOCKADDR_UN_SUN_LEN 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f conftest* { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fpos_t in stdio.h" >&5 $as_echo_n "checking for fpos_t in stdio.h... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "fpos_t" >/dev/null 2>&1; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_FPOS 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f conftest* for ac_header in sys/socket.h netdb.h netinet/in.h arpa/inet.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in sys/time.h limits.h sys/param.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a fileno() prototype in stdio.h" >&5 $as_echo_n "checking for a fileno() prototype in stdio.h... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "fileno" >/dev/null 2>&1; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_FILENO_PROTO 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f conftest* if test "$HAVE_SYS_SOCKET_H"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for socklen_t in sys/socket.h" >&5 $as_echo_n "checking for socklen_t in sys/socket.h... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "socklen_t" >/dev/null 2>&1; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_SOCKLEN 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f conftest* fi #-------------------------------------------------------------------- # Do we need cross-process locking on this platform? #-------------------------------------------------------------------- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether cross-process locking is required by accept()" >&5 $as_echo_n "checking whether cross-process locking is required by accept()... " >&6; } case "`uname -sr`" in IRIX\ 5.* | SunOS\ 5.* | UNIX_System_V\ 4.0) { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define USE_LOCKING 1" >>confdefs.h ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } ;; esac #-------------------------------------------------------------------- # Does va_arg(arg, long double) crash the compiler? # hpux 9.04 compiler does and so does Stratus FTX (uses HP's compiler) #-------------------------------------------------------------------- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether va_arg(arg, long double) crashes the compiler" >&5 $as_echo_n "checking whether va_arg(arg, long double) crashes the compiler... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { long double lDblArg; va_list arg; lDblArg = va_arg(arg, long double); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_VA_ARG_LONG_DOUBLE_BUG 1" >>confdefs.h fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 $as_echo_n "checking for an ANSI C-conforming const... " >&6; } if ${ac_cv_c_const+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { /* FIXME: Include the comments suggested by Paul. */ #ifndef __cplusplus /* Ultrix mips cc rejects this. */ typedef int charset[2]; const charset cs; /* SunOS 4.1.1 cc rejects this. */ char const *const *pcpcc; char **ppc; /* NEC SVR4.0.2 mips cc rejects this. */ struct point {int x, y;}; static struct point const zero = {0,0}; /* AIX XL C 1.02.0.0 rejects this. It does not let you subtract one const X* pointer from another in an arm of an if-expression whose if-part is not a constant expression */ const char *g = "string"; pcpcc = &g + (g ? g-g : 0); /* HPUX 7.0 cc rejects these. */ ++pcpcc; ppc = (char**) pcpcc; pcpcc = (char const *const *) ppc; { /* SCO 3.2v4 cc rejects this. */ char *t; char const *s = 0 ? (char *) 0 : (char const *) 0; *t++ = 0; if (s) return 0; } { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ int x[] = {25, 17}; const int *foo = &x[0]; ++foo; } { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ typedef const int *iptr; iptr p = 0; ++p; } { /* AIX XL C 1.02.0.0 rejects this saying "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ struct s { int j; const int *ap[3]; }; struct s *b; b->j = 5; } { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ const int foo = 10; if (!foo) return 0; } return !cs[0] && !zero.x; #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_const=yes else ac_cv_c_const=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5 $as_echo "$ac_cv_c_const" >&6; } if test $ac_cv_c_const = no; then $as_echo "#define const /**/" >>confdefs.h fi cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in #( -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by $as_me, which was generated by GNU Autoconf 2.68. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_headers="$ac_config_headers" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration headers: $config_headers Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ config.status configured by $0, generated by GNU Autoconf 2.68, with options \\"\$ac_cs_config\\" Copyright (C) 2010 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "fcgi_config.h") CONFIG_HEADERS="$CONFIG_HEADERS fcgi_config.h" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :H $CONFIG_HEADERS " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi FCGI-0.74/configure.in0000644000175000017500000000056111417356077013134 0ustar raflrafldnl $Id: configure.in,v 1.9 2001/09/22 09:30:45 skimo Exp $ dnl dnl This file is an input file used by the GNU "autoconf" program to dnl generate the file "configure", which is run during the build dnl to configure the system for the local environment. AC_INIT AM_CONFIG_HEADER([fcgi_config.h]) AC_PROG_CC AC_PROG_CPP FCGI_COMMON_CHECKS AC_OUTPUT FCGI-0.74/Makefile.PL0000644000175000017500000001134411570050037012561 0ustar raflrafl# $Id: Makefile.PL,v 1.33 2002/12/15 19:40:19 skimo Exp $ use ExtUtils::MakeMaker; use IO::File; use Config; use Cwd 'cwd'; use Getopt::Long; use File::Copy qw(copy); @h1 = qw(fastcgi.h fcgiapp.h fcgimisc.h fcgios.h); @h = (@h1, 'fcgi_config.h'); @o = qw(FCGI.o); @dist1 = qw(LICENSE.TERMS); @dist2 = qw(fcgiapp.c os_unix.c os_win32.c); @dist3 = (@h1, qw(fcgi_config_x86.h)); GetOptions ("pure-perl!" => \$pure, "use-installed:s" => \$useinstalled); $pure = "0" unless defined $pure; open(CFG,">FCGI.cfg"); print CFG "\$pure = $pure;1;\n"; close CFG; $libfound = 0; @libs = (); if (! $pure) { my $cwd = cwd(); my $devkit = "$cwd/.."; if (defined $useinstalled) { require ExtUtils::Liblist; my $libspec = $useinstalled ? "-L$useinstalled/lib " : ""; $libspec .= "-lfcgi"; my @l = MM->ext($libspec); if ($l[0] || $l[1] || $l[2]) { $prefix = "$useinstalled/include" if $useinstalled; $libfound = 1; push @libs, $libspec; } } if (!$libfound && -d "$devkit/libfcgi" && -d "$devkit/include") { # devkit if (grep { ! -f "$devkit/include/$_" } @dist3 or grep { ! -f "$devkit/libfcgi/$_" } @dist2) { warn "This appears to be a FastCGI devkit distribution, " . "but one or more FastCGI library files are missing. \n" . "Please check the integrity of the distribution.\n"; exit -1; } my $extrarules = join "\n", map { $b = $_; $b =~ s/\.c$//; my $s="$devkit/libfcgi/$b.c"; "$b\$(OBJ_EXT): $s\n\t". '$(CCCMD) $(CCCDLFLAGS) -I$(PERL_INC) $(DEFINE) '."$s\n"; } @dist2; eval 'package MY; sub postamble { $extrarules; }'; $prefix = $devkit; } } $sys = $^O eq 'MSWin32' ? 'win32' : 'unix'; push @o, "fcgiapp.o", "os_$sys.o" unless $libfound; $inc = '-I.' unless $libfound; $inc .= " -I$prefix/include" if $prefix; push(@extras, CAPI => 'TRUE') if ($] >= 5.005 and $^O eq 'MSWin32' and $Config{archname} =~ /-object\b/i); push(@extras, ABSTRACT => 'Fast CGI module', AUTHOR => 'Sven Verdoolaege (skimo@kotnet.org)' ) if ($ExtUtils::MakeMaker::VERSION >= 5.4301); push @extras, META_MERGE => { resources => { repository => 'git://git.shadowcat.co.uk/catagits/fcgi2.git', }, } if $ExtUtils::MakeMaker::VERSION >= 6.46; $plfiles = { 'echo.PL' => 'echo.fpl', 'remote.PL' => 'remote.fpl', 'threaded.PL' => 'threaded.fpl', 'FCGI.PL' => 'FCGI.pm', }; $plfiles->{'FCGI.XL'} = 'FCGI.xs' unless $pure; if ($pure) { push @extras, LINKTYPE => ' '; } else { if ("$sys" eq "win32") { push @libs, ":nosearch -lws2_32"; push @extras, 'DEFINE' => '-DDLLAPI=__declspec(dllexport)'; } push @extras, 'LIBS' => [ "@libs" ], 'OBJECT' => "@o", 'INC' => $inc; } # See lib/ExtUtils/MakeMaker.pm for details of how to influence # the contents of the Makefile that is written. # Work around bug in previous versions of MakeMaker WriteMakefile( 'NAME' => 'FCGI', 'VERSION_FROM' => 'version.pm', 'dist' => { 'COMPRESS' => 'gzip -9f', 'SUFFIX' => 'gz', 'PREOP' => '$(CP) '.join(' ', map {"../$_"} @dist1, (map {"libfcgi/$_"} @dist2), map {"include/$_"} @dist3).' $(DISTVNAME);'. '$(CP) MANIFEST MANIFEST.old;'. '$(ECHO) '. join('\\\n',@dist1,@dist2,@dist3) . '>> $(DISTVNAME)/MANIFEST', 'POSTOP' => '$(MV) MANIFEST.old MANIFEST', }, 'clean' => { FILES => 'config.cache fcgi_config.h' . ' FCGI.xs FCGI.c FCGI.cfg ' . (join ' ', values %$plfiles)}, 'PL_FILES' => $plfiles, PM => {'FCGI.pm' => '$(INST_ARCHLIBDIR)/FCGI.pm'}, @extras, ); exit if -f 'fcgi_config.h' or $libfound or $pure; # CPAN and no installed lib found if ($sys eq "win32") { # configure will almost certainly not run on a normal NT install, # use the pregenerated configuration file print "Using prebuilt fcgi_config.h file for Windows\n"; unlink("fcgi_config.h"); my $confdir = $prefix ? "$prefix/include/" : ''; die $! unless copy("${confdir}fcgi_config_x86.h","fcgi_config.h"); # Win can't deal with existence of FCGI.xs or absence of FCGI.c unlink("FCGI.xs"); open(F, ">FCGI.c"); close(F); $now = time; $before = $now - 600; utime $before, $before, "FCGI.c"; utime $now, $now, "FCGI.PL"; } else { print "Running ./configure for you\n"; print "Please read configure.readme for information on how to run it yourself\n"; $ENV{'CC'} = $Config{'cc'}; system("$Config{sh} configure"); } FCGI-0.74/fcgios.h0000711000175000017500000000677411637307650012252 0ustar raflrafl/* * fcgios.h -- * * Description of file. * * * Copyright (c) 1996 Open Market, Inc. * All rights reserved. * * This file contains proprietary and confidential information and * remains the unpublished property of Open Market, Inc. Use, * disclosure, or reproduction is prohibited except as permitted by * express written license agreement with Open Market, Inc. * * Bill Snapper * snapper@openmarket.com */ #ifndef _FCGIOS_H #define _FCGIOS_H #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include #include #endif #include "fcgi_config.h" #ifdef HAVE_SYS_TIME_H #include #endif #ifdef HAVE_SYS_TYPES_H #include #endif #if defined (c_plusplus) || defined (__cplusplus) extern "C" { #endif #ifdef _WIN32 #define OS_Errno GetLastError() #define OS_SetErrno(err) SetLastError(err) #ifndef O_NONBLOCK #define O_NONBLOCK 0x0004 /* no delay */ #endif #else /* !_WIN32 */ #define OS_Errno errno #define OS_SetErrno(err) errno = (err) #endif /* !_WIN32 */ #ifndef DLLAPI #ifdef _WIN32 #define DLLAPI __declspec(dllimport) #else #define DLLAPI #endif #endif /* This is the initializer for a "struct timeval" used in a select() call * right after a new request is accept()ed to determine readablity. Its * a drop-dead timer. Its only used for AF_UNIX sockets (not TCP sockets). * Its a workaround for a kernel bug in Linux 2.0.x and SCO Unixware. * Making this as small as possible, yet remain reliable would be best. * 2 seconds is very conservative. 0,0 is not reliable. The shorter the * timeout, the faster request processing will recover. The longer the * timeout, the more likely this application being "busy" will cause other * requests to abort and cause more dead sockets that need this timeout. */ #define READABLE_UNIX_FD_DROP_DEAD_TIMEVAL 2,0 #ifndef STDIN_FILENO #define STDIN_FILENO 0 #endif #ifndef STDOUT_FILENO #define STDOUT_FILENO 1 #endif #ifndef STDERR_FILENO #define STDERR_FILENO 2 #endif #ifndef MAXPATHLEN #define MAXPATHLEN 1024 #endif #ifndef X_OK #define X_OK 0x01 #endif #ifndef _CLIENTDATA # if defined(__STDC__) || defined(__cplusplus) typedef void *ClientData; # else typedef int *ClientData; # endif /* __STDC__ */ #define _CLIENTDATA #endif typedef void (*OS_AsyncProc) (ClientData clientData, int len); DLLAPI int OS_LibInit(int stdioFds[3]); DLLAPI void OS_LibShutdown(void); DLLAPI int OS_CreateLocalIpcFd(const char *bindPath, int backlog); DLLAPI int OS_FcgiConnect(char *bindPath); DLLAPI int OS_Read(int fd, char * buf, size_t len); DLLAPI int OS_Write(int fd, char * buf, size_t len); DLLAPI int OS_SpawnChild(char *execPath, int listenFd); DLLAPI int OS_AsyncReadStdin(void *buf, int len, OS_AsyncProc procPtr, ClientData clientData); DLLAPI int OS_AsyncRead(int fd, int offset, void *buf, int len, OS_AsyncProc procPtr, ClientData clientData); DLLAPI int OS_AsyncWrite(int fd, int offset, void *buf, int len, OS_AsyncProc procPtr, ClientData clientData); DLLAPI int OS_Close(int fd, int shutdown); DLLAPI int OS_CloseRead(int fd); DLLAPI int OS_DoIo(struct timeval *tmo); DLLAPI int OS_Accept(int listen_sock, int fail_on_intr, const char *webServerAddrs); DLLAPI int OS_IpcClose(int ipcFd, int shutdown); DLLAPI int OS_IsFcgi(int sock); DLLAPI void OS_SetFlags(int fd, int flags); DLLAPI void OS_ShutdownPending(void); #if defined (__cplusplus) || defined (c_plusplus) } /* terminate extern "C" { */ #endif #endif /* _FCGIOS_H */ FCGI-0.74/test.pl0000644000175000017500000000013211561774552012133 0ustar raflrafluse Test; BEGIN { plan tests => 1 }; use FCGI; ok(1); # If we made it this far, we're ok. FCGI-0.74/LICENSE.TERMS0000711000175000017500000000323711637307650012514 0ustar raflraflThis FastCGI application library source and object code (the "Software") and its documentation (the "Documentation") are copyrighted by Open Market, Inc ("Open Market"). The following terms apply to all files associated with the Software and Documentation unless explicitly disclaimed in individual files. Open Market permits you to use, copy, modify, distribute, and license this Software and the Documentation for any purpose, provided that existing copyright notices are retained in all copies and that this notice is included verbatim in any distributions. No written agreement, license, or royalty fee is required for any of the authorized uses. Modifications to this Software and Documentation may be copyrighted by their authors and need not follow the licensing terms described here. If modifications to this Software and Documentation have new licensing terms, the new terms must be clearly indicated on the first page of each file where they apply. OPEN MARKET MAKES NO EXPRESS OR IMPLIED WARRANTY WITH RESPECT TO THE SOFTWARE OR THE DOCUMENTATION, INCLUDING WITHOUT LIMITATION ANY WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL OPEN MARKET BE LIABLE TO YOU OR ANY THIRD PARTY FOR ANY DAMAGES ARISING FROM OR RELATING TO THIS SOFTWARE OR THE DOCUMENTATION, INCLUDING, WITHOUT LIMITATION, ANY INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR SIMILAR DAMAGES, INCLUDING LOST PROFITS OR LOST DATA, EVEN IF OPEN MARKET HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS". OPEN MARKET HAS NO LIABILITY IN CONTRACT, TORT, NEGLIGENCE OR OTHERWISE ARISING OUT OF THIS SOFTWARE OR THE DOCUMENTATION. FCGI-0.74/fcgi_config_x86.h0000600000175000017500000000164211637307650013724 0ustar raflrafl/* * Copied to fcgi_config.h when building on WinNT without cygwin, * i.e. configure is not run. See fcgi_config.h.in for details. */ #define HAVE_FPOS 1 #define HAVE_LIMITS_H 1 #define HAVE_STREAMBUF_CHAR_TYPE 1 #define HAVE_STRERROR 1 #undef HAVE_ARPA_INET_H #undef HAVE_DLFCN_H #undef HAVE_FILENO_PROTO #undef HAVE_INTTYPES_H #undef HAVE_IOSTREAM_WITHASSIGN_STREAMBUF #undef HAVE_LIBNSL #undef HAVE_LIBSOCKET #undef HAVE_MEMORY_H #undef HAVE_NETDB_H #undef HAVE_NETINET_IN_H #undef HAVE_PTHREAD #undef HAVE_SOCKADDR_UN_SUN_LEN #undef HAVE_SOCKLEN #undef HAVE_STDINT_H #undef HAVE_STDLIB_H #undef HAVE_STRING_H #undef HAVE_STRINGS_H #undef HAVE_SYS_PARAM_H #undef HAVE_SYS_SOCKET_H #undef HAVE_SYS_STAT_H #undef HAVE_SYS_TIME_H #undef HAVE_SYS_TYPES_H #undef HAVE_UNISTD_H #undef HAVE_VA_ARG_LONG_DOUBLE_BUG #undef PTHREAD_CREATE_JOINABLE #undef STDC_HEADERS #undef USE_LOCKING #undef const #undef inline #undef ssize_t FCGI-0.74/META.json0000600000175000017500000000164611637307650012236 0ustar raflrafl{ "abstract" : "Fast CGI module", "author" : [ "Sven Verdoolaege (skimo@kotnet.org)" ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 6.59, CPAN::Meta::Converter version 2.112150", "license" : [ "unknown" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : "2" }, "name" : "FCGI", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : 0 } }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : 0 } }, "runtime" : { "requires" : {} } }, "release_status" : "stable", "resources" : { "repository" : { "url" : "git://git.shadowcat.co.uk/catagits/fcgi2.git" } }, "version" : "0.74" } FCGI-0.74/fastcgi.h0000600000175000017500000000562511637307650012407 0ustar raflrafl/* * fastcgi.h -- * * Defines for the FastCGI protocol. * * * Copyright (c) 1995-1996 Open Market, Inc. * * See the file "LICENSE.TERMS" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * $Id: fastcgi.h,v 1.1 1997/09/16 15:36:32 stanleyg Exp $ */ #ifndef _FASTCGI_H #define _FASTCGI_H /* * Listening socket file number */ #define FCGI_LISTENSOCK_FILENO 0 typedef struct { unsigned char version; unsigned char type; unsigned char requestIdB1; unsigned char requestIdB0; unsigned char contentLengthB1; unsigned char contentLengthB0; unsigned char paddingLength; unsigned char reserved; } FCGI_Header; #define FCGI_MAX_LENGTH 0xffff /* * Number of bytes in a FCGI_Header. Future versions of the protocol * will not reduce this number. */ #define FCGI_HEADER_LEN 8 /* * Value for version component of FCGI_Header */ #define FCGI_VERSION_1 1 /* * Values for type component of FCGI_Header */ #define FCGI_BEGIN_REQUEST 1 #define FCGI_ABORT_REQUEST 2 #define FCGI_END_REQUEST 3 #define FCGI_PARAMS 4 #define FCGI_STDIN 5 #define FCGI_STDOUT 6 #define FCGI_STDERR 7 #define FCGI_DATA 8 #define FCGI_GET_VALUES 9 #define FCGI_GET_VALUES_RESULT 10 #define FCGI_UNKNOWN_TYPE 11 #define FCGI_MAXTYPE (FCGI_UNKNOWN_TYPE) /* * Value for requestId component of FCGI_Header */ #define FCGI_NULL_REQUEST_ID 0 typedef struct { unsigned char roleB1; unsigned char roleB0; unsigned char flags; unsigned char reserved[5]; } FCGI_BeginRequestBody; typedef struct { FCGI_Header header; FCGI_BeginRequestBody body; } FCGI_BeginRequestRecord; /* * Mask for flags component of FCGI_BeginRequestBody */ #define FCGI_KEEP_CONN 1 /* * Values for role component of FCGI_BeginRequestBody */ #define FCGI_RESPONDER 1 #define FCGI_AUTHORIZER 2 #define FCGI_FILTER 3 typedef struct { unsigned char appStatusB3; unsigned char appStatusB2; unsigned char appStatusB1; unsigned char appStatusB0; unsigned char protocolStatus; unsigned char reserved[3]; } FCGI_EndRequestBody; typedef struct { FCGI_Header header; FCGI_EndRequestBody body; } FCGI_EndRequestRecord; /* * Values for protocolStatus component of FCGI_EndRequestBody */ #define FCGI_REQUEST_COMPLETE 0 #define FCGI_CANT_MPX_CONN 1 #define FCGI_OVERLOADED 2 #define FCGI_UNKNOWN_ROLE 3 /* * Variable names for FCGI_GET_VALUES / FCGI_GET_VALUES_RESULT records */ #define FCGI_MAX_CONNS "FCGI_MAX_CONNS" #define FCGI_MAX_REQS "FCGI_MAX_REQS" #define FCGI_MPXS_CONNS "FCGI_MPXS_CONNS" typedef struct { unsigned char type; unsigned char reserved[7]; } FCGI_UnknownTypeBody; typedef struct { FCGI_Header header; FCGI_UnknownTypeBody body; } FCGI_UnknownTypeRecord; #endif /* _FASTCGI_H */ FCGI-0.74/configure.readme0000644000175000017500000001732711417356077013773 0ustar raflrafl$Id: configure.readme,v 1.1 1999/02/13 05:26:47 roberts Exp $ Basic Installation ================== These are generic installation instructions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, a file `config.cache' that saves the results of its tests to speed up reconfiguring, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.in' is used to create `configure' by a program called `autoconf'. You only need `configure.in' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. If you're using `csh' on an old version of System V, you might need to type `sh ./configure' instead to prevent `csh' from trying to execute `configure' itself. Running `configure' takes awhile. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package. 4. Type `make install' to install the programs and any data files and documentation. 5. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. You can give `configure' initial values for variables by setting them in the environment. Using a Bourne-compatible shell, you can do that on the command line like this: CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure Or on systems that have the `env' program, you can do it like this: env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you must use a version of `make' that supports the `VPATH' variable, such as GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. If you have to use a `make' that does not supports the `VPATH' variable, you have to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. Installation Names ================== By default, `make install' will install the package's files in `/usr/local/bin', `/usr/local/man', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PATH'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you give `configure' the option `--exec-prefix=PATH', the package will use PATH as the prefix for installing programs and libraries. Documentation and other data files will still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=PATH' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Optional Features ================= Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Specifying the System Type ========================== There may be some features `configure' can not figure out automatically, but needs to determine by the type of host the package will run on. Usually `configure' can figure that out, but if it prints a message saying it can not guess the host type, give it the `--host=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name with three fields: CPU-COMPANY-SYSTEM See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the host type. If you are building compiler tools for cross-compiling, you can also use the `--target=TYPE' option to select the type of system they will produce code for and the `--build=TYPE' option to select the type of system on which you are compiling the package. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Operation Controls ================== `configure' recognizes the following options to control how it operates. `--cache-file=FILE' Use and save the results of the tests in FILE instead of `./config.cache'. Set FILE to `/dev/null' to disable caching, for debugging `configure'. `--help' Print a summary of the options to `configure', and exit. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `--version' Print the version of Autoconf used to generate the `configure' script, and exit. `configure' also accepts some other, not widely useful, options. FCGI-0.74/os_win32.c0000711000175000017500000013667111637307650012436 0ustar raflrafl/* * os_win32.c -- * * * Copyright (c) 1995 Open Market, Inc. * All rights reserved. * * This file contains proprietary and confidential information and * remains the unpublished property of Open Market, Inc. Use, * disclosure, or reproduction is prohibited except as permitted by * express written license agreement with Open Market, Inc. * * Bill Snapper * snapper@openmarket.com * * (Special thanks to Karen and Bill. They made my job much easier and * significantly more enjoyable.) */ #ifndef lint static const char rcsid[] = "$Id: os_win32.c,v 1.35 2004/01/31 17:47:07 robs Exp $"; #endif /* not lint */ #define WIN32_LEAN_AND_MEAN #include #include #include #include #include #include #include #include #define DLLAPI __declspec(dllexport) #include "fcgimisc.h" #include "fcgios.h" #define WIN32_OPEN_MAX 128 /* XXX: Small hack */ /* * millisecs to wait for a client connection before checking the * shutdown flag (then go back to waiting for a connection, etc). */ #define ACCEPT_TIMEOUT 1000 #define MUTEX_VARNAME "_FCGI_MUTEX_" #define SHUTDOWN_EVENT_NAME "_FCGI_SHUTDOWN_EVENT_" #define LOCALHOST "localhost" static HANDLE hIoCompPort = INVALID_HANDLE_VALUE; static HANDLE hStdinCompPort = INVALID_HANDLE_VALUE; static HANDLE hStdinThread = INVALID_HANDLE_VALUE; static HANDLE stdioHandles[3] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}; // This is a nail for listening to more than one port.. static HANDLE acceptMutex = INVALID_HANDLE_VALUE; static BOOLEAN shutdownPending = FALSE; static BOOLEAN shutdownNow = FALSE; /* * An enumeration of the file types * supported by the FD_TABLE structure. * * XXX: Not all currently supported. This allows for future * functionality. */ typedef enum { FD_UNUSED, FD_FILE_SYNC, FD_FILE_ASYNC, FD_SOCKET_SYNC, FD_SOCKET_ASYNC, FD_PIPE_SYNC, FD_PIPE_ASYNC } FILE_TYPE; typedef union { HANDLE fileHandle; SOCKET sock; unsigned int value; } DESCRIPTOR; /* * Structure used to map file handle and socket handle * values into values that can be used to create unix-like * select bitmaps, read/write for both sockets/files. */ struct FD_TABLE { DESCRIPTOR fid; FILE_TYPE type; char *path; DWORD Errno; unsigned long instance; int status; int offset; /* only valid for async file writes */ LPDWORD offsetHighPtr; /* pointers to offset high and low words */ LPDWORD offsetLowPtr; /* only valid for async file writes (logs) */ HANDLE hMapMutex; /* mutex handle for multi-proc offset update */ LPVOID ovList; /* List of associated OVERLAPPED_REQUESTs */ }; /* * XXX Note there is no dyanmic sizing of this table, so if the * number of open file descriptors exceeds WIN32_OPEN_MAX the * app will blow up. */ static struct FD_TABLE fdTable[WIN32_OPEN_MAX]; static CRITICAL_SECTION fdTableCritical; struct OVERLAPPED_REQUEST { OVERLAPPED overlapped; unsigned long instance; /* file instance (won't match after a close) */ OS_AsyncProc procPtr; /* callback routine */ ClientData clientData; /* callback argument */ ClientData clientData1; /* additional clientData */ }; typedef struct OVERLAPPED_REQUEST *POVERLAPPED_REQUEST; static const char *bindPathPrefix = "\\\\.\\pipe\\FastCGI\\"; static FILE_TYPE listenType = FD_UNUSED; // XXX This should be a DESCRIPTOR static HANDLE hListen = INVALID_HANDLE_VALUE; static BOOLEAN libInitialized = FALSE; /* *-------------------------------------------------------------- * * Win32NewDescriptor -- * * Set up for I/O descriptor masquerading. * * Results: * Returns "fake id" which masquerades as a UNIX-style "small * non-negative integer" file/socket descriptor. * Win32_* routine below will "do the right thing" based on the * descriptor's actual type. -1 indicates failure. * * Side effects: * Entry in fdTable is reserved to represent the socket/file. * *-------------------------------------------------------------- */ static int Win32NewDescriptor(FILE_TYPE type, int fd, int desiredFd) { int index = -1; EnterCriticalSection(&fdTableCritical); /* * If desiredFd is set, try to get this entry (this is used for * mapping stdio handles). Otherwise try to get the fd entry. * If this is not available, find a the first empty slot. . */ if (desiredFd >= 0 && desiredFd < WIN32_OPEN_MAX) { if (fdTable[desiredFd].type == FD_UNUSED) { index = desiredFd; } } else if (fd > 0) { if (fd < WIN32_OPEN_MAX && fdTable[fd].type == FD_UNUSED) { index = fd; } else { int i; for (i = 1; i < WIN32_OPEN_MAX; ++i) { if (fdTable[i].type == FD_UNUSED) { index = i; break; } } } } if (index != -1) { fdTable[index].fid.value = fd; fdTable[index].type = type; fdTable[index].path = NULL; fdTable[index].Errno = NO_ERROR; fdTable[index].status = 0; fdTable[index].offset = -1; fdTable[index].offsetHighPtr = fdTable[index].offsetLowPtr = NULL; fdTable[index].hMapMutex = NULL; fdTable[index].ovList = NULL; } LeaveCriticalSection(&fdTableCritical); return index; } /* *-------------------------------------------------------------- * * StdinThread-- * * This thread performs I/O on stadard input. It is needed * because you can't guarantee that all applications will * create standard input with sufficient access to perform * asynchronous I/O. Since we don't want to block the app * reading from stdin we make it look like it's using I/O * completion ports to perform async I/O. * * Results: * Data is read from stdin and posted to the io completion * port. * * Side effects: * None. * *-------------------------------------------------------------- */ static void StdinThread(void * startup) { int doIo = TRUE; unsigned long fd; unsigned long bytesRead; POVERLAPPED_REQUEST pOv; // Touch the arg to prevent warning startup = NULL; while(doIo) { /* * Block until a request to read from stdin comes in or a * request to terminate the thread arrives (fd = -1). */ if (!GetQueuedCompletionStatus(hStdinCompPort, &bytesRead, &fd, (LPOVERLAPPED *)&pOv, (DWORD)-1) && !pOv) { doIo = 0; break; } ASSERT((fd == STDIN_FILENO) || (fd == -1)); if(fd == -1) { doIo = 0; break; } ASSERT(pOv->clientData1 != NULL); if(ReadFile(stdioHandles[STDIN_FILENO], pOv->clientData1, bytesRead, &bytesRead, NULL)) { PostQueuedCompletionStatus(hIoCompPort, bytesRead, STDIN_FILENO, (LPOVERLAPPED)pOv); } else { doIo = 0; break; } } ExitThread(0); } void OS_ShutdownPending(void) { shutdownPending = TRUE; } static void ShutdownRequestThread(void * arg) { HANDLE shutdownEvent = (HANDLE) arg; WaitForSingleObject(shutdownEvent, INFINITE); shutdownPending = TRUE; // emulate the unix behaviour raise(SIGTERM); if (listenType == FD_PIPE_SYNC) { // Its a hassle to get ConnectNamedPipe to return early, // so just wack the whole process - yes, this will toast // any requests in progress, but at least its a clean // shutdown (its better than TerminateProcess()) exit(0); } // FD_SOCKET_SYNC: When in Accept(), select() is used to poll // the shutdownPending flag - yeah this isn't pretty either // but its only one process doing it if an Accept mutex is used. // This at least buys no toasted requests. } /* *-------------------------------------------------------------- * * OS_LibInit -- * * Set up the OS library for use. * * Results: * Returns 0 if success, -1 if not. * * Side effects: * Sockets initialized, pseudo file descriptors setup, etc. * *-------------------------------------------------------------- */ int OS_LibInit(int stdioFds[3]) { WORD wVersion; WSADATA wsaData; int err; int fakeFd; char *cLenPtr = NULL; char *val = NULL; if(libInitialized) return 0; InitializeCriticalSection(&fdTableCritical); /* * Initialize windows sockets library. */ wVersion = MAKEWORD(2,0); err = WSAStartup( wVersion, &wsaData ); if (err) { fprintf(stderr, "Error starting Windows Sockets. Error: %d", WSAGetLastError()); exit(111); } /* * Create the I/O completion port to be used for our I/O queue. */ if (hIoCompPort == INVALID_HANDLE_VALUE) { hIoCompPort = CreateIoCompletionPort (INVALID_HANDLE_VALUE, NULL, 0, 1); if(hIoCompPort == INVALID_HANDLE_VALUE) { printf("

OS_LibInit Failed CreateIoCompletionPort! ERROR: %d

\r\n\r\n", GetLastError()); return -1; } } /* * If a shutdown event is in the env, save it (I don't see any to * remove it from the environment out from under the application). * Spawn a thread to wait on the shutdown request. */ val = getenv(SHUTDOWN_EVENT_NAME); if (val != NULL) { HANDLE shutdownEvent = (HANDLE) atoi(val); if (_beginthread(ShutdownRequestThread, 0, shutdownEvent) == -1) { return -1; } } if (acceptMutex == INVALID_HANDLE_VALUE) { /* If an accept mutex is in the env, use it */ val = getenv(MUTEX_VARNAME); if (val != NULL) { acceptMutex = (HANDLE) atoi(val); } } /* * Determine if this library is being used to listen for FastCGI * connections. This is communicated by STDIN containing a * valid handle to a listener object. In this case, both the * "stdout" and "stderr" handles will be INVALID (ie. closed) by * the starting process. * * The trick is determining if this is a pipe or a socket... * * XXX: Add the async accept test to determine socket or handle to a * pipe!!! */ if((GetStdHandle(STD_OUTPUT_HANDLE) == INVALID_HANDLE_VALUE) && (GetStdHandle(STD_ERROR_HANDLE) == INVALID_HANDLE_VALUE) && (GetStdHandle(STD_INPUT_HANDLE) != INVALID_HANDLE_VALUE) ) { DWORD pipeMode = PIPE_READMODE_BYTE | PIPE_WAIT; HANDLE oldStdIn = GetStdHandle(STD_INPUT_HANDLE); // Move the handle to a "low" number if (! DuplicateHandle(GetCurrentProcess(), oldStdIn, GetCurrentProcess(), &hListen, 0, TRUE, DUPLICATE_SAME_ACCESS)) { return -1; } if (! SetStdHandle(STD_INPUT_HANDLE, hListen)) { return -1; } CloseHandle(oldStdIn); /* * Set the pipe handle state so that it operates in wait mode. * * NOTE: The listenFd is not mapped to a pseudo file descriptor * as all work done on it is contained to the OS library. * * XXX: Initial assumption is that SetNamedPipeHandleState will * fail if this is an IP socket... */ if (SetNamedPipeHandleState(hListen, &pipeMode, NULL, NULL)) { listenType = FD_PIPE_SYNC; } else { listenType = FD_SOCKET_SYNC; } } /* * If there are no stdioFds passed in, we're done. */ if(stdioFds == NULL) { libInitialized = 1; return 0; } /* * Setup standard input asynchronous I/O. There is actually a separate * thread spawned for this purpose. The reason for this is that some * web servers use anonymous pipes for the connection between itself * and a CGI application. Anonymous pipes can't perform asynchronous * I/O or use I/O completion ports. Therefore in order to present a * consistent I/O dispatch model to an application we emulate I/O * completion port behavior by having the standard input thread posting * messages to the hIoCompPort which look like a complete overlapped * I/O structure. This keeps the event dispatching simple from the * application perspective. */ stdioHandles[STDIN_FILENO] = GetStdHandle(STD_INPUT_HANDLE); if(!SetHandleInformation(stdioHandles[STDIN_FILENO], HANDLE_FLAG_INHERIT, 0)) { /* * XXX: Causes error when run from command line. Check KB err = GetLastError(); DebugBreak(); exit(99); */ } if ((fakeFd = Win32NewDescriptor(FD_PIPE_SYNC, (int)stdioHandles[STDIN_FILENO], STDIN_FILENO)) == -1) { return -1; } else { /* * Set stdin equal to our pseudo FD and create the I/O completion * port to be used for async I/O. */ stdioFds[STDIN_FILENO] = fakeFd; } /* * Create the I/O completion port to be used for communicating with * the thread doing I/O on standard in. This port will carry read * and possibly thread termination requests to the StdinThread. */ if (hStdinCompPort == INVALID_HANDLE_VALUE) { hStdinCompPort = CreateIoCompletionPort (INVALID_HANDLE_VALUE, NULL, 0, 1); if(hStdinCompPort == INVALID_HANDLE_VALUE) { printf("

OS_LibInit Failed CreateIoCompletionPort: STDIN! ERROR: %d

\r\n\r\n", GetLastError()); return -1; } } /* * Create the thread that will read stdin if the CONTENT_LENGTH * is non-zero. */ if((cLenPtr = getenv("CONTENT_LENGTH")) != NULL && atoi(cLenPtr) > 0) { hStdinThread = (HANDLE) _beginthread(StdinThread, 0, NULL); if (hStdinThread == (HANDLE) -1) { printf("

OS_LibInit Failed to create STDIN thread! ERROR: %d

\r\n\r\n", GetLastError()); return -1; } } /* * STDOUT will be used synchronously. * * XXX: May want to convert this so that it could be used for OVERLAPPED * I/O later. If so, model it after the Stdin I/O as stdout is * also incapable of async I/O on some servers. */ stdioHandles[STDOUT_FILENO] = GetStdHandle(STD_OUTPUT_HANDLE); if(!SetHandleInformation(stdioHandles[STDOUT_FILENO], HANDLE_FLAG_INHERIT, FALSE)) { DebugBreak(); exit(99); } if ((fakeFd = Win32NewDescriptor(FD_PIPE_SYNC, (int)stdioHandles[STDOUT_FILENO], STDOUT_FILENO)) == -1) { return -1; } else { /* * Set stdout equal to our pseudo FD */ stdioFds[STDOUT_FILENO] = fakeFd; } stdioHandles[STDERR_FILENO] = GetStdHandle(STD_ERROR_HANDLE); if(!SetHandleInformation(stdioHandles[STDERR_FILENO], HANDLE_FLAG_INHERIT, FALSE)) { DebugBreak(); exit(99); } if ((fakeFd = Win32NewDescriptor(FD_PIPE_SYNC, (int)stdioHandles[STDERR_FILENO], STDERR_FILENO)) == -1) { return -1; } else { /* * Set stderr equal to our pseudo FD */ stdioFds[STDERR_FILENO] = fakeFd; } return 0; } /* *-------------------------------------------------------------- * * OS_LibShutdown -- * * Shutdown the OS library. * * Results: * None. * * Side effects: * Memory freed, handles closed. * *-------------------------------------------------------------- */ void OS_LibShutdown() { if (hIoCompPort != INVALID_HANDLE_VALUE) { CloseHandle(hIoCompPort); hIoCompPort = INVALID_HANDLE_VALUE; } if (hStdinCompPort != INVALID_HANDLE_VALUE) { CloseHandle(hStdinCompPort); hStdinCompPort = INVALID_HANDLE_VALUE; } if (acceptMutex != INVALID_HANDLE_VALUE) { ReleaseMutex(acceptMutex); } DisconnectNamedPipe(hListen); CancelIo(hListen); WSACleanup(); } /* *-------------------------------------------------------------- * * Win32FreeDescriptor -- * * Free I/O descriptor entry in fdTable. * * Results: * Frees I/O descriptor entry in fdTable. * * Side effects: * None. * *-------------------------------------------------------------- */ static void Win32FreeDescriptor(int fd) { /* Catch it if fd is a bogus value */ ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX)); EnterCriticalSection(&fdTableCritical); if (fdTable[fd].type != FD_UNUSED) { switch (fdTable[fd].type) { case FD_FILE_SYNC: case FD_FILE_ASYNC: /* Free file path string */ ASSERT(fdTable[fd].path != NULL); free(fdTable[fd].path); fdTable[fd].path = NULL; break; default: break; } ASSERT(fdTable[fd].path == NULL); fdTable[fd].type = FD_UNUSED; fdTable[fd].path = NULL; fdTable[fd].Errno = NO_ERROR; fdTable[fd].offsetHighPtr = fdTable[fd].offsetLowPtr = NULL; if (fdTable[fd].hMapMutex != NULL) { CloseHandle(fdTable[fd].hMapMutex); fdTable[fd].hMapMutex = NULL; } } LeaveCriticalSection(&fdTableCritical); return; } static short getPort(const char * bindPath) { short port = 0; char * p = strchr(bindPath, ':'); if (p && *++p) { char buf[6]; strncpy(buf, p, 6); buf[5] = '\0'; port = (short) atoi(buf); } return port; } /* * OS_CreateLocalIpcFd -- * * This procedure is responsible for creating the listener pipe * on Windows NT for local process communication. It will create a * named pipe and return a file descriptor to it to the caller. * * Results: * Listener pipe created. This call returns either a valid * pseudo file descriptor or -1 on error. * * Side effects: * Listener pipe and IPC address are stored in the FCGI info * structure. * 'errno' will set on errors (-1 is returned). * *---------------------------------------------------------------------- */ int OS_CreateLocalIpcFd(const char *bindPath, int backlog) { int pseudoFd = -1; short port = getPort(bindPath); if (acceptMutex == INVALID_HANDLE_VALUE) { acceptMutex = CreateMutex(NULL, FALSE, NULL); if (acceptMutex == NULL) return -2; if (! SetHandleInformation(acceptMutex, HANDLE_FLAG_INHERIT, TRUE)) return -3; } // There's nothing to be gained (at the moment) by a shutdown Event if (port && *bindPath != ':' && strncmp(bindPath, LOCALHOST, strlen(LOCALHOST))) { fprintf(stderr, "To start a service on a TCP port can not " "specify a host name.\n" "You should either use \"localhost:\" or " " just use \":.\"\n"); exit(1); } listenType = (port) ? FD_SOCKET_SYNC : FD_PIPE_ASYNC; if (port) { SOCKET listenSock; struct sockaddr_in sockAddr; int sockLen = sizeof(sockAddr); memset(&sockAddr, 0, sizeof(sockAddr)); sockAddr.sin_family = AF_INET; sockAddr.sin_addr.s_addr = htonl(INADDR_ANY); sockAddr.sin_port = htons(port); listenSock = socket(AF_INET, SOCK_STREAM, 0); if (listenSock == INVALID_SOCKET) { return -4; } if (bind(listenSock, (struct sockaddr *) &sockAddr, sockLen) ) { return -12; } if (listen(listenSock, backlog)) { return -5; } pseudoFd = Win32NewDescriptor(listenType, listenSock, -1); if (pseudoFd == -1) { closesocket(listenSock); return -6; } hListen = (HANDLE) listenSock; } else { HANDLE hListenPipe = INVALID_HANDLE_VALUE; char *pipePath = malloc(strlen(bindPathPrefix) + strlen(bindPath) + 1); if (! pipePath) { return -7; } strcpy(pipePath, bindPathPrefix); strcat(pipePath, bindPath); hListenPipe = CreateNamedPipe(pipePath, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT | PIPE_READMODE_BYTE, PIPE_UNLIMITED_INSTANCES, 4096, 4096, 0, NULL); free(pipePath); if (hListenPipe == INVALID_HANDLE_VALUE) { return -8; } if (! SetHandleInformation(hListenPipe, HANDLE_FLAG_INHERIT, TRUE)) { return -9; } pseudoFd = Win32NewDescriptor(listenType, (int) hListenPipe, -1); if (pseudoFd == -1) { CloseHandle(hListenPipe); return -10; } hListen = (HANDLE) hListenPipe; } return pseudoFd; } /* *---------------------------------------------------------------------- * * OS_FcgiConnect -- * * Create the pipe pathname connect to the remote application if * possible. * * Results: * -1 if fail or a valid handle if connection succeeds. * * Side effects: * Remote connection established. * *---------------------------------------------------------------------- */ int OS_FcgiConnect(char *bindPath) { short port = getPort(bindPath); int pseudoFd = -1; if (port) { struct hostent *hp; char *host = NULL; struct sockaddr_in sockAddr; int sockLen = sizeof(sockAddr); SOCKET sock; if (*bindPath != ':') { char * p = strchr(bindPath, ':'); int len = p - bindPath + 1; host = malloc(len); strncpy(host, bindPath, len); host[len] = '\0'; } hp = gethostbyname(host ? host : LOCALHOST); if (host) { free(host); } if (hp == NULL) { fprintf(stderr, "Unknown host: %s\n", bindPath); return -1; } memset(&sockAddr, 0, sizeof(sockAddr)); sockAddr.sin_family = AF_INET; memcpy(&sockAddr.sin_addr, hp->h_addr, hp->h_length); sockAddr.sin_port = htons(port); sock = socket(AF_INET, SOCK_STREAM, 0); if (sock == INVALID_SOCKET) { return -1; } if (! connect(sock, (struct sockaddr *) &sockAddr, sockLen)) { closesocket(sock); return -1; } pseudoFd = Win32NewDescriptor(FD_SOCKET_SYNC, sock, -1); if (pseudoFd == -1) { closesocket(sock); return -1; } } else { char *pipePath = malloc(strlen(bindPathPrefix) + strlen(bindPath) + 1); HANDLE hPipe; if (! pipePath) { return -1; } strcpy(pipePath, bindPathPrefix); strcat(pipePath, bindPath); hPipe = CreateFile(pipePath, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); free(pipePath); if( hPipe == INVALID_HANDLE_VALUE) { return -1; } pseudoFd = Win32NewDescriptor(FD_PIPE_ASYNC, (int) hPipe, -1); if (pseudoFd == -1) { CloseHandle(hPipe); return -1; } /* * Set stdin equal to our pseudo FD and create the I/O completion * port to be used for async I/O. */ if (! CreateIoCompletionPort(hPipe, hIoCompPort, pseudoFd, 1)) { Win32FreeDescriptor(pseudoFd); CloseHandle(hPipe); return -1; } } return pseudoFd; } /* *-------------------------------------------------------------- * * OS_Read -- * * Pass through to the appropriate NT read function. * * Results: * Returns number of byes read. Mimics unix read:. * n bytes read, 0 or -1 failure: errno contains actual error * * Side effects: * None. * *-------------------------------------------------------------- */ int OS_Read(int fd, char * buf, size_t len) { DWORD bytesRead; int ret = -1; ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX)); if (shutdownNow) return -1; switch (fdTable[fd].type) { case FD_FILE_SYNC: case FD_FILE_ASYNC: case FD_PIPE_SYNC: case FD_PIPE_ASYNC: if (ReadFile(fdTable[fd].fid.fileHandle, buf, len, &bytesRead, NULL)) { ret = bytesRead; } else { fdTable[fd].Errno = GetLastError(); } break; case FD_SOCKET_SYNC: case FD_SOCKET_ASYNC: ret = recv(fdTable[fd].fid.sock, buf, len, 0); if (ret == SOCKET_ERROR) { fdTable[fd].Errno = WSAGetLastError(); ret = -1; } break; default: ASSERT(0); } return ret; } /* *-------------------------------------------------------------- * * OS_Write -- * * Perform a synchronous OS write. * * Results: * Returns number of bytes written. Mimics unix write: * n bytes written, 0 or -1 failure (??? couldn't find man page). * * Side effects: * none. * *-------------------------------------------------------------- */ int OS_Write(int fd, char * buf, size_t len) { DWORD bytesWritten; int ret = -1; ASSERT(fd >= 0 && fd < WIN32_OPEN_MAX); if (shutdownNow) return -1; switch (fdTable[fd].type) { case FD_FILE_SYNC: case FD_FILE_ASYNC: case FD_PIPE_SYNC: case FD_PIPE_ASYNC: if (WriteFile(fdTable[fd].fid.fileHandle, buf, len, &bytesWritten, NULL)) { ret = bytesWritten; } else { fdTable[fd].Errno = GetLastError(); } break; case FD_SOCKET_SYNC: case FD_SOCKET_ASYNC: ret = send(fdTable[fd].fid.sock, buf, len, 0); if (ret == SOCKET_ERROR) { fdTable[fd].Errno = WSAGetLastError(); ret = -1; } break; default: ASSERT(0); } return ret; } /* *---------------------------------------------------------------------- * * OS_SpawnChild -- * * Spawns a new server listener process, and stores the information * relating to the child in the supplied record. A wait handler is * registered on the child's completion. This involves creating * a process on NT and preparing a command line with the required * state (currently a -childproc flag and the server socket to use * for accepting connections). * * Results: * 0 if success, -1 if error. * * Side effects: * Child process spawned. * *---------------------------------------------------------------------- */ int OS_SpawnChild(char *execPath, int listenFd) { STARTUPINFO StartupInfo; PROCESS_INFORMATION pInfo; BOOL success; memset((void *)&StartupInfo, 0, sizeof(STARTUPINFO)); StartupInfo.cb = sizeof (STARTUPINFO); StartupInfo.lpReserved = NULL; StartupInfo.lpReserved2 = NULL; StartupInfo.cbReserved2 = 0; StartupInfo.lpDesktop = NULL; /* * FastCGI on NT will set the listener pipe HANDLE in the stdin of * the new process. The fact that there is a stdin and NULL handles * for stdout and stderr tells the FastCGI process that this is a * FastCGI process and not a CGI process. */ StartupInfo.dwFlags = STARTF_USESTDHANDLES; /* * XXX: Do I have to dup the handle before spawning the process or is * it sufficient to use the handle as it's reference counted * by NT anyway? */ StartupInfo.hStdInput = fdTable[listenFd].fid.fileHandle; StartupInfo.hStdOutput = INVALID_HANDLE_VALUE; StartupInfo.hStdError = INVALID_HANDLE_VALUE; /* * Make the listener socket inheritable. */ success = SetHandleInformation(StartupInfo.hStdInput, HANDLE_FLAG_INHERIT, TRUE); if(!success) { exit(99); } /* * XXX: Might want to apply some specific security attributes to the * processes. */ success = CreateProcess(execPath, /* LPCSTR address of module name */ NULL, /* LPCSTR address of command line */ NULL, /* Process security attributes */ NULL, /* Thread security attributes */ TRUE, /* Inheritable Handes inherited. */ 0, /* DWORD creation flags */ NULL, /* Use parent environment block */ NULL, /* Address of current directory name */ &StartupInfo, /* Address of STARTUPINFO */ &pInfo); /* Address of PROCESS_INFORMATION */ if(success) { return 0; } else { return -1; } } /* *-------------------------------------------------------------- * * OS_AsyncReadStdin -- * * This initiates an asynchronous read on the standard * input handle. This handle is not guaranteed to be * capable of performing asynchronous I/O so we send a * message to the StdinThread to do the synchronous read. * * Results: * -1 if error, 0 otherwise. * * Side effects: * Asynchronous message is queued to the StdinThread and an * overlapped structure is allocated/initialized. * *-------------------------------------------------------------- */ int OS_AsyncReadStdin(void *buf, int len, OS_AsyncProc procPtr, ClientData clientData) { POVERLAPPED_REQUEST pOv; ASSERT(fdTable[STDIN_FILENO].type != FD_UNUSED); pOv = (POVERLAPPED_REQUEST)malloc(sizeof(struct OVERLAPPED_REQUEST)); ASSERT(pOv); memset((void *)pOv, 0, sizeof(struct OVERLAPPED_REQUEST)); pOv->clientData1 = (ClientData)buf; pOv->instance = fdTable[STDIN_FILENO].instance; pOv->procPtr = procPtr; pOv->clientData = clientData; PostQueuedCompletionStatus(hStdinCompPort, len, STDIN_FILENO, (LPOVERLAPPED)pOv); return 0; } /* *-------------------------------------------------------------- * * OS_AsyncRead -- * * This initiates an asynchronous read on the file * handle which may be a socket or named pipe. * * We also must save the ProcPtr and ClientData, so later * when the io completes, we know who to call. * * We don't look at any results here (the ReadFile may * return data if it is cached) but do all completion * processing in OS_Select when we get the io completion * port done notifications. Then we call the callback. * * Results: * -1 if error, 0 otherwise. * * Side effects: * Asynchronous I/O operation is queued for completion. * *-------------------------------------------------------------- */ int OS_AsyncRead(int fd, int offset, void *buf, int len, OS_AsyncProc procPtr, ClientData clientData) { DWORD bytesRead; POVERLAPPED_REQUEST pOv; /* * Catch any bogus fd values */ ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX)); /* * Confirm that this is an async fd */ ASSERT(fdTable[fd].type != FD_UNUSED); ASSERT(fdTable[fd].type != FD_FILE_SYNC); ASSERT(fdTable[fd].type != FD_PIPE_SYNC); ASSERT(fdTable[fd].type != FD_SOCKET_SYNC); pOv = (POVERLAPPED_REQUEST)malloc(sizeof(struct OVERLAPPED_REQUEST)); ASSERT(pOv); memset((void *)pOv, 0, sizeof(struct OVERLAPPED_REQUEST)); /* * Only file offsets should be non-zero, but make sure. */ if (fdTable[fd].type == FD_FILE_ASYNC) if (fdTable[fd].offset >= 0) pOv->overlapped.Offset = fdTable[fd].offset; else pOv->overlapped.Offset = offset; pOv->instance = fdTable[fd].instance; pOv->procPtr = procPtr; pOv->clientData = clientData; bytesRead = fd; /* * ReadFile returns: TRUE success, FALSE failure */ if (!ReadFile(fdTable[fd].fid.fileHandle, buf, len, &bytesRead, (LPOVERLAPPED)pOv)) { fdTable[fd].Errno = GetLastError(); if(fdTable[fd].Errno == ERROR_NO_DATA || fdTable[fd].Errno == ERROR_PIPE_NOT_CONNECTED) { PostQueuedCompletionStatus(hIoCompPort, 0, fd, (LPOVERLAPPED)pOv); return 0; } if(fdTable[fd].Errno != ERROR_IO_PENDING) { PostQueuedCompletionStatus(hIoCompPort, 0, fd, (LPOVERLAPPED)pOv); return -1; } fdTable[fd].Errno = 0; } return 0; } /* *-------------------------------------------------------------- * * OS_AsyncWrite -- * * This initiates an asynchronous write on the "fake" file * descriptor (which may be a file, socket, or named pipe). * We also must save the ProcPtr and ClientData, so later * when the io completes, we know who to call. * * We don't look at any results here (the WriteFile generally * completes immediately) but do all completion processing * in OS_DoIo when we get the io completion port done * notifications. Then we call the callback. * * Results: * -1 if error, 0 otherwise. * * Side effects: * Asynchronous I/O operation is queued for completion. * *-------------------------------------------------------------- */ int OS_AsyncWrite(int fd, int offset, void *buf, int len, OS_AsyncProc procPtr, ClientData clientData) { DWORD bytesWritten; POVERLAPPED_REQUEST pOv; /* * Catch any bogus fd values */ ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX)); /* * Confirm that this is an async fd */ ASSERT(fdTable[fd].type != FD_UNUSED); ASSERT(fdTable[fd].type != FD_FILE_SYNC); ASSERT(fdTable[fd].type != FD_PIPE_SYNC); ASSERT(fdTable[fd].type != FD_SOCKET_SYNC); pOv = (POVERLAPPED_REQUEST)malloc(sizeof(struct OVERLAPPED_REQUEST)); ASSERT(pOv); memset((void *)pOv, 0, sizeof(struct OVERLAPPED_REQUEST)); /* * Only file offsets should be non-zero, but make sure. */ if (fdTable[fd].type == FD_FILE_ASYNC) /* * Only file opened via OS_AsyncWrite with * O_APPEND will have an offset != -1. */ if (fdTable[fd].offset >= 0) /* * If the descriptor has a memory mapped file * handle, take the offsets from there. */ if (fdTable[fd].hMapMutex != NULL) { /* * Wait infinitely; this *should* not cause problems. */ WaitForSingleObject(fdTable[fd].hMapMutex, INFINITE); /* * Retrieve the shared offset values. */ pOv->overlapped.OffsetHigh = *(fdTable[fd].offsetHighPtr); pOv->overlapped.Offset = *(fdTable[fd].offsetLowPtr); /* * Update the shared offset values for the next write */ *(fdTable[fd].offsetHighPtr) += 0; /* XXX How do I handle overflow */ *(fdTable[fd].offsetLowPtr) += len; ReleaseMutex(fdTable[fd].hMapMutex); } else pOv->overlapped.Offset = fdTable[fd].offset; else pOv->overlapped.Offset = offset; pOv->instance = fdTable[fd].instance; pOv->procPtr = procPtr; pOv->clientData = clientData; bytesWritten = fd; /* * WriteFile returns: TRUE success, FALSE failure */ if (!WriteFile(fdTable[fd].fid.fileHandle, buf, len, &bytesWritten, (LPOVERLAPPED)pOv)) { fdTable[fd].Errno = GetLastError(); if(fdTable[fd].Errno != ERROR_IO_PENDING) { PostQueuedCompletionStatus(hIoCompPort, 0, fd, (LPOVERLAPPED)pOv); return -1; } fdTable[fd].Errno = 0; } if (fdTable[fd].offset >= 0) fdTable[fd].offset += len; return 0; } /* *-------------------------------------------------------------- * * OS_Close -- * * Closes the descriptor with routine appropriate for * descriptor's type. * * Results: * Socket or file is closed. Return values mimic Unix close: * 0 success, -1 failure * * Side effects: * Entry in fdTable is marked as free. * *-------------------------------------------------------------- */ int OS_Close(int fd, int shutdown_ok) { int ret = 0; /* * Catch it if fd is a bogus value */ ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX)); ASSERT(fdTable[fd].type != FD_UNUSED); switch (fdTable[fd].type) { case FD_PIPE_SYNC: case FD_PIPE_ASYNC: case FD_FILE_SYNC: case FD_FILE_ASYNC: break; case FD_SOCKET_SYNC: case FD_SOCKET_ASYNC: /* * shutdown() the send side and then read() from client until EOF * or a timeout expires. This is done to minimize the potential * that a TCP RST will be sent by our TCP stack in response to * receipt of additional data from the client. The RST would * cause the client to discard potentially useful response data. */ if (shutdown_ok) { if (shutdown(fdTable[fd].fid.sock, SD_SEND) == 0) { struct timeval tv; fd_set rfds; int sock = fdTable[fd].fid.sock; int rv; char trash[1024]; FD_ZERO(&rfds); do { #pragma warning( disable : 4127 ) FD_SET((unsigned) sock, &rfds); #pragma warning( default : 4127 ) tv.tv_sec = 2; tv.tv_usec = 0; rv = select(sock + 1, &rfds, NULL, NULL, &tv); } while (rv > 0 && recv(sock, trash, sizeof(trash), 0) > 0); } } closesocket(fdTable[fd].fid.sock); break; default: ret = -1; /* fake failure */ } Win32FreeDescriptor(fd); return ret; } /* *-------------------------------------------------------------- * * OS_CloseRead -- * * Cancel outstanding asynchronous reads and prevent subsequent * reads from completing. * * Results: * Socket or file is shutdown. Return values mimic Unix shutdown: * 0 success, -1 failure * *-------------------------------------------------------------- */ int OS_CloseRead(int fd) { int ret = 0; /* * Catch it if fd is a bogus value */ ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX)); ASSERT(fdTable[fd].type == FD_SOCKET_ASYNC || fdTable[fd].type == FD_SOCKET_SYNC); if (shutdown(fdTable[fd].fid.sock,0) == SOCKET_ERROR) ret = -1; return ret; } /* *-------------------------------------------------------------- * * OS_DoIo -- * * This function was formerly OS_Select. It's purpose is * to pull I/O completion events off the queue and dispatch * them to the appropriate place. * * Results: * Returns 0. * * Side effects: * Handlers are called. * *-------------------------------------------------------------- */ int OS_DoIo(struct timeval *tmo) { unsigned long fd; unsigned long bytes; POVERLAPPED_REQUEST pOv; struct timeb tb; int ms; int ms_last; int err; /* XXX * We can loop in here, but not too long, as wait handlers * must run. * For cgi stdin, apparently select returns when io completion * ports don't, so don't wait the full timeout. */ if(tmo) ms = (tmo->tv_sec*1000 + tmo->tv_usec/1000) / 2; else ms = 1000; ftime(&tb); ms_last = tb.time*1000 + tb.millitm; while (ms >= 0) { if(tmo && (ms = tmo->tv_sec*1000 + tmo->tv_usec/1000)> 100) ms = 100; if (!GetQueuedCompletionStatus(hIoCompPort, &bytes, &fd, (LPOVERLAPPED *)&pOv, ms) && !pOv) { err = WSAGetLastError(); return 0; /* timeout */ } ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX)); /* call callback if descriptor still valid */ ASSERT(pOv); if(pOv->instance == fdTable[fd].instance) (*pOv->procPtr)(pOv->clientData, bytes); free(pOv); ftime(&tb); ms -= (tb.time*1000 + tb.millitm - ms_last); ms_last = tb.time*1000 + tb.millitm; } return 0; } static int isAddrOK(struct sockaddr_in * inet_sockaddr, const char * okAddrs) { static const char *token = " ,;:\t"; char *ipaddr; char *p; if (okAddrs == NULL) return TRUE; ipaddr = inet_ntoa(inet_sockaddr->sin_addr); p = strstr(okAddrs, ipaddr); if (p == NULL) return FALSE; if (p == okAddrs) { p += strlen(ipaddr); return (strchr(token, *p) != NULL); } if (strchr(token, *--p) != NULL) { p += strlen(ipaddr) + 1; return (strchr(token, *p) != NULL); } return FALSE; } #ifndef NO_WSAACEPT static int CALLBACK isAddrOKCallback(LPWSABUF lpCallerId, LPWSABUF dc0, LPQOS dc1, LPQOS dc2, LPWSABUF dc3, LPWSABUF dc4, GROUP *dc5, DWORD data) { struct sockaddr_in *sockaddr = (struct sockaddr_in *) lpCallerId->buf; // Touch the args to avoid warnings dc0 = NULL; dc1 = NULL; dc2 = NULL; dc3 = NULL; dc4 = NULL; dc5 = NULL; if ((void *) data == NULL) return CF_ACCEPT; if (sockaddr->sin_family != AF_INET) return CF_ACCEPT; return isAddrOK(sockaddr, (const char *) data) ? CF_ACCEPT : CF_REJECT; } #endif static void printLastError(const char * text) { LPVOID buf; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), 0, (LPTSTR) &buf, 0, NULL ); fprintf(stderr, "%s: %s\n", text, (LPCTSTR) buf); LocalFree(buf); } static int acceptNamedPipe() { int ipcFd = -1; if (! ConnectNamedPipe(hListen, NULL)) { switch (GetLastError()) { case ERROR_PIPE_CONNECTED: // A client connected after CreateNamedPipe but // before ConnectNamedPipe. Its a good connection. break; case ERROR_IO_PENDING: // The NamedPipe was opened with an Overlapped structure // and there is a pending io operation. mod_fastcgi // did this in 2.2.12 (fcgi_pm.c v1.52). case ERROR_PIPE_LISTENING: // The pipe handle is in nonblocking mode. case ERROR_NO_DATA: // The previous client closed its handle (and we failed // to call DisconnectNamedPipe) default: printLastError("unexpected ConnectNamedPipe() error"); } } ipcFd = Win32NewDescriptor(FD_PIPE_SYNC, (int) hListen, -1); if (ipcFd == -1) { DisconnectNamedPipe(hListen); } return ipcFd; } static int acceptSocket(const char *webServerAddrs) { SOCKET hSock; int ipcFd = -1; for (;;) { struct sockaddr sockaddr; int sockaddrLen = sizeof(sockaddr); for (;;) { const struct timeval timeout = {1, 0}; fd_set readfds; FD_ZERO(&readfds); #pragma warning( disable : 4127 ) FD_SET((unsigned int) hListen, &readfds); #pragma warning( default : 4127 ) if (select(0, &readfds, NULL, NULL, &timeout) == 0) { if (shutdownPending) { OS_LibShutdown(); return -1; } } else { break; } } #if NO_WSAACEPT hSock = accept((SOCKET) hListen, &sockaddr, &sockaddrLen); if (hSock == INVALID_SOCKET) { break; } if (isAddrOK((struct sockaddr_in *) &sockaddr, webServerAddrs)) { break; } closesocket(hSock); #else hSock = WSAAccept((unsigned int) hListen, &sockaddr, &sockaddrLen, isAddrOKCallback, (DWORD) webServerAddrs); if (hSock != INVALID_SOCKET) { break; } if (WSAGetLastError() != WSAECONNREFUSED) { break; } #endif } if (hSock == INVALID_SOCKET) { /* Use FormatMessage() */ fprintf(stderr, "accept()/WSAAccept() failed: %d", WSAGetLastError()); return -1; } ipcFd = Win32NewDescriptor(FD_SOCKET_SYNC, hSock, -1); if (ipcFd == -1) { closesocket(hSock); } return ipcFd; } /* *---------------------------------------------------------------------- * * OS_Accept -- * * Accepts a new FastCGI connection. This routine knows whether * we're dealing with TCP based sockets or NT Named Pipes for IPC. * * fail_on_intr is ignored in the Win lib. * * Results: * -1 if the operation fails, otherwise this is a valid IPC fd. * *---------------------------------------------------------------------- */ int OS_Accept(int listen_sock, int fail_on_intr, const char *webServerAddrs) { int ipcFd = -1; // Touch args to prevent warnings listen_sock = 0; fail_on_intr = 0; // @todo Muliple listen sockets and sockets other than 0 are not // supported due to the use of globals. if (shutdownPending) { OS_LibShutdown(); return -1; } // The mutex is to keep other processes (and threads, when supported) // from going into the accept cycle. The accept cycle needs to // periodically break out to check the state of the shutdown flag // and there's no point to having more than one thread do that. if (acceptMutex != INVALID_HANDLE_VALUE) { if (WaitForSingleObject(acceptMutex, INFINITE) == WAIT_FAILED) { printLastError("WaitForSingleObject() failed"); return -1; } } if (shutdownPending) { OS_LibShutdown(); } else if (listenType == FD_PIPE_SYNC) { ipcFd = acceptNamedPipe(); } else if (listenType == FD_SOCKET_SYNC) { ipcFd = acceptSocket(webServerAddrs); } else { fprintf(stderr, "unknown listenType (%d)\n", listenType); } if (acceptMutex != INVALID_HANDLE_VALUE) { ReleaseMutex(acceptMutex); } return ipcFd; } /* *---------------------------------------------------------------------- * * OS_IpcClose * * OS IPC routine to close an IPC connection. * * Results: * * * Side effects: * IPC connection is closed. * *---------------------------------------------------------------------- */ int OS_IpcClose(int ipcFd, int shutdown) { if (ipcFd == -1) return 0; /* * Catch it if fd is a bogus value */ ASSERT((ipcFd >= 0) && (ipcFd < WIN32_OPEN_MAX)); ASSERT(fdTable[ipcFd].type != FD_UNUSED); switch (listenType) { case FD_PIPE_SYNC: /* * Make sure that the client (ie. a Web Server in this case) has * read all data from the pipe before we disconnect. */ if (! FlushFileBuffers(fdTable[ipcFd].fid.fileHandle)) return -1; if (! DisconnectNamedPipe(fdTable[ipcFd].fid.fileHandle)) return -1; /* fall through */ case FD_SOCKET_SYNC: OS_Close(ipcFd, shutdown); break; case FD_UNUSED: default: exit(106); break; } return 0; } /* *---------------------------------------------------------------------- * * OS_IsFcgi -- * * Determines whether this process is a FastCGI process or not. * * Results: * Returns 1 if FastCGI, 0 if not. * * Side effects: * None. * *---------------------------------------------------------------------- */ int OS_IsFcgi(int sock) { // Touch args to prevent warnings sock = 0; /* XXX This is broken for sock */ return (listenType != FD_UNUSED); } /* *---------------------------------------------------------------------- * * OS_SetFlags -- * * Sets selected flag bits in an open file descriptor. Currently * this is only to put a SOCKET into non-blocking mode. * *---------------------------------------------------------------------- */ void OS_SetFlags(int fd, int flags) { unsigned long pLong = 1L; int err; if (fdTable[fd].type == FD_SOCKET_SYNC && flags == O_NONBLOCK) { if (ioctlsocket(fdTable[fd].fid.sock, FIONBIO, &pLong) == SOCKET_ERROR) { exit(WSAGetLastError()); } if (!CreateIoCompletionPort((HANDLE)fdTable[fd].fid.sock, hIoCompPort, fd, 1)) { err = GetLastError(); exit(err); } fdTable[fd].type = FD_SOCKET_ASYNC; } return; } FCGI-0.74/FCGI.XL0000644000175000017500000002567511453233747011613 0ustar raflrafluse Config; open OUT, ">FCGI.xs"; print "Generating FCGI.xs for Perl version $]\n"; #unless (exists $Config{apiversion} && $Config{apiversion} >= 5.005) unless ($] >= 5.005) { for (qw(sv_undef diehook warnhook in_eval)) { print OUT "#define PL_$_ $_\n" } } print OUT while ; close OUT; __END__ /* $Id: FCGI.XL,v 1.10 2003/06/22 00:24:11 robs Exp $ */ #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "fcgi_config.h" #include "fcgiapp.h" #include "fastcgi.h" #ifndef FALSE #define FALSE (0) #endif #ifndef TRUE #define TRUE (1) #endif #ifndef dTHX #define dTHX #endif #ifndef INT2PTR #define INT2PTR(a,b) ((a) (b)) #endif /* Deprecation added 2010-10-05. The deprecated functionality should not be * removed for at least a year after that. */ #define WIDE_CHAR_DEPRECATION_MSG "Use of wide characters in %s is deprecated" \ " and will stop wprking in a future version of FCGI" #if defined(USE_LOCKING) && defined(USE_THREADS) static perl_mutex accept_mutex; #endif typedef struct FCGP_Request { int accepted; int bound; SV* svin; SV* svout; SV* sverr; GV* gv[3]; HV* hvEnv; FCGX_Request* requestPtr; } FCGP_Request; static void FCGI_Finish(FCGP_Request* request); static void FCGI_Flush(FCGP_Request* request) { dTHX; if(!request->bound) return; FCGX_FFlush(INT2PTR(FCGX_Stream *, SvIV((SV*) SvRV(request->svout)))); FCGX_FFlush(INT2PTR(FCGX_Stream *, SvIV((SV*) SvRV(request->sverr)))); } static void FCGI_UndoBinding(FCGP_Request* request) { dTHX; #ifdef USE_PERLIO sv_unmagic((SV *)GvIOp(request->gv[0]), 'q'); sv_unmagic((SV *)GvIOp(request->gv[1]), 'q'); sv_unmagic((SV *)GvIOp(request->gv[2]), 'q'); #else sv_unmagic((SV *)request->gv[0], 'q'); sv_unmagic((SV *)request->gv[1], 'q'); sv_unmagic((SV *)request->gv[2], 'q'); #endif request->bound = FALSE; } static void FCGI_Bind(FCGP_Request* request) { dTHX; #ifdef USE_PERLIO /* For tied filehandles, we apply tiedscalar magic to the IO slot of the GP rather than the GV itself. */ if (!GvIOp(request->gv[1])) GvIOp(request->gv[1]) = newIO(); if (!GvIOp(request->gv[2])) GvIOp(request->gv[2]) = newIO(); if (!GvIOp(request->gv[0])) GvIOp(request->gv[0]) = newIO(); sv_magic((SV *)GvIOp(request->gv[1]), request->svout, 'q', Nullch, 0); sv_magic((SV *)GvIOp(request->gv[2]), request->sverr, 'q', Nullch, 0); sv_magic((SV *)GvIOp(request->gv[0]), request->svin, 'q', Nullch, 0); #else sv_magic((SV *)request->gv[1], request->svout, 'q', Nullch, 0); sv_magic((SV *)request->gv[2], request->sverr, 'q', Nullch, 0); sv_magic((SV *)request->gv[0], request->svin, 'q', Nullch, 0); #endif request->bound = TRUE; } static void populate_env(char **envp, HV *hv) { int i; char *p, *p1; SV *sv; dTHX; hv_clear(hv); for(i = 0; ; i++) { if((p = envp[i]) == NULL) break; p1 = strchr(p, '='); assert(p1 != NULL); sv = newSVpv(p1 + 1, 0); /* call magic for this value ourselves */ hv_store(hv, p, p1 - p, sv, 0); SvSETMAGIC(sv); } } static int FCGI_IsFastCGI(FCGP_Request* request) { static int isCGI = -1; /* -1: not checked; 0: FCGI; 1: CGI */ if (request->requestPtr->listen_sock == FCGI_LISTENSOCK_FILENO) { if (isCGI == -1) isCGI = FCGX_IsCGI(); return !isCGI; } /* A explicit socket is being used -> assume FastCGI */ return 1; } static int FCGI_Accept(FCGP_Request* request) { dTHX; if (!FCGI_IsFastCGI(request)) { static int been_here = 0; /* * Not first call to FCGI_Accept and running as CGI means * application is done. */ if (been_here) return EOF; been_here = 1; } else { FCGX_Request *fcgx_req = request->requestPtr; int acceptResult; FCGI_Finish(request); #if defined(USE_LOCKING) && defined(USE_THREADS) MUTEX_LOCK(&accept_mutex); #endif acceptResult = FCGX_Accept_r(fcgx_req); #if defined(USE_LOCKING) && defined(USE_THREADS) MUTEX_UNLOCK(&accept_mutex); #endif if(acceptResult < 0) { return acceptResult; } populate_env(fcgx_req->envp, request->hvEnv); if (!request->svout) { newSVrv(request->svout = newSV(0), "FCGI::Stream"); newSVrv(request->sverr = newSV(0), "FCGI::Stream"); newSVrv(request->svin = newSV(0), "FCGI::Stream"); } sv_setiv(SvRV(request->svout), INT2PTR(IV, fcgx_req->out)); sv_setiv(SvRV(request->sverr), INT2PTR(IV, fcgx_req->err)); sv_setiv(SvRV(request->svin), INT2PTR(IV, fcgx_req->in)); FCGI_Bind(request); request->accepted = TRUE; } return 0; } static void FCGI_Finish(FCGP_Request* request) { int was_bound; dTHX; if(!request->accepted) return; if (was_bound = request->bound) FCGI_UndoBinding(request); if (was_bound) FCGX_Finish_r(request->requestPtr); else FCGX_Free(request->requestPtr, 1); request->accepted = FALSE; } static int FCGI_StartFilterData(FCGP_Request* request) { return request->requestPtr->in ? FCGX_StartFilterData(request->requestPtr->in) : -1; } static FCGP_Request * FCGI_Request(GV *in, GV *out, GV *err, HV *env, int socket, int flags) { FCGX_Request* fcgx_req; FCGP_Request* req; Newz(551, fcgx_req, 1, FCGX_Request); FCGX_InitRequest(fcgx_req, socket, flags); Newz(551, req, 1, FCGP_Request); req->requestPtr = fcgx_req; SvREFCNT_inc(in); req->gv[0] = in; SvREFCNT_inc(out); req->gv[1] = out; SvREFCNT_inc(err); req->gv[2] = err; SvREFCNT_inc(env); req->hvEnv = env; return req; } static void FCGI_Release_Request(FCGP_Request *req) { SvREFCNT_dec(req->gv[0]); SvREFCNT_dec(req->gv[1]); SvREFCNT_dec(req->gv[2]); SvREFCNT_dec(req->hvEnv); FCGI_Finish(req); Safefree(req->requestPtr); Safefree(req); } static void FCGI_Init() { #if defined(USE_LOCKING) && defined(USE_THREADS) dTHX; MUTEX_INIT(&accept_mutex); #endif FCGX_Init(); } typedef FCGX_Stream* FCGI__Stream; typedef FCGP_Request* FCGI; typedef GV* GLOBREF; typedef HV* HASHREF; MODULE = FCGI PACKAGE = FCGI PREFIX = FCGI_ BOOT: FCGI_Init(); SV * RequestX(in, out, err, env, socket, flags) GLOBREF in; GLOBREF out; GLOBREF err; HASHREF env; int socket; int flags; PROTOTYPE: ***$$$ CODE: RETVAL = sv_setref_pv(newSV(0), "FCGI", FCGI_Request(in, out, err, env, socket, flags)); OUTPUT: RETVAL int OpenSocket(path, backlog) char* path; int backlog; PROTOTYPE: $$ CODE: RETVAL = FCGX_OpenSocket(path, backlog); OUTPUT: RETVAL void CloseSocket(socket) int socket; PROTOTYPE: $ CODE: close(socket); int FCGI_Accept(request) FCGI request; PROTOTYPE: $ void FCGI_Finish(request) FCGI request; PROTOTYPE: $ void FCGI_Flush(request) FCGI request; PROTOTYPE: $ HV * GetEnvironment(request) FCGI request; PROTOTYPE: $ CODE: RETVAL = request->hvEnv; OUTPUT: RETVAL void GetHandles(request) FCGI request; PROTOTYPE: $ PREINIT: int i; PPCODE: EXTEND(sp,3); for (i = 0; i < 3; ++i) PUSHs(sv_2mortal(newRV((SV *) request->gv[i]))); int FCGI_IsFastCGI(request) FCGI request; PROTOTYPE: $ void Detach(request) FCGI request; PROTOTYPE: $ CODE: if (request->accepted && request->bound) { FCGI_UndoBinding(request); FCGX_Detach(request->requestPtr); } void Attach(request) FCGI request; PROTOTYPE: $ CODE: if (request->accepted && !request->bound) { FCGI_Bind(request); FCGX_Attach(request->requestPtr); } void LastCall(request) FCGI request; PROTOTYPE: $ CODE: FCGX_ShutdownPending(); int FCGI_StartFilterData(request) FCGI request; PROTOTYPE: $ void DESTROY(request) FCGI request; CODE: FCGI_Release_Request(request); MODULE = FCGI PACKAGE = FCGI::Stream SV * PRINT(stream, ...) FCGI::Stream stream; PREINIT: int n; STRLEN len; register char *str; bool ok = TRUE; CODE: for (n = 1; ok && n < items; ++n) { #ifdef DO_UTF8 if (DO_UTF8(ST(n)) && !sv_utf8_downgrade(ST(n), 1) && ckWARN_d(WARN_UTF8)) Perl_warner(aTHX_ WARN_UTF8, WIDE_CHAR_DEPRECATION_MSG, "FCGI::Stream::PRINT"); #endif str = (char *)SvPV(ST(n),len); if (FCGX_PutStr(str, len, stream) < 0) ok = FALSE; } if (ok && SvTRUEx(perl_get_sv("|", FALSE)) && FCGX_FFlush(stream) < 0) ok = FALSE; RETVAL = ok ? &PL_sv_yes : &PL_sv_undef; OUTPUT: RETVAL int WRITE(stream, bufsv, len, ...) FCGI::Stream stream; SV *bufsv; int len; PREINIT: int offset; char *buf; STRLEN blen; int n; CODE: offset = (items == 4) ? (int)SvIV(ST(3)) : 0; #ifdef DO_UTF8 if (DO_UTF8(bufsv) && !sv_utf8_downgrade(bufsv, 1) && ckWARN_d(WARN_UTF8)) Perl_warner(aTHX_ WARN_UTF8, WIDE_CHAR_DEPRECATION_MSG, "FCGI::Stream::WRITE"); #endif buf = SvPV(bufsv, blen); if (offset < 0) offset += blen; if (len > blen - offset) len = blen - offset; if (offset < 0 || offset >= blen || (n = FCGX_PutStr(buf+offset, len, stream)) < 0) ST(0) = &PL_sv_undef; else { ST(0) = sv_newmortal(); sv_setiv(ST(0), n); } void READ(stream, bufsv, len, ...) FCGI::Stream stream; SV *bufsv; int len; PREINIT: int offset = 0; char *buf; STRLEN blen; CODE: if (items < 3 || items > 4) croak("Usage: FCGI::Stream::READ(STREAM, SCALAR, LENGTH [, OFFSET ])"); if (len < 0) croak("Negative length"); if (!SvOK(bufsv)) sv_setpvn(bufsv, "", 0); #ifdef DO_UTF8 if (DO_UTF8(bufsv) && !sv_utf8_downgrade(bufsv, 1) && ckWARN_d(WARN_UTF8)) Perl_warner(aTHX_ WARN_UTF8, WIDE_CHAR_DEPRECATION_MSG, "FCGI::Stream::READ"); #endif buf = SvPV_force(bufsv, blen); if (items == 4) { offset = SvIV(ST(3)); if (offset < 0) { if (-offset > (int)blen) croak("Offset outside string"); offset += blen; } } buf = SvGROW(bufsv, len + offset + 1); if (offset > blen) Zero(buf + blen, offset - blen, char); len = FCGX_GetStr(buf + offset, len, stream); SvCUR_set(bufsv, len + offset); *SvEND(bufsv) = '\0'; (void)SvPOK_only(bufsv); SvSETMAGIC(bufsv); XSRETURN_IV(len); SV * GETC(stream) FCGI::Stream stream; PREINIT: int retval; CODE: if ((retval = FCGX_GetChar(stream)) != -1) { ST(0) = sv_newmortal(); sv_setpvf(ST(0), "%c", retval); } else ST(0) = &PL_sv_undef; bool CLOSE(stream) FCGI::Stream stream; CODE: RETVAL = FCGX_FClose(stream) != -1; OUTPUT: RETVAL FCGI-0.74/fcgi_config.h.in0000644000175000017500000000505211637307637013640 0ustar raflrafl/* fcgi_config.h.in. Generated from configure.in by autoheader. */ /* Define to 1 if you have the header file. */ #undef HAVE_ARPA_INET_H /* Define if there's a fileno() prototype in stdio.h */ #undef HAVE_FILENO_PROTO /* Define if the fpos_t typedef is in stdio.h */ #undef HAVE_FPOS /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_LIMITS_H /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the header file. */ #undef HAVE_NETDB_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_IN_H /* Define if sockaddr_un in sys/un.h contains a sun_len component */ #undef HAVE_SOCKADDR_UN_SUN_LEN /* Define if the socklen_t typedef is in sys/socket.h */ #undef HAVE_SOCKLEN /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_PARAM_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SOCKET_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TIME_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define if va_arg(arg, long double) crashes the compiler */ #undef HAVE_VA_ARG_LONG_DOUBLE_BUG /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Define if cross-process locking is required by accept() */ #undef USE_LOCKING /* Define to empty if `const' does not conform to ANSI C. */ #undef const /* Define to `int' if does not define. */ #undef ssize_t FCGI-0.74/FCGI.PL0000644000175000017500000003200711637306261011562 0ustar raflrafluse Config; use ExtUtils::MakeMaker; do 'FCGI.cfg' or die "no FCGI.cfg"; open OUT, ">FCGI.pm"; print "Generating FCGI.pm\n"; print OUT <<'EOP'; # $Id: FCGI.PL,v 1.37 2002/12/15 20:02:48 skimo Exp $ package FCGI; require Exporter; require DynaLoader; @ISA = qw(Exporter DynaLoader); # Items to export into callers namespace by default. Note: do not export # names by default without a very good reason. Use EXPORT_OK instead. # Do not simply export all your public functions/methods/constants. @EXPORT = qw( ); EOP print OUT '$VERSION = q{'.MM->parse_version('version.pm')."};\n\n"; print OUT "bootstrap FCGI;\n" unless ($pure); print OUT '$VERSION = eval $VERSION;'; print OUT <<'EOP' if ($pure); use Symbol; use POSIX 'ENOTCONN'; use constant VERSION_1 => 1; use constant BEGIN_REQUEST => 1; use constant PARAMS => 4; use constant FCGI_STDIN => 5; use constant FCGI_STDOUT => 6; use constant FCGI_STDERR => 7; use constant RESPONDER => 1; use constant AUTHORIZER => 2; use constant FILTER => 3; %FCGI::rolenames = (RESPONDER, "RESPONDER", AUTHORIZER, "AUTHORIZER", FILTER, "FILTER", ); # This only works on Unix; anyone familiar with Windows is welcome # to give a hand here sub IsFastCGI { my ($req) = @_; $req->{isfastcgi} = (!defined getpeername shift->{listen_sock}) && $! == ENOTCONN unless exists $req->{isfastcgi}; return $req->{isfastcgi}; } sub GetEnvironment { return shift->{'env'}; } sub read_nv_len { my ($stream) = @_; my $buf; return undef unless read $stream, $buf, 1, 0; my ($len) = unpack("C", $buf); if ($len & 0x80) { $buf = pack("C", $len & 0x7F); return undef unless read $stream, $buf, 3, 1; $len = unpack("N", $buf); } $len; } sub RequestX { my $self = { in => shift, out => shift, err => shift, env => shift, socket => shift, flags => shift, last => 0, }; open $self->{listen_sock}, "<&=0"; bless $self, "FCGI"; } my $run_once = 0; sub Accept { my ($req) = @_; unless ($req->IsFastCGI()) { return -1 if $run_once; $run_once = 1; return 0; } $req->Finish(); $req->{socket} = gensym(); if ($req->{last} || !accept($req->{socket}, $req->{listen_sock})) { $req->{error} = "accept"; return -1; } my ($type, $id, $body) = $req->read_record(); if ($type != BEGIN_REQUEST) { $req->{error} = "begin request"; return -1; } my ($role, $flags) = unpack("nC", $body); $req->{role} = $role; $req->{flags} = $flags; $req->{id} = $id; %{$req->{env}} = (); $req->{env}{FCGI_ROLE} = $FCGI::rolenames{$req->{role}}; my $param = FCGI::Stream->new($req, PARAMS); my ($nlen, $vlen); while (defined($nlen = read_nv_len($param)) && defined($vlen = read_nv_len($param))) { my ($name, $val); read $param, $name, $nlen; read $param, $val, $vlen; $req->{env}{$name} = $val; } $req->Bind; $req->{accepted} = 1; return 0; } sub UndoBindings { my ($req) = @_; untie ${$req->{in}}; untie ${$req->{out}}; untie ${$req->{err}}; $req->{bound} = 0; } sub Bind { my ($req) = @_; tie ${$req->{in}}, 'FCGI::Stream', $req, FCGI_STDIN; tie ${$req->{out}}, 'FCGI::Stream', $req, FCGI_STDOUT; tie ${$req->{err}}, 'FCGI::Stream', $req, FCGI_STDERR; $req->{bound} = 1; } sub Attach { my ($req) = @_; $req->Bind() if ($req->{accepted} && !$req->{bound}); } sub Detach { my ($req) = @_; $req->UndoBindings() if ($req->{accepted} && $req->{bound}); } sub Finish { my ($req) = @_; return unless $req->{accepted}; if ($req->{bound}) { $req->UndoBindings(); # apparently these are harmful # close ${$req->{out}}; # close ${$req->{err}}; } $req->{accepted} = 0; } sub LastCall { shift->{last} = 1; } sub DESTROY { shift->Finish(); } sub read_record { my ($self) = @_; my ($header, $body); read($self->{socket}, $header, 8); my ($version, $type, $id, $clen, $plen) = unpack("CCnnC", $header); read($self->{socket}, $body, $clen+$plen); $body = undef if $clen == 0; ($type, $id, $body); } sub read { my ($self, $rtype, $len) = @_; while (length $self->{buf} < $len) { my ($type, $id, $buf) = $self->read_record(); return undef unless defined $buf; if ($type != $rtype) { $self->{error} = "unexpected stream type"; return 0; } $self->{buf} .= $buf; } my ($newbuf, $result) = (substr($self->{buf}, $len), substr($self->{buf}, 0, $len)); $self->{buf} = $newbuf; $result; } sub Flush { my ($req) = @_; } sub write { my ($self, $type, $content, $len) = @_; return unless $len > 0; $self->write_record($type, $content, $len); } sub write_record { my ($self, $type, $content, $length) = @_; my $offset = 0; while ($length > 0) { my $len = $length > 32*1024 ? 32*1024 : $length; my $padlen = (8 - ($len % 8)) % 8; my $templ = "CCnnCxa${len}x$padlen"; my $data = pack($templ, VERSION_1, $type, $self->{id}, $len, $padlen, substr($content, $offset, $len)); syswrite $self->{socket}, $data; $length -= $len; $offset += $len; } } { package FCGI::Stream; sub new { my ($class, $src, $type) = @_; my $handle = do { \local *FH }; tie($$handle, $class, $src, $type); $handle; } sub TIEHANDLE { my ($class, $src, $type) = @_; bless { src => $src, type => $type }, $class; } sub READ { my ($stream, undef, $len, $offset) = @_; my ($ref) = \$_[1]; my $buf = $stream->{src}->read($stream->{type}, $len); return undef unless defined $buf; substr($$ref, $offset, 0, $buf); length $buf; } sub PRINT { my ($stream) = shift; for (@_) { $stream->{src}->write($stream->{type}, $_, length($_)); } return 1; } sub CLOSE { my ($stream) = @_; $stream->{src}->write_record($stream->{type}, undef, 0); } } EOP print OUT while ; close OUT; __END__ # Preloaded methods go here. # Autoload methods go after __END__, and are processed by the autosplit program. *FAIL_ACCEPT_ON_INTR = sub() { 1 }; sub Request(;***$*$) { my @defaults = (\*STDIN, \*STDOUT, \*STDERR, \%ENV, 0, FAIL_ACCEPT_ON_INTR()); $_[4] = fileno($_[4]) if defined($_[4]) && defined(fileno($_[4])); splice @defaults,0,@_,@_; RequestX(@defaults); } sub accept() { warn "accept called as a method; you probably wanted to call Accept" if @_; if ( defined($FCGI::ENV) ) { %ENV = %$FCGI::ENV; } else { $FCGI::ENV = {%ENV}; } my $rc = Accept($global_request); for (keys %$FCGI::ENV) { $ENV{$_} = $FCGI::ENV->{$_} unless exists $ENV{$_}; } # not SFIO $SIG{__WARN__} = $warn_handler if (tied (*STDIN)); $SIG{__DIE__} = $die_handler if (tied (*STDIN)); return $rc; } sub finish() { warn "finish called as a method; you probably wanted to call Finish" if @_; %ENV = %$FCGI::ENV if defined($FCGI::ENV); # not SFIO if (tied (*STDIN)) { delete $SIG{__WARN__} if ($SIG{__WARN__} == $warn_handler); delete $SIG{__DIE__} if ($SIG{__DIE__} == $die_handler); } Finish ($global_request); } sub flush() { warn "flush called as a method; you probably wanted to call Flush" if @_; Flush($global_request); } sub detach() { warn "detach called as a method; you probably wanted to call Detach" if @_; Detach($global_request); } sub attach() { warn "attach called as a method; you probably wanted to call Attach" if @_; Attach($global_request); } # deprecated sub set_exit_status { } sub start_filter_data() { StartFilterData($global_request); } $global_request = Request(); $warn_handler = sub { print STDERR @_ }; $die_handler = sub { print STDERR @_ unless $^S }; package FCGI::Stream; sub PRINTF { shift->PRINT(sprintf(shift, @_)); } sub BINMODE { } sub READLINE { my $stream = shift; my ($s, $c); my $rs = $/ eq '' ? "\n\n" : $/; my $l = substr $rs, -1; my $len = length $rs; $c = $stream->GETC(); if ($/ eq '') { while ($c eq "\n") { $c = $stream->GETC(); } } while (defined $c) { $s .= $c; last if $c eq $l and substr($s, -$len) eq $rs; $c = $stream->GETC(); } $s; } sub OPEN { $_[0]->CLOSE; if (@_ == 2) { return open($_[0], $_[1]); } else { my $rc; eval("$rc = open($_[0], $_[1], $_[2])"); die $@ if $@; return $rc; } } # Some things (e.g. IPC::Run) use fileno to determine if a filehandle is open, # so we return a defined, but meaningless value. (-1 being the error return # value from the syscall in c, meaning it can never be a valid fd no) # Probably a better alternative would be to return the fcgi stream fd. sub FILENO { -1 } 1; =pod =head1 NAME FCGI - Fast CGI module =head1 SYNOPSIS use FCGI; my $count = 0; my $request = FCGI::Request(); while($request->Accept() >= 0) { print("Content-type: text/html\r\n\r\n", ++$count); } =head1 DESCRIPTION Functions: =over 4 =item FCGI::Request Creates a request handle. It has the following optional parameters: =over 8 =item input perl file handle (default: \*STDIN) =item output perl file handle (default: \*STDOUT) =item error perl file handle (default: \*STDERR) These filehandles will be setup to act as input/output/error on successful Accept. =item environment hash reference (default: \%ENV) The hash will be populated with the environment. =item socket (default: 0) Socket to communicate with the server. Can be the result of the OpenSocket function. For the moment, it's the file descriptor of the socket that should be passed. This may change in the future. You should only use your own socket if your program is not started by a process manager such as mod_fastcgi (except for the FastCgiExternalServer case) or cgi-fcgi. If you use the option, you have to let your FastCGI server know which port (and possibly server) your program is listening on. See remote.pl for an example. =item flags (default: 0) Possible values: =over 12 =item FCGI::FAIL_ACCEPT_ON_INTR If set, Accept will fail if interrupted. It not set, it will just keep on waiting. =back =back Example usage: my $req = FCGI::Request; or: my %env; my $in = new IO::Handle; my $out = new IO::Handle; my $err = new IO::Handle; my $req = FCGI::Request($in, $out, $err, \%env); =item FCGI::OpenSocket(path, backlog) Creates a socket suitable to use as an argument to Request. =over 8 =item path Pathname of socket or colon followed by local tcp port. Note that some systems take file permissions into account on Unix domain sockets, so you'll have to make sure that the server can write to the created file, by changing the umask before the call and/or changing permissions and/or group of the file afterwards. =item backlog Maximum length of the queue of pending connections. If a connection request arrives with the queue full the client may receive an error with an indication of ECONNREFUSED. =back =item FCGI::CloseSocket(socket) Close a socket opened with OpenSocket. =item $req->Accept() Accepts a connection on $req, attaching the filehandles and populating the environment hash. Returns 0 on success. If a connection has been accepted before, the old one will be finished first. Note that unlike with the old interface, no die and warn handlers are installed by default. This means that if you are not running an sfio enabled perl, any warn or die message will not end up in the server's log by default. It is advised you set up die and warn handlers yourself. FCGI.pm contains an example of die and warn handlers. =item $req->Finish() Finishes accepted connection. Also detaches filehandles. =item $req->Flush() Flushes accepted connection. =item $req->Detach() Temporarily detaches filehandles on an accepted connection. =item $req->Attach() Re-attaches filehandles on an accepted connection. =item $req->LastCall() Tells the library not to accept any more requests on this handle. It should be safe to call this method from signal handlers. Note that this method is still experimental and everything about it, including its name, is subject to change. =item $env = $req->GetEnvironment() Returns the environment parameter passed to FCGI::Request. =item ($in, $out, $err) = $req->GetHandles() Returns the file handle parameters passed to FCGI::Request. =item $isfcgi = $req->IsFastCGI() Returns whether or not the program was run as a FastCGI. =back =HEAD1 LIMITATIONS FCGI.pm isn't Unicode aware, only characters within the range 0x00-0xFF are supported. Attempts to output strings containing characters above 0xFF results in a exception: (F) C. Users who wants the previous (FCGI.pm <= 0.68) incorrect behavior can disable the exception by using the C pragma. { use bytes; print "\x{263A}"; } =head1 AUTHOR Sven Verdoolaege =cut __END__