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