It builds on a Sun, buts untested.
There may be some issues with WinNT.
*
*/
#ifndef lint
-static const char rcsid[] = "$Id: cgi-fcgi.c,v 1.7 1999/07/28 00:38:34 roberts Exp $";
+static const char rcsid[] = "$Id: cgi-fcgi.c,v 1.8 1999/08/05 21:25:51 roberts Exp $";
#endif /* not lint */
#include "fcgi_config.h"
{
int listenFd, i;
- if((listenFd = OS_CreateLocalIpcFd(bindPath)) == -1) {
+ /* @@@ Should be able to pick up the backlog as an arg */
+ if((listenFd = OS_CreateLocalIpcFd(bindPath, 5)) == -1) {
exit(OS_Errno);
}
*/
#ifndef lint
-static const char rcsid[] = "$Id: threaded.c,v 1.5 1999/08/05 14:18:35 roberts Exp $";
+static const char rcsid[] = "$Id: threaded.c,v 1.6 1999/08/05 21:25:51 roberts Exp $";
#endif /* not lint */
#include "fcgi_config.h"
FCGX_ParamArray envp;
char *server_name;
- FCGX_InitRequest(&request);
+ FCGX_InitRequest(&request, 0, 0);
for (;;)
{
/* Some platforms require accept() serialization, some don't.. */
pthread_mutex_lock(&accept_mutex);
- rc = FCGX_Accept_r(&in, &out, &err, &envp, &request);
+ rc = FCGX_Accept_r(&request);
pthread_mutex_unlock(&accept_mutex);
if (rc < 0)
* 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.3 1999/07/28 00:27:51 roberts Exp $
+ * $Id: fcgiapp.h,v 1.4 1999/08/05 21:25:52 roberts Exp $
*/
#ifndef _FCGIAPP_H
typedef char **FCGX_ParamArray;
/*
- * State associated with a request.
+ * FCGX_Request Flags
*
- * Its exposed for API simplicity, DON'T use it - it WILL change!
+ * 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 requestId; /* valid if isBeginProcessed */
int keepConnection; /* don't close ipcFd at end of request */
- int role;
int appStatus;
int nWriters; /* number of open writers (0..2) */
- FCGX_Stream *inStream;
- FCGX_Stream *outStream;
- FCGX_Stream *errStream;
- struct Params *paramsPtr;
+ int flags;
+ int listen_sock;
} FCGX_Request;
\f
/*
*----------------------------------------------------------------------
*
+ * 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().
+ * 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 void FCGX_InitRequest(FCGX_Request *request);
+DLLAPI int FCGX_InitRequest(FCGX_Request *request, int sock, int flags);
/*
*----------------------------------------------------------------------
*
*----------------------------------------------------------------------
*/
-DLLAPI int FCGX_Accept_r(
- FCGX_Stream **in,
- FCGX_Stream **out,
- FCGX_Stream **err,
- FCGX_ParamArray *envp,
- FCGX_Request *request);
+DLLAPI int FCGX_Accept_r(FCGX_Request *request);
/*
*----------------------------------------------------------------------
DLLAPI int OS_LibInit(int stdioFds[3]);
DLLAPI void OS_LibShutdown(void);
-DLLAPI int OS_CreateLocalIpcFd(char *bindPath);
+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_Close(int fd);
DLLAPI int OS_CloseRead(int fd);
DLLAPI int OS_DoIo(struct timeval *tmo);
-DLLAPI int OS_FcgiIpcAccept(char *clientAddrList);
+DLLAPI int OS_Accept(int listen_sock, int fail_on_intr, const char *clientAddrList);
DLLAPI int OS_IpcClose(int ipcFd);
-DLLAPI int OS_IsFcgi(void);
+DLLAPI int OS_IsFcgi(int sock);
DLLAPI void OS_SetFlags(int fd, int flags);
#if defined (__cplusplus) || defined (c_plusplus)
*
*/
#ifndef lint
-static const char rcsid[] = "$Id: fcgiapp.c,v 1.7 1999/07/28 00:22:18 roberts Exp $";
+static const char rcsid[] = "$Id: fcgiapp.c,v 1.8 1999/08/05 21:25:53 roberts Exp $";
#endif /* not lint */
#include "fcgi_config.h"
* Frees a Params structure and all the parameters it contains.
*
* Side effects:
- * paramsPtr becomes invalid.
+ * env becomes invalid.
*
*----------------------------------------------------------------------
*/
}
}
- isFastCGI = OS_IsFcgi();
+ isFastCGI = OS_IsFcgi(FCGI_LISTENSOCK_FILENO);
return !isFastCGI;
}
return;
}
- if (reqDataPtr->inStream) {
- int errStatus = FCGX_FClose(reqDataPtr->errStream);
- int outStatus = FCGX_FClose(reqDataPtr->outStream);
+ if (reqDataPtr->in) {
+ int errStatus = FCGX_FClose(reqDataPtr->err);
+ int outStatus = FCGX_FClose(reqDataPtr->out);
if (errStatus || outStatus
- || FCGX_GetError(reqDataPtr->inStream)
+ || FCGX_GetError(reqDataPtr->in)
|| !reqDataPtr->keepConnection)
{
OS_IpcClose(reqDataPtr->ipcFd);
ASSERT(reqDataPtr->nWriters == 0);
- FreeStream(&reqDataPtr->inStream);
- FreeStream(&reqDataPtr->outStream);
- FreeStream(&reqDataPtr->errStream);
+ FreeStream(&reqDataPtr->in);
+ FreeStream(&reqDataPtr->out);
+ FreeStream(&reqDataPtr->err);
FreeParams(&reqDataPtr->paramsPtr);
}
reqDataPtr->ipcFd = -1;
}
}
-\f
-void FCGX_InitRequest(FCGX_Request *request)
+int FCGX_OpenSocket(const char *path, int backlog)
+{
+ return OS_CreateLocalIpcFd(path, backlog);
+}
+
+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;
+
+ return 0;
}
/*
/* If our compiler doesn't play by the ISO rules for struct layout, halt. */
ASSERT(sizeof(FCGI_Header) == FCGI_HEADER_LEN);
- FCGX_InitRequest(&reqData);
+ FCGX_InitRequest(&reqData, FCGI_LISTENSOCK_FILENO, 0);
if (OS_LibInit(NULL) == -1) {
return OS_Errno ? OS_Errno : -9997;
}
}
- return FCGX_Accept_r(in, out, err, envp, &reqData);
+ return FCGX_Accept_r(&reqData);
}
/*
*
*----------------------------------------------------------------------
*/
-int FCGX_Accept_r(
- FCGX_Stream **in,
- FCGX_Stream **out,
- FCGX_Stream **err,
- FCGX_ParamArray *envp,
- FCGX_Request *reqDataPtr)
+int FCGX_Accept_r(FCGX_Request *reqDataPtr)
{
+ FCGX_Stream **in = &reqDataPtr->in;
+ FCGX_Stream **out = &reqDataPtr->out;
+ FCGX_Stream **err = &reqDataPtr->err;
+ FCGX_ParamArray *envp = &reqDataPtr->envp;
+
if (!libInitialized) {
return -9998;
}
* return -1 to the caller, who should exit.
*/
if (reqDataPtr->ipcFd < 0) {
- reqDataPtr->ipcFd = OS_FcgiIpcAccept(webServerAddressList);
+ 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;
}
* errors occur, close the connection and try again.
*/
reqDataPtr->isBeginProcessed = FALSE;
- reqDataPtr->inStream = NewReader(reqDataPtr, 8192, 0);
- FillBuffProc(reqDataPtr->inStream);
+ reqDataPtr->in = NewReader(reqDataPtr, 8192, 0);
+ FillBuffProc(reqDataPtr->in);
if(!reqDataPtr->isBeginProcessed) {
goto TryAgain;
}
reqDataPtr->paramsPtr = NewParams(30);
PutParam(reqDataPtr->paramsPtr, StringCopy(roleStr));
}
- SetReaderType(reqDataPtr->inStream, FCGI_PARAMS);
- if(ReadParams(reqDataPtr->paramsPtr, reqDataPtr->inStream) >= 0) {
+ 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.
*/
TryAgain:
FreeParams(&reqDataPtr->paramsPtr);
- FreeStream(&reqDataPtr->inStream);
+ FreeStream(&reqDataPtr->in);
OS_Close(reqDataPtr->ipcFd);
reqDataPtr->ipcFd = -1;
} /* for (;;) */
* Build the remaining data structures representing the new
* request and return successfully to the caller.
*/
- SetReaderType(reqDataPtr->inStream, FCGI_STDIN);
- reqDataPtr->outStream = NewWriter(reqDataPtr, 8192, FCGI_STDOUT);
- reqDataPtr->errStream = NewWriter(reqDataPtr, 512, FCGI_STDERR);
+ SetReaderType(reqDataPtr->in, FCGI_STDIN);
+ reqDataPtr->out = NewWriter(reqDataPtr, 8192, FCGI_STDOUT);
+ reqDataPtr->err = NewWriter(reqDataPtr, 512, FCGI_STDERR);
reqDataPtr->nWriters = 2;
- *in = reqDataPtr->inStream;
- *out = reqDataPtr->outStream;
- *err = reqDataPtr->errStream;
+ *in = reqDataPtr->in;
+ *out = reqDataPtr->out;
+ *err = reqDataPtr->err;
*envp = reqDataPtr->paramsPtr->vec;
return 0;
}
SetError(stream, FCGX_CALL_SEQ_ERROR);
return -1;
}
- SetReaderType(reqDataPtr->inStream, FCGI_DATA);
+ SetReaderType(reqDataPtr->in, FCGI_DATA);
return 0;
}
\f
*/
#ifndef lint
-static const char rcsid[] = "$Id: os_unix.c,v 1.11 1999/08/02 19:22:00 skimo Exp $";
+static const char rcsid[] = "$Id: os_unix.c,v 1.12 1999/08/05 21:25:55 roberts Exp $";
#endif /* not lint */
#include "fcgi_config.h"
static int asyncIoTableSize = 16;
static AioInfo *asyncIoTable = NULL;
-static int isFastCGI = FALSE;
static int libInitialized = FALSE;
static fd_set readFdSet;
*----------------------------------------------------------------------
*/
-static int OS_BuildSockAddrUn(char *bindPath,
+static int OS_BuildSockAddrUn(const char *bindPath,
struct sockaddr_un *servAddrPtr,
int *servAddrLen)
{
*
*----------------------------------------------------------------------
*/
-int OS_CreateLocalIpcFd(char *bindPath)
+int OS_CreateLocalIpcFd(const char *bindPath, int backlog)
{
int listenSock, servLen;
union SockAddrUnion sa;
}
}
if(bind(listenSock, (struct sockaddr *) &sa.unixVariant, servLen) < 0
- || listen(listenSock, 5) < 0) {
+ || listen(listenSock, backlog) < 0) {
perror("bind/listen");
exit(errno);
}
*
*----------------------------------------------------------------------
*/
-static int ClientAddrOK(struct sockaddr_in *saPtr, char *clientList)
+static int ClientAddrOK(struct sockaddr_in *saPtr, const char *clientList)
{
int result = FALSE;
char *clientListCopy, *cur, *next;
*
*----------------------------------------------------------------------
*/
-static int AcquireLock(int blocking)
+static int AcquireLock(int sock, int fail_on_intr)
{
#ifdef USE_LOCKING
- struct flock lock;
- lock.l_type = F_WRLCK;
- lock.l_start = 0;
- lock.l_whence = SEEK_SET;
- lock.l_len = 0;
-
- if(fcntl(FCGI_LISTENSOCK_FILENO,
- blocking ? F_SETLKW : F_SETLK, &lock) < 0) {
- if (errno != EINTR)
- return -1;
- }
-#endif /* 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);
+
+ return -1;
+
+#else
return 0;
+#endif
}
\f
/*
*
*----------------------------------------------------------------------
*/
-static int ReleaseLock(void)
+static int ReleaseLock(int sock)
{
#ifdef USE_LOCKING
- struct flock lock;
- lock.l_type = F_UNLCK;
- lock.l_start = 0;
- lock.l_whence = SEEK_SET;
- lock.l_len = 0;
+ 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);
- if(fcntl(FCGI_LISTENSOCK_FILENO, F_SETLK, &lock) < 0) {
- return -1;
- }
-#endif /* USE_LOCKING */
+ return -1;
+
+#else
return 0;
+#endif
}
\f
/*
*----------------------------------------------------------------------
*
- * OS_FcgiIpcAccept --
+ * OS_Accept --
*
* Accepts a new FastCGI connection. This routine knows whether
* we're dealing with TCP based sockets or NT Named Pipes for IPC.
*
*----------------------------------------------------------------------
*/
-int OS_FcgiIpcAccept(char *clientAddrList)
+int OS_Accept(int listen_sock, int fail_on_intr, const char *clientAddrList)
{
int socket;
union {
struct sockaddr_un un;
struct sockaddr_in in;
} sa;
-#ifdef HAVE_SOCKLEN
- socklen_t len;
-#else
- int len;
-#endif
- while (1) {
- if (AcquireLock(TRUE) < 0)
- return (-1);
+ for (;;) {
+ if (AcquireLock(listen_sock, fail_on_intr))
+ return -1;
- while (1) {
+ for (;;) {
do {
- len = sizeof(sa);
- socket = accept(FCGI_LISTENSOCK_FILENO, (struct sockaddr *) &sa.un, &len);
- } while (socket < 0 && errno == EINTR);
+#ifdef HAVE_SOCKLEN
+ socklen_t len = sizeof(sa);
+#else
+ int len = sizeof(sa);
+#endif
+ socket = accept(listen_sock, (struct sockaddr *)&sa, &len);
+ } while (socket < 0 && errno == EINTR && !fail_on_intr);
if (socket < 0) {
if (!is_reasonable_accept_errno(errno)) {
int errnoSave = errno;
-
- ReleaseLock();
+ ReleaseLock(listen_sock);
errno = errnoSave;
return (-1);
}
errno = 0;
}
- else {
+ else { /* socket >= 0 */
int set = 1;
if (sa.in.sin_family != AF_INET)
break;
close(socket);
- }
- } /* while(1) - accept */
+ } /* socket >= 0 */
+ } /* for(;;) */
- if (ReleaseLock() < 0)
+ if (ReleaseLock(listen_sock))
return (-1);
if (sa.in.sin_family != AF_UNIX || is_af_unix_keeper(socket))
*
*----------------------------------------------------------------------
*/
-int OS_IsFcgi()
+int OS_IsFcgi(int sock)
{
+ int isFastCGI = FALSE;
union {
struct sockaddr_in in;
struct sockaddr_un un;
int len = sizeof(sa);
#endif
- if (getpeername(FCGI_LISTENSOCK_FILENO, (struct sockaddr *)&sa, &len) != 0
- && errno == ENOTCONN)
- isFastCGI = TRUE;
- else
- isFastCGI = FALSE;
-
- return (isFastCGI);
+ if (getpeername(sock, (struct sockaddr *)&sa, &len) != 0 && errno == ENOTCONN) {
+ return TRUE;
+ }
+ else {
+ return FALSE;
+ }
}
\f
/*
* significantly more enjoyable.)
*/
#ifndef lint
-static const char rcsid[] = "$Id: os_win32.c,v 1.2 1999/07/28 00:18:31 roberts Exp $";
+static const char rcsid[] = "$Id: os_win32.c,v 1.3 1999/08/05 21:25:56 roberts Exp $";
#endif /* not lint */
#include "fcgi_config.h"
static const char *bindPathPrefix = "\\\\.\\pipe\\FastCGI\\";
-static int isFastCGI = FALSE;
-static int isCGI = FALSE;
static int listenType = FD_UNUSED;
static HANDLE hListen = INVALID_HANDLE_VALUE;
static int libInitialized = 0;
(GetStdHandle(STD_INPUT_HANDLE) != INVALID_HANDLE_VALUE) ) {
hListen = GetStdHandle(STD_INPUT_HANDLE);
- isFastCGI = TRUE;
/*
* Set the pipe handle state so that it operates in wait mode.
*
*----------------------------------------------------------------------
*/
-int OS_CreateLocalIpcFd(char *bindPath)
+int OS_CreateLocalIpcFd(const char *bindPath, int backlog)
{
int retFd = -1;
SECURITY_ATTRIBUTES sa;
servLen = sizeof(sockAddr);
if(bind(listenSock, (struct sockaddr *) &sockAddr, servLen) < 0
- || listen(listenSock, 5) < 0) {
+ || listen(listenSock, backlog) < 0) {
perror("bind/listen");
exit(errno);
}
/*
*----------------------------------------------------------------------
*
- * OS_FcgiIpcAccept --
+ * OS_Accept --
*
* Accepts a new FastCGI connection. This routine knows whether
* we're dealing with TCP based sockets or NT Named Pipes for IPC.
*
*----------------------------------------------------------------------
*/
-int OS_FcgiIpcAccept(char *serverHostList)
+int OS_Accept(int listen_sock, int fail_on_intr, const char *clientAddrList)
{
+ /* XXX This is broken for listen_sock & fail_on_intr */
struct sockaddr_in sa;
int isNewConnection;
int ipcFd = -1;
*
*----------------------------------------------------------------------
*/
-int OS_IsFcgi()
+int OS_IsFcgi(int sock)
{
+ /* XXX This is broken for sock */
if(listenType == FD_UNUSED) {
- isCGI = TRUE;
- return 0;
+ return FALSE;
} else {
- isCGI = FALSE;
- return 1;
+ return TRUE;
}
}