*/
#ifndef lint
-static const char rcsid[] = "$Id: os_unix.c,v 1.20 2000/09/20 15:45:29 robs Exp $";
+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 <string.h>
#include <sys/time.h>
#include <sys/un.h>
+#include <signal.h>
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
#include "fastcgi.h"
-#include "fcgiapp.h"
-#include "fcgiappmisc.h"
#include "fcgimisc.h"
#include "fcgios.h"
-#ifndef FALSE
-#define FALSE 0
-#endif
-
-#ifndef TRUE
-#define TRUE 1
+#ifndef INADDR_NONE
+#define INADDR_NONE ((unsigned long) -1)
#endif
/*
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);
+}
+
/*
*--------------------------------------------------------------
*
FD_ZERO(&writeFdSet);
FD_ZERO(&readFdSetPost);
FD_ZERO(&writeFdSetPost);
+
+ OS_InstallSignalHandlers(TRUE);
+
libInitialized = TRUE;
+
return 0;
}
-\f
/*
*--------------------------------------------------------------
*
return;
}
-\f
/*
*----------------------------------------------------------------------
*
#endif
return 0;
}
-\f
union SockAddrUnion {
struct sockaddr_un unixVariant;
struct sockaddr_in inetVariant;
};
-\f
/*
* OS_CreateLocalIpcFd --
*
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];
strcpy(host, bindPath);
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 {
return listenSock;
}
-\f
/*
*----------------------------------------------------------------------
*
int connectStatus;
char *tp;
char host[MAXPATHLEN];
- short port;
+ short port = 0;
int tcp = FALSE;
strcpy(host, bindPath);
}
}
-\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
/*
*--------------------------------------------------------------
*
}
-\f
/*
*--------------------------------------------------------------
*
if(fd > maxFd)
maxFd = fd;
- if(index >= asyncIoTableSize) {
+ while (index >= asyncIoTableSize) {
GrowAsyncTable();
}
FD_SET(fd, &readFdSet);
return 0;
}
-\f
+
/*
*--------------------------------------------------------------
*
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)
{
+ if (fd == -1)
+ return 0;
+
if (asyncIoInUse) {
int index = AIO_RD_IX(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);
}
-\f
+
/*
*--------------------------------------------------------------
*
return shutdown(fd, 0);
}
-\f
/*
*--------------------------------------------------------------
*
* Not all systems have strdup().
* @@@ autoconf should determine whether or not this is needed, but for now..
*/
-char * str_dup(const char * str)
+static char * str_dup(const char * str)
{
char * sdup = (char *) malloc(strlen(str) + 1);
return sdup;
}
-\f
/*
*----------------------------------------------------------------------
*
return result;
}
-\f
/*
*----------------------------------------------------------------------
*
if (fcntl(sock, F_SETLKW, &lock) != -1)
return 0;
- } while (errno == EINTR && !fail_on_intr);
+ } while (errno == EINTR
+ && ! fail_on_intr
+ && ! shutdownPending);
return -1;
return 0;
#endif
}
-\f
+
/*
*----------------------------------------------------------------------
*
#endif
}
-\f
/**********************************************************************
* Determine if the errno resulting from a failed accept() warrants a
* retry or exit(). Based on Apache's http_main.c accept() handling
*/
int OS_Accept(int listen_sock, int fail_on_intr, const char *webServerAddrs)
{
- int socket;
+ int socket = -1;
union {
struct sockaddr_un un;
struct sockaddr_in in;
#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);
+ } while (socket < 0
+ && errno == EINTR
+ && ! fail_on_intr
+ && ! shutdownPending);
if (socket < 0) {
- if (!is_reasonable_accept_errno(errno)) {
+ if (shutdownPending || ! is_reasonable_accept_errno(errno)) {
int errnoSave = errno;
+
ReleaseLock(listen_sock);
- errno = errnoSave;
+
+ if (! shutdownPending) {
+ errno = errnoSave;
+ }
+
return (-1);
}
errno = 0;
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 len = sizeof(sa);
#endif
+ errno = 0;
+
if (getpeername(sock, (struct sockaddr *)&sa, &len) != 0 && errno == ENOTCONN) {
return TRUE;
}
return FALSE;
}
}
-\f
+
/*
*----------------------------------------------------------------------
*