-/*
+/*
* 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
+ *
+ * Copyright (c) 1996 Open Market, Inc.
+ *
+ * See the file "LICENSE" for information on usage and redistribution
+ * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
#ifndef lint
-static const char rcsid[] = "$Id: os_unix.c,v 1.4 1998/12/09 03:25:43 roberts Exp $";
+static const char rcsid[] = "$Id: os_unix.c,v 1.38 2003/06/22 00:16:43 robs Exp $";
#endif /* not lint */
-#include "fcgimisc.h"
-#include "fcgiapp.h"
-#include "fcgiappmisc.h"
-#include "fastcgi.h"
+#include "fcgi_config.h"
-#include <stdio.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
+#include <sys/types.h>
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
#endif
+
+#include <arpa/inet.h>
#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-#include <memory.h> /* for memchr() */
#include <errno.h>
-#include <stdarg.h>
+#include <fcntl.h> /* for fcntl */
#include <math.h>
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h> /* for getpeername */
-#endif
+#include <memory.h> /* for memchr() */
+#include <netinet/tcp.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
#include <sys/un.h>
-#include <fcntl.h> /* for fcntl */
+#include <signal.h>
+
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
-#include <sys/time.h>
-#include <sys/types.h>
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h> /* for getpeername */
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
#endif
-#include <arpa/inet.h>
+#include "fastcgi.h"
+#include "fcgimisc.h"
#include "fcgios.h"
-#ifndef _CLIENTDATA
-# if defined(__STDC__) || defined(__cplusplus)
- typedef void *ClientData;
-# else
- typedef int *ClientData;
-# endif /* __STDC__ */
-#define _CLIENTDATA
+#ifndef INADDR_NONE
+#define INADDR_NONE ((unsigned long) -1)
#endif
/*
#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;
-#define STDIN_FILENO 0
-#define STDOUT_FILENO 1
-#define STDERR_FILENO 2
-
-#ifndef FALSE
-#define FALSE 0
-#endif
-#ifndef TRUE
-#define TRUE 1
-#endif
-
-static int isFastCGI = FALSE;
static int libInitialized = FALSE;
static fd_set readFdSet;
static int numWrPosted = 0;
static int volatile maxFd = -1;
-\f
+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);
+}
+
/*
*--------------------------------------------------------------
*
{
if(libInitialized)
return 0;
-
- asyncIoTable = malloc(asyncIoTableSize * sizeof(AioInfo));
+
+ asyncIoTable = (AioInfo *)malloc(asyncIoTableSize * sizeof(AioInfo));
if(asyncIoTable == NULL) {
errno = ENOMEM;
return -1;
FD_ZERO(&writeFdSet);
FD_ZERO(&readFdSetPost);
FD_ZERO(&writeFdSetPost);
+
+ OS_InstallSignalHandlers(TRUE);
+
libInitialized = TRUE;
+
return 0;
}
-\f
/*
*--------------------------------------------------------------
*
{
if(!libInitialized)
return;
-
+
free(asyncIoTable);
asyncIoTable = NULL;
libInitialized = FALSE;
return;
}
-\f
/*
*----------------------------------------------------------------------
*
*----------------------------------------------------------------------
*/
-static int OS_BuildSockAddrUn(char *bindPath,
+static int OS_BuildSockAddrUn(const char *bindPath,
struct sockaddr_un *servAddrPtr,
int *servAddrLen)
{
#endif
return 0;
}
-\f
union SockAddrUnion {
struct sockaddr_un unixVariant;
struct sockaddr_in inetVariant;
};
-\f
/*
* OS_CreateLocalIpcFd --
*
*
*----------------------------------------------------------------------
*/
-int OS_CreateLocalIpcFd(char *bindPath)
+int OS_CreateLocalIpcFd(const char *bindPath, int backlog)
{
int listenSock, servLen;
- union SockAddrUnion sa;
+ union SockAddrUnion sa;
int tcp = FALSE;
+ unsigned long tcp_ia = 0;
char *tp;
- short port;
+ short port = 0;
char host[MAXPATHLEN];
+ if (strlen(bindPath) >= MAXPATHLEN) {
+ fprintf(stderr,
+ "Listening socket path is longer than %d bytes -- exiting!\n",
+ MAXPATHLEN);
+ exit(1);
+ }
strcpy(host, bindPath);
if((tp = strchr(host, ':')) != 0) {
*tp++ = 0;
tcp = TRUE;
}
}
- if(tcp && (*host && strcmp(host, "localhost") != 0)) {
- fprintf(stderr, "To start a service on a TCP port can not "
- "specify a host name.\n"
- "You should either use \"localhost:<port>\" or "
- " just use \":<port>.\"\n");
- exit(1);
+ 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) {
if(tcp) {
memset((char *) &sa.inetVariant, 0, sizeof(sa.inetVariant));
sa.inetVariant.sin_family = AF_INET;
- sa.inetVariant.sin_addr.s_addr = htonl(INADDR_ANY);
+ sa.inetVariant.sin_addr.s_addr = tcp_ia;
sa.inetVariant.sin_port = htons(port);
servLen = sizeof(sa.inetVariant);
} else {
}
}
if(bind(listenSock, (struct sockaddr *) &sa.unixVariant, servLen) < 0
- || listen(listenSock, 5) < 0) {
+ || listen(listenSock, backlog) < 0) {
perror("bind/listen");
exit(errno);
}
return listenSock;
}
-\f
/*
*----------------------------------------------------------------------
*
int connectStatus;
char *tp;
char host[MAXPATHLEN];
- short port;
+ short port = 0;
int tcp = FALSE;
+ if (strlen(bindPath) >= MAXPATHLEN) {
+ fprintf(stderr, "Listening socket path is too long\n");
+ exit(1000);
+ }
strcpy(host, bindPath);
if((tp = strchr(host, ':')) != 0) {
*tp++ = 0;
resultSock = socket(AF_UNIX, SOCK_STREAM, 0);
}
- assert(resultSock >= 0);
+ ASSERT(resultSock >= 0);
connectStatus = connect(resultSock, (struct sockaddr *) &sa.unixVariant,
servLen);
if(connectStatus >= 0) {
return -1;
}
}
-
-\f
+
/*
*--------------------------------------------------------------
*
*/
int OS_Read(int fd, char * buf, size_t len)
{
+ if (shutdownNow) return -1;
return(read(fd, buf, len));
}
-\f
+
/*
*--------------------------------------------------------------
*
*/
int OS_Write(int fd, char * buf, size_t len)
{
+ if (shutdownNow) return -1;
return(write(fd, buf, len));
}
-\f
/*
*----------------------------------------------------------------------
*
return 0;
}
-\f
/*
*--------------------------------------------------------------
*
*
*--------------------------------------------------------------
*/
-int OS_AsyncReadStdin(void *buf, int len, OS_AsyncProc procPtr,
+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;
static void GrowAsyncTable(void)
{
int oldTableSize = asyncIoTableSize;
-
+
asyncIoTableSize = asyncIoTableSize * 2;
- asyncIoTable = realloc(asyncIoTable, asyncIoTableSize * sizeof(AioInfo));
+ asyncIoTable = (AioInfo *)realloc(asyncIoTable, asyncIoTableSize * sizeof(AioInfo));
if(asyncIoTable == NULL) {
errno = ENOMEM;
exit(errno);
}
-\f
/*
*--------------------------------------------------------------
*
OS_AsyncProc procPtr, ClientData clientData)
{
int index = AIO_RD_IX(fd);
-
+
ASSERT(asyncIoTable != NULL);
+ asyncIoInUse = TRUE;
if(fd > maxFd)
maxFd = fd;
- if(index >= asyncIoTableSize) {
+ while (index >= asyncIoTableSize) {
GrowAsyncTable();
}
FD_SET(fd, &readFdSet);
return 0;
}
-\f
+
/*
*--------------------------------------------------------------
*
*
*--------------------------------------------------------------
*/
-int OS_AsyncWrite(int fd, int offset, void *buf, int len,
+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;
- if(index >= asyncIoTableSize) {
+ while (index >= asyncIoTableSize) {
GrowAsyncTable();
}
FD_SET(fd, &writeFdSet);
return 0;
}
-\f
+
/*
*--------------------------------------------------------------
*
*
*--------------------------------------------------------------
*/
-int OS_Close(int fd)
+int OS_Close(int fd, int shutdown_ok)
{
- int index = AIO_RD_IX(fd);
-
- FD_CLR(fd, &readFdSet);
- FD_CLR(fd, &readFdSetPost);
- if(asyncIoTable[index].inUse != 0) {
- asyncIoTable[index].inUse = 0;
+ 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--;
+ }
}
-
- FD_CLR(fd, &writeFdSet);
- FD_CLR(fd, &writeFdSetPost);
- index = AIO_WR_IX(fd);
- if(asyncIoTable[index].inUse != 0) {
- asyncIoTable[index].inUse = 0;
+
+ /*
+ * 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);
+ }
}
- if(maxFd == fd)
- maxFd--;
+
return close(fd);
}
-\f
+
/*
*--------------------------------------------------------------
*
asyncIoTable[AIO_RD_IX(fd)].inUse = 0;
FD_CLR(fd, &readFdSet);
}
-
+
return shutdown(fd, 0);
}
-\f
/*
*--------------------------------------------------------------
*
fd_set readFdSetCpy;
fd_set writeFdSetCpy;
+ asyncIoInUse = TRUE;
FD_ZERO(&readFdSetCpy);
FD_ZERO(&writeFdSetCpy);
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)
return 0;
-
+
for(fd = 0; fd <= maxFd; fd++) {
/*
* Do reads and dispatch callback.
*/
- if(FD_ISSET(fd, &readFdSetPost)
+ 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;
numWrPosted--;
FD_CLR(fd, &writeFdSetPost);
aioPtr = &asyncIoTable[AIO_WR_IX(fd)];
-
+
len = write(aioPtr->fd, aioPtr->buf, aioPtr->len);
procPtr = aioPtr->procPtr;
return 0;
}
-\f
+/*
+ * 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;
+}
+
/*
*----------------------------------------------------------------------
*
*
*----------------------------------------------------------------------
*/
-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;
- char *newString = NULL;
- int strLen;
- if(clientList == NULL || *clientList == '\0') {
+ if (clientList == NULL || *clientList == '\0') {
return TRUE;
}
- strLen = strlen(clientList);
- clientListCopy = malloc(strLen + 1);
- assert(newString != NULL);
- memcpy(newString, clientList, strLen);
- newString[strLen] = '\000';
-
- for(cur = clientListCopy; cur != NULL; cur = next) {
+ clientListCopy = str_dup(clientList);
+
+ for (cur = clientListCopy; cur != NULL; cur = next) {
next = strchr(cur, ',');
- if(next != NULL) {
+ if (next != NULL) {
*next++ = '\0';
- }
- if(inet_addr(cur) == saPtr->sin_addr.s_addr) {
+ }
+ if (inet_addr(cur) == saPtr->sin_addr.s_addr) {
result = TRUE;
break;
}
}
+
free(clientListCopy);
return result;
}
-\f
/*
*----------------------------------------------------------------------
*
*
*----------------------------------------------------------------------
*/
-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
+ && ! shutdownPending);
+
+ 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(FCGI_LISTENSOCK_FILENO, F_SETLK, &lock) < 0) {
- return -1;
- }
-#endif /* USE_LOCKING */
+ 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);
}
-\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 *webServerAddrs)
{
- int socket;
- union u_sockaddr {
+ int socket = -1;
+ union {
struct sockaddr_un un;
struct sockaddr_in in;
} sa;
- int clilen;
-
- if (AcquireLock(TRUE) < 0) {
- return (-1);
- }
+
for (;;) {
- do {
- clilen = sizeof(sa);
- socket = accept(FCGI_LISTENSOCK_FILENO,
- (struct sockaddr *) &sa.un,
- &clilen);
- } while ((socket < 0) && (errno == EINTR));
-
- if (socket >= 0) {
- /*
- * If the new connection uses TCP/IP, check the client IP address;
- * if the address isn't valid, close the connection and
- * try again.
- */
- if ((sa.in.sin_family == AF_INET)
- && (!ClientAddrOK(&sa.in, clientAddrList))) {
- close(socket);
- continue;
- }
- break;
- }
+ if (AcquireLock(listen_sock, fail_on_intr))
+ return -1;
- /* Based on Apache's (v1.3.1) http_main.c accept() handling and
- * Stevens' Unix Network Programming Vol 1, 2nd Ed, para. 15.6
- */
- switch (errno) {
-#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:
+ for (;;) {
+ do {
+#ifdef HAVE_SOCKLEN
+ socklen_t len = sizeof(sa);
+#else
+ int len = sizeof(sa);
#endif
-#ifdef ETIMEDOUT
- case ETIMEDOUT:
-#endif
-#ifdef EHOSTUNREACH
- case EHOSTUNREACH:
-#endif
-#ifdef ENETUNREACH
- case ENETUNREACH:
-#endif
- break; /* switch(errno) */
+ if (shutdownPending) break;
+ /* There's a window here */
- default: {
+ 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();
- errno = errnoSave;
+
+ ReleaseLock(listen_sock);
+
+ if (! shutdownPending) {
+ errno = errnoSave;
+ }
+
+ return (-1);
}
- return (-1);
- } /* switch(errno) */
- } /* for(;;) */
+ 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 */
- if (ReleaseLock() < 0) {
- return (-1);
- }
return (socket);
}
-\f
+
/*
*----------------------------------------------------------------------
*
*
*----------------------------------------------------------------------
*/
-int OS_IpcClose(int ipcFd)
+int OS_IpcClose(int ipcFd, int shutdown)
{
- return OS_Close(ipcFd);
+ return OS_Close(ipcFd, shutdown);
}
-\f
/*
*----------------------------------------------------------------------
*
*
*----------------------------------------------------------------------
*/
-int OS_IsFcgi()
+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(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
+
/*
*----------------------------------------------------------------------
*