Home | History | Annotate | Line # | Download | only in httpd
daemon-bozo.c revision 1.7
      1  1.7       mrg /*	$NetBSD: daemon-bozo.c,v 1.7 2009/05/23 02:26:03 mrg Exp $	*/
      2  1.2       tls 
      3  1.7       mrg /*	$eterna: daemon-bozo.c,v 1.17 2009/05/22 21:51:38 mrg Exp $	*/
      4  1.1       tls 
      5  1.1       tls /*
      6  1.5       mrg  * Copyright (c) 1997-2009 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 	char	*iflag;		/* bind address; default INADDR_ANY */
     53  1.1       tls static	int	*sock;		/* bound sockets */
     54  1.1       tls static	int	nsock;		/* number of above */
     55  1.7       mrg static	struct pollfd *fds;	/* current poll fd set */
     56  1.7       mrg static	int	request_times;	/* how many times this proc has processed
     57  1.7       mrg 				   a request */
     58  1.1       tls 
     59  1.7       mrg static	void	daemon_runchild(int);
     60  1.1       tls static	void	sigchild(int);	/* SIGCHLD handler */
     61  1.1       tls 
     62  1.7       mrg #ifndef POLLRDNORM
     63  1.7       mrg #define POLLRDNORM 0
     64  1.7       mrg #endif
     65  1.7       mrg #ifndef POLLRDBAND
     66  1.7       mrg #define POLLRDBAND 0
     67  1.7       mrg #endif
     68  1.7       mrg #ifndef INFTIM
     69  1.7       mrg #define INFTIM -1
     70  1.7       mrg #endif
     71  1.7       mrg 
     72  1.1       tls /* ARGSUSED */
     73  1.1       tls static void
     74  1.1       tls sigchild(signo)
     75  1.1       tls 	int signo;
     76  1.1       tls {
     77  1.1       tls 	while (waitpid(-1, NULL, WNOHANG) > 0)
     78  1.1       tls 		;
     79  1.1       tls }
     80  1.1       tls 
     81  1.1       tls void
     82  1.1       tls daemon_init()
     83  1.1       tls {
     84  1.1       tls 	struct addrinfo h, *r, *r0;
     85  1.1       tls 	int e, i, on = 1;
     86  1.1       tls 
     87  1.1       tls 	if (!bflag)
     88  1.1       tls 		return;
     89  1.1       tls 
     90  1.1       tls 	if (fflag == 0)
     91  1.1       tls 		daemon(1, 0);
     92  1.1       tls 
     93  1.1       tls 	warning("started in daemon mode as `%s' port `%s' root `%s'",
     94  1.1       tls 	    myname, Iflag, slashdir);
     95  1.1       tls 
     96  1.1       tls 	memset(&h, 0, sizeof h);
     97  1.1       tls 	h.ai_family = PF_UNSPEC;
     98  1.1       tls 	h.ai_socktype = SOCK_STREAM;
     99  1.1       tls 	h.ai_flags = AI_PASSIVE;
    100  1.1       tls 	e = getaddrinfo(iflag, Iflag, &h, &r0);
    101  1.1       tls 	if (e)
    102  1.1       tls 		error(1, "getaddrinfo([%s]:%s): %s",
    103  1.1       tls 		    iflag ? iflag : "*", Iflag, gai_strerror(e));
    104  1.1       tls 	for (r = r0; r != NULL; r = r->ai_next)
    105  1.1       tls 		nsock++;
    106  1.1       tls 	sock = bozomalloc(nsock * sizeof *sock);
    107  1.7       mrg 	fds = bozomalloc(nsock * sizeof *fds);
    108  1.1       tls 	for (i = 0, r = r0; r != NULL; r = r->ai_next) {
    109  1.1       tls 		sock[i] = socket(r->ai_family, SOCK_STREAM, 0);
    110  1.1       tls 		if (sock[i] == -1)
    111  1.1       tls 			continue;
    112  1.1       tls 		if (setsockopt(sock[i], SOL_SOCKET, SO_REUSEADDR, &on,
    113  1.1       tls 		    sizeof(on)) == -1)
    114  1.1       tls 			warning("setsockopt SO_REUSEADDR: %s",
    115  1.1       tls 			    strerror(errno));
    116  1.1       tls 		if (bind(sock[i], r->ai_addr, r->ai_addrlen) == -1)
    117  1.1       tls 			continue;
    118  1.1       tls 		if (listen(sock[i], SOMAXCONN) == -1)
    119  1.1       tls 			continue;
    120  1.7       mrg 		fds[i].events = POLLIN | POLLPRI | POLLRDNORM |
    121  1.7       mrg 				POLLRDBAND | POLLERR;
    122  1.7       mrg 		fds[i].fd = sock[i];
    123  1.1       tls 		i++;
    124  1.1       tls 	}
    125  1.1       tls 	if (i == 0)
    126  1.1       tls 		error(1, "could not find any addresses to bind");
    127  1.1       tls 	nsock = i;
    128  1.1       tls 	freeaddrinfo(r0);
    129  1.1       tls 
    130  1.1       tls 	signal(SIGCHLD, sigchild);
    131  1.1       tls }
    132  1.1       tls 
    133  1.7       mrg void
    134  1.7       mrg daemon_closefds(void)
    135  1.7       mrg {
    136  1.7       mrg 	int i;
    137  1.7       mrg 
    138  1.7       mrg 	for (i = 0; i < nsock; i++)
    139  1.7       mrg 		close(sock[i]);
    140  1.7       mrg }
    141  1.7       mrg 
    142  1.7       mrg static void
    143  1.7       mrg daemon_runchild(int fd)
    144  1.7       mrg {
    145  1.7       mrg 
    146  1.7       mrg 	request_times++;
    147  1.7       mrg 
    148  1.7       mrg 	/* setup stdin/stdout/stderr */
    149  1.7       mrg 	dup2(fd, 0);
    150  1.7       mrg 	dup2(fd, 1);
    151  1.7       mrg 	/*dup2(fd, 2);*/
    152  1.7       mrg 	close(fd);
    153  1.7       mrg }
    154  1.7       mrg 
    155  1.1       tls /*
    156  1.1       tls  * the parent never returns from this function, only children that
    157  1.5       mrg  * are ready to run... XXXMRG - still true in fork-lesser bozo?
    158  1.1       tls  */
    159  1.1       tls void
    160  1.1       tls daemon_fork()
    161  1.1       tls {
    162  1.7       mrg 	int i;
    163  1.1       tls 
    164  1.7       mrg 	debug((DEBUG_FAT, "%s: pid %u request_times %d", __func__, getpid(),
    165  1.7       mrg 	       request_times));
    166  1.7       mrg 	/* if we've handled 5 files, exit and let someone else work */
    167  1.7       mrg 	if (request_times > 5 || (bflag == 2 && request_times > 0))
    168  1.7       mrg 		exit(0);
    169  1.6       mrg 
    170  1.6       mrg 	while (bflag) {
    171  1.6       mrg 		struct	sockaddr_storage ss;
    172  1.6       mrg 		socklen_t slen;
    173  1.6       mrg 		int fd;
    174  1.6       mrg 
    175  1.6       mrg 		if (nsock == 0)
    176  1.6       mrg 			exit(0);
    177  1.1       tls 
    178  1.1       tls 		/*
    179  1.1       tls 		 * wait for a connection, then fork() and return NULL in
    180  1.1       tls 		 * the parent, who will come back here waiting for another
    181  1.1       tls 		 * connection.  read the request in in the child, and return
    182  1.1       tls 		 * it, for processing.
    183  1.1       tls 		 */
    184  1.1       tls again:
    185  1.1       tls 		if (poll(fds, nsock, INFTIM) == -1) {
    186  1.6       mrg 			/* fail on programmer errors */
    187  1.6       mrg 			if (errno == EFAULT ||
    188  1.6       mrg 			    errno == EINVAL)
    189  1.1       tls 				error(1, "poll: %s", strerror(errno));
    190  1.6       mrg 
    191  1.6       mrg 			/* sleep on some temporary kernel failures */
    192  1.6       mrg 			if (errno == ENOMEM ||
    193  1.6       mrg 			    errno == EAGAIN)
    194  1.6       mrg 				sleep(1);
    195  1.6       mrg 
    196  1.1       tls 			goto again;
    197  1.1       tls 		}
    198  1.1       tls 
    199  1.1       tls 		for (i = 0; i < nsock; i++) {
    200  1.1       tls 			if (fds[i].revents & (POLLNVAL|POLLERR|POLLHUP)) {
    201  1.6       mrg 				warning("poll on fd %d pid %d revents %d: %s",
    202  1.7       mrg 				    fds[i].fd, getpid(), fds[i].revents,
    203  1.7       mrg 				    strerror(errno));
    204  1.6       mrg 				warning("nsock = %d", nsock);
    205  1.6       mrg 				close(sock[i]);
    206  1.6       mrg 				nsock--;
    207  1.6       mrg 				warning("nsock now = %d", nsock);
    208  1.6       mrg 				/* no sockets left */
    209  1.6       mrg 				if (nsock == 0)
    210  1.6       mrg 					exit(0);
    211  1.6       mrg 				/* last socket; easy case */
    212  1.6       mrg 				if (nsock == i)
    213  1.6       mrg 					break;
    214  1.6       mrg 				memmove(&fds[i], &fds[i+i],
    215  1.6       mrg 					(nsock - i) * sizeof(*fds));
    216  1.6       mrg 				memmove(&sock[i], &sock[i+i],
    217  1.6       mrg 					(nsock - i) * sizeof(*sock));
    218  1.6       mrg 				break;
    219  1.1       tls 			}
    220  1.1       tls 			if (fds[i].revents == 0)
    221  1.1       tls 				continue;
    222  1.1       tls 
    223  1.4  degroote 			slen = sizeof(ss);
    224  1.6       mrg 			fd = accept(fds[i].fd, (struct sockaddr *)&ss, &slen);
    225  1.1       tls 			if (fd == -1) {
    226  1.6       mrg 				if (errno == EFAULT ||
    227  1.6       mrg 				    errno == EINVAL)
    228  1.1       tls 					error(1, "accept: %s", strerror(errno));
    229  1.6       mrg 
    230  1.6       mrg 				if (errno == ENOMEM ||
    231  1.6       mrg 				    errno == EAGAIN)
    232  1.6       mrg 					sleep(1);
    233  1.6       mrg 
    234  1.1       tls 				continue;
    235  1.1       tls 			}
    236  1.7       mrg 
    237  1.7       mrg 			if (request_times > 0) {
    238  1.7       mrg 				daemon_runchild(fd);
    239  1.7       mrg 				return;
    240  1.7       mrg 			}
    241  1.7       mrg 
    242  1.1       tls 			switch (fork()) {
    243  1.1       tls 			case -1: /* eep, failure */
    244  1.7       mrg 				warning("fork() failed, sleeping for "
    245  1.7       mrg 					"10 seconds: %s", strerror(errno));
    246  1.1       tls 				close(fd);
    247  1.1       tls 				sleep(10);
    248  1.7       mrg 				break;
    249  1.1       tls 
    250  1.1       tls 			case 0: /* child */
    251  1.7       mrg 				daemon_runchild(fd);
    252  1.1       tls 				return;
    253  1.1       tls 
    254  1.1       tls 			default: /* parent */
    255  1.1       tls 				close(fd);
    256  1.7       mrg 				break;
    257  1.1       tls 			}
    258  1.1       tls 		}
    259  1.1       tls 	}
    260  1.1       tls }
    261  1.1       tls 
    262  1.1       tls #endif /* NO_DAEMON_MODE */
    263