Home | History | Annotate | Line # | Download | only in httpd
daemon-bozo.c revision 1.8
      1  1.8       mrg /*	$NetBSD: daemon-bozo.c,v 1.8 2010/05/10 03:37:45 mrg Exp $	*/
      2  1.2       tls 
      3  1.8       mrg /*	$eterna: daemon-bozo.c,v 1.19 2010/05/10 02:51:28 mrg Exp $	*/
      4  1.1       tls 
      5  1.1       tls /*
      6  1.8       mrg  * Copyright (c) 1997-2010 Matthew R. Green
      7  1.1       tls  * All rights reserved.
      8  1.1       tls  *
      9  1.1       tls  * Redistribution and use in source and binary forms, with or without
     10  1.1       tls  * modification, are permitted provided that the following conditions
     11  1.1       tls  * are met:
     12  1.1       tls  * 1. Redistributions of source code must retain the above copyright
     13  1.1       tls  *    notice, this list of conditions and the following disclaimer.
     14  1.1       tls  * 2. Redistributions in binary form must reproduce the above copyright
     15  1.1       tls  *    notice, this list of conditions and the following disclaimer and
     16  1.1       tls  *    dedication in the documentation and/or other materials provided
     17  1.1       tls  *    with the distribution.
     18  1.1       tls  *
     19  1.1       tls  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     20  1.1       tls  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     21  1.1       tls  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     22  1.1       tls  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     23  1.1       tls  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     24  1.1       tls  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     25  1.1       tls  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     26  1.1       tls  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     27  1.1       tls  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  1.1       tls  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  1.1       tls  * SUCH DAMAGE.
     30  1.1       tls  *
     31  1.1       tls  */
     32  1.1       tls 
     33  1.1       tls /* this code implements daemon mode for bozohttpd */
     34  1.1       tls 
     35  1.1       tls #ifndef NO_DAEMON_MODE
     36  1.1       tls 
     37  1.1       tls #include <sys/param.h>
     38  1.1       tls #include <sys/socket.h>
     39  1.1       tls #include <sys/wait.h>
     40  1.1       tls 
     41  1.1       tls #include <netinet/in.h>
     42  1.1       tls 
     43  1.1       tls #include <errno.h>
     44  1.1       tls #include <netdb.h>
     45  1.1       tls #include <poll.h>
     46  1.1       tls #include <stdlib.h>
     47  1.1       tls #include <string.h>
     48  1.1       tls #include <unistd.h>
     49  1.1       tls 
     50  1.1       tls #include "bozohttpd.h"
     51  1.1       tls 
     52  1.1       tls static	void	sigchild(int);	/* SIGCHLD handler */
     53  1.1       tls 
     54  1.7       mrg #ifndef POLLRDNORM
     55  1.7       mrg #define POLLRDNORM 0
     56  1.7       mrg #endif
     57  1.7       mrg #ifndef POLLRDBAND
     58  1.7       mrg #define POLLRDBAND 0
     59  1.7       mrg #endif
     60  1.7       mrg #ifndef INFTIM
     61  1.7       mrg #define INFTIM -1
     62  1.7       mrg #endif
     63  1.7       mrg 
     64  1.1       tls /* ARGSUSED */
     65  1.1       tls static void
     66  1.8       mrg sigchild(int signo)
     67  1.1       tls {
     68  1.8       mrg 	while (waitpid(-1, NULL, WNOHANG) > 0) {
     69  1.8       mrg 	}
     70  1.1       tls }
     71  1.1       tls 
     72  1.1       tls void
     73  1.8       mrg bozo_daemon_init(bozohttpd_t *httpd)
     74  1.1       tls {
     75  1.1       tls 	struct addrinfo h, *r, *r0;
     76  1.8       mrg 	const char	*portnum;
     77  1.1       tls 	int e, i, on = 1;
     78  1.1       tls 
     79  1.8       mrg 	if (!httpd->background)
     80  1.1       tls 		return;
     81  1.1       tls 
     82  1.8       mrg 	if (httpd->foreground == 0)
     83  1.1       tls 		daemon(1, 0);
     84  1.1       tls 
     85  1.8       mrg 	portnum = (httpd->bindport) ? httpd->bindport : "http";
     86  1.8       mrg 	bozo_warn(httpd, "started in daemon mode as `%s' port `%s' root `%s'",
     87  1.8       mrg 	    httpd->virthostname, portnum, httpd->slashdir);
     88  1.1       tls 
     89  1.8       mrg 	memset(&h, 0, sizeof(h));
     90  1.1       tls 	h.ai_family = PF_UNSPEC;
     91  1.1       tls 	h.ai_socktype = SOCK_STREAM;
     92  1.1       tls 	h.ai_flags = AI_PASSIVE;
     93  1.8       mrg 	e = getaddrinfo(httpd->bindaddress, portnum, &h, &r0);
     94  1.1       tls 	if (e)
     95  1.8       mrg 		bozo_err(httpd, 1, "getaddrinfo([%s]:%s): %s",
     96  1.8       mrg 		    httpd->bindaddress ? httpd->bindaddress : "*",
     97  1.8       mrg 		    portnum, gai_strerror(e));
     98  1.1       tls 	for (r = r0; r != NULL; r = r->ai_next)
     99  1.8       mrg 		httpd->nsock++;
    100  1.8       mrg 	httpd->sock = bozomalloc(httpd, httpd->nsock * sizeof(*httpd->sock));
    101  1.8       mrg 	httpd->fds = bozomalloc(httpd, httpd->nsock * sizeof(*httpd->fds));
    102  1.1       tls 	for (i = 0, r = r0; r != NULL; r = r->ai_next) {
    103  1.8       mrg 		httpd->sock[i] = socket(r->ai_family, SOCK_STREAM, 0);
    104  1.8       mrg 		if (httpd->sock[i] == -1)
    105  1.1       tls 			continue;
    106  1.8       mrg 		if (setsockopt(httpd->sock[i], SOL_SOCKET, SO_REUSEADDR, &on,
    107  1.1       tls 		    sizeof(on)) == -1)
    108  1.8       mrg 			bozo_warn(httpd, "setsockopt SO_REUSEADDR: %s",
    109  1.1       tls 			    strerror(errno));
    110  1.8       mrg 		if (bind(httpd->sock[i], r->ai_addr, r->ai_addrlen) == -1)
    111  1.1       tls 			continue;
    112  1.8       mrg 		if (listen(httpd->sock[i], SOMAXCONN) == -1)
    113  1.1       tls 			continue;
    114  1.8       mrg 		httpd->fds[i].events = POLLIN | POLLPRI | POLLRDNORM |
    115  1.7       mrg 				POLLRDBAND | POLLERR;
    116  1.8       mrg 		httpd->fds[i].fd = httpd->sock[i];
    117  1.1       tls 		i++;
    118  1.1       tls 	}
    119  1.1       tls 	if (i == 0)
    120  1.8       mrg 		bozo_err(httpd, 1, "could not find any addresses to bind");
    121  1.8       mrg 	httpd->nsock = i;
    122  1.1       tls 	freeaddrinfo(r0);
    123  1.1       tls 
    124  1.1       tls 	signal(SIGCHLD, sigchild);
    125  1.1       tls }
    126  1.1       tls 
    127  1.7       mrg void
    128  1.8       mrg bozo_daemon_closefds(bozohttpd_t *httpd)
    129  1.7       mrg {
    130  1.7       mrg 	int i;
    131  1.7       mrg 
    132  1.8       mrg 	for (i = 0; i < httpd->nsock; i++)
    133  1.8       mrg 		close(httpd->sock[i]);
    134  1.7       mrg }
    135  1.7       mrg 
    136  1.7       mrg static void
    137  1.8       mrg daemon_runchild(bozohttpd_t *httpd, int fd)
    138  1.7       mrg {
    139  1.7       mrg 
    140  1.8       mrg 	httpd->request_times++;
    141  1.7       mrg 
    142  1.7       mrg 	/* setup stdin/stdout/stderr */
    143  1.7       mrg 	dup2(fd, 0);
    144  1.7       mrg 	dup2(fd, 1);
    145  1.7       mrg 	/*dup2(fd, 2);*/
    146  1.7       mrg 	close(fd);
    147  1.7       mrg }
    148  1.7       mrg 
    149  1.1       tls /*
    150  1.1       tls  * the parent never returns from this function, only children that
    151  1.5       mrg  * are ready to run... XXXMRG - still true in fork-lesser bozo?
    152  1.1       tls  */
    153  1.1       tls void
    154  1.8       mrg bozo_daemon_fork(bozohttpd_t *httpd)
    155  1.1       tls {
    156  1.7       mrg 	int i;
    157  1.1       tls 
    158  1.8       mrg 	debug((httpd, DEBUG_FAT, "%s: pid %u request_times %d",
    159  1.8       mrg 		__func__, getpid(),
    160  1.8       mrg 		httpd->request_times));
    161  1.7       mrg 	/* if we've handled 5 files, exit and let someone else work */
    162  1.8       mrg 	if (httpd->request_times > 5 ||
    163  1.8       mrg 	    (httpd->background == 2 && httpd->request_times > 0))
    164  1.7       mrg 		exit(0);
    165  1.6       mrg 
    166  1.8       mrg 	while (httpd->background) {
    167  1.6       mrg 		struct	sockaddr_storage ss;
    168  1.6       mrg 		socklen_t slen;
    169  1.6       mrg 		int fd;
    170  1.6       mrg 
    171  1.8       mrg 		if (httpd->nsock == 0)
    172  1.6       mrg 			exit(0);
    173  1.1       tls 
    174  1.1       tls 		/*
    175  1.1       tls 		 * wait for a connection, then fork() and return NULL in
    176  1.1       tls 		 * the parent, who will come back here waiting for another
    177  1.1       tls 		 * connection.  read the request in in the child, and return
    178  1.1       tls 		 * it, for processing.
    179  1.1       tls 		 */
    180  1.1       tls again:
    181  1.8       mrg 		if (poll(httpd->fds, (unsigned)httpd->nsock, INFTIM) == -1) {
    182  1.6       mrg 			/* fail on programmer errors */
    183  1.6       mrg 			if (errno == EFAULT ||
    184  1.6       mrg 			    errno == EINVAL)
    185  1.8       mrg 				bozo_err(httpd, 1, "poll: %s",
    186  1.8       mrg 					strerror(errno));
    187  1.6       mrg 
    188  1.6       mrg 			/* sleep on some temporary kernel failures */
    189  1.6       mrg 			if (errno == ENOMEM ||
    190  1.6       mrg 			    errno == EAGAIN)
    191  1.6       mrg 				sleep(1);
    192  1.6       mrg 
    193  1.1       tls 			goto again;
    194  1.1       tls 		}
    195  1.1       tls 
    196  1.8       mrg 		for (i = 0; i < httpd->nsock; i++) {
    197  1.8       mrg 			if (httpd->fds[i].revents & (POLLNVAL|POLLERR|POLLHUP)) {
    198  1.8       mrg 				bozo_warn(httpd,
    199  1.8       mrg 					"poll on fd %d pid %d revents %d: %s",
    200  1.8       mrg 					httpd->fds[i].fd, getpid(),
    201  1.8       mrg 					httpd->fds[i].revents,
    202  1.8       mrg 					strerror(errno));
    203  1.8       mrg 				bozo_warn(httpd, "nsock = %d", httpd->nsock);
    204  1.8       mrg 				close(httpd->sock[i]);
    205  1.8       mrg 				httpd->nsock--;
    206  1.8       mrg 				bozo_warn(httpd, "nsock now = %d", httpd->nsock);
    207  1.6       mrg 				/* no sockets left */
    208  1.8       mrg 				if (httpd->nsock == 0)
    209  1.6       mrg 					exit(0);
    210  1.6       mrg 				/* last socket; easy case */
    211  1.8       mrg 				if (httpd->nsock == i)
    212  1.6       mrg 					break;
    213  1.8       mrg 				memmove(&httpd->fds[i], &httpd->fds[i+i],
    214  1.8       mrg 					(httpd->nsock - i) *
    215  1.8       mrg 						sizeof(*httpd->fds));
    216  1.8       mrg 				memmove(&httpd->sock[i], &httpd->sock[i+i],
    217  1.8       mrg 					(httpd->nsock - i) *
    218  1.8       mrg 						sizeof(*httpd->sock));
    219  1.6       mrg 				break;
    220  1.1       tls 			}
    221  1.8       mrg 			if (httpd->fds[i].revents == 0)
    222  1.1       tls 				continue;
    223  1.1       tls 
    224  1.4  degroote 			slen = sizeof(ss);
    225  1.8       mrg 			fd = accept(httpd->fds[i].fd,
    226  1.8       mrg 					(struct sockaddr *)(void *)&ss, &slen);
    227  1.1       tls 			if (fd == -1) {
    228  1.6       mrg 				if (errno == EFAULT ||
    229  1.6       mrg 				    errno == EINVAL)
    230  1.8       mrg 					bozo_err(httpd, 1, "accept: %s",
    231  1.8       mrg 						strerror(errno));
    232  1.6       mrg 
    233  1.6       mrg 				if (errno == ENOMEM ||
    234  1.6       mrg 				    errno == EAGAIN)
    235  1.6       mrg 					sleep(1);
    236  1.6       mrg 
    237  1.1       tls 				continue;
    238  1.1       tls 			}
    239  1.7       mrg 
    240  1.8       mrg 			if (httpd->request_times > 0) {
    241  1.8       mrg 				daemon_runchild(httpd, fd);
    242  1.7       mrg 				return;
    243  1.7       mrg 			}
    244  1.7       mrg 
    245  1.1       tls 			switch (fork()) {
    246  1.1       tls 			case -1: /* eep, failure */
    247  1.8       mrg 				bozo_warn(httpd, "fork() failed, sleeping for "
    248  1.7       mrg 					"10 seconds: %s", strerror(errno));
    249  1.1       tls 				close(fd);
    250  1.1       tls 				sleep(10);
    251  1.7       mrg 				break;
    252  1.1       tls 
    253  1.1       tls 			case 0: /* child */
    254  1.8       mrg 				daemon_runchild(httpd, fd);
    255  1.1       tls 				return;
    256  1.1       tls 
    257  1.1       tls 			default: /* parent */
    258  1.1       tls 				close(fd);
    259  1.7       mrg 				break;
    260  1.1       tls 			}
    261  1.1       tls 		}
    262  1.1       tls 	}
    263  1.1       tls }
    264  1.1       tls 
    265  1.1       tls #endif /* NO_DAEMON_MODE */
    266