Home | History | Annotate | Line # | Download | only in httpd
daemon-bozo.c revision 1.2
      1 /*	$NetBSD: daemon-bozo.c,v 1.2 2007/10/17 18:48:01 tls Exp $	*/
      2 
      3 /*	$eterna: daemon-bozo.c,v 1.8 2006/05/17 08:22:03 mrg Exp $	*/
      4 
      5 /*
      6  * Copyright (c) 1997-2006 Matthew R. Green
      7  * All rights reserved.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer and
     16  *    dedication in the documentation and/or other materials provided
     17  *    with the distribution.
     18  * 3. The name of the author may not be used to endorse or promote products
     19  *    derived from this software without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     28  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     29  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     31  * SUCH DAMAGE.
     32  *
     33  */
     34 
     35 /* this code implements daemon mode for bozohttpd */
     36 
     37 #ifndef NO_DAEMON_MODE
     38 
     39 #include <sys/param.h>
     40 #include <sys/socket.h>
     41 #include <sys/wait.h>
     42 
     43 #include <netinet/in.h>
     44 
     45 #include <errno.h>
     46 #include <netdb.h>
     47 #include <poll.h>
     48 #include <stdlib.h>
     49 #include <string.h>
     50 #include <unistd.h>
     51 
     52 #include "bozohttpd.h"
     53 
     54 	char	*iflag;		/* bind address; default INADDR_ANY */
     55 static	int	*sock;		/* bound sockets */
     56 static	int	nsock;		/* number of above */
     57 
     58 static	void	sigchild(int);	/* SIGCHLD handler */
     59 
     60 /* ARGSUSED */
     61 static void
     62 sigchild(signo)
     63 	int signo;
     64 {
     65 	while (waitpid(-1, NULL, WNOHANG) > 0)
     66 		;
     67 }
     68 
     69 void
     70 daemon_init()
     71 {
     72 	struct addrinfo h, *r, *r0;
     73 	int e, i, on = 1;
     74 
     75 	if (!bflag)
     76 		return;
     77 
     78 	if (fflag == 0)
     79 		daemon(1, 0);
     80 
     81 	warning("started in daemon mode as `%s' port `%s' root `%s'",
     82 	    myname, Iflag, slashdir);
     83 
     84 	memset(&h, 0, sizeof h);
     85 	h.ai_family = PF_UNSPEC;
     86 	h.ai_socktype = SOCK_STREAM;
     87 	h.ai_flags = AI_PASSIVE;
     88 	e = getaddrinfo(iflag, Iflag, &h, &r0);
     89 	if (e)
     90 		error(1, "getaddrinfo([%s]:%s): %s",
     91 		    iflag ? iflag : "*", Iflag, gai_strerror(e));
     92 	for (r = r0; r != NULL; r = r->ai_next)
     93 		nsock++;
     94 	sock = bozomalloc(nsock * sizeof *sock);
     95 	for (i = 0, r = r0; r != NULL; r = r->ai_next) {
     96 		sock[i] = socket(r->ai_family, SOCK_STREAM, 0);
     97 		if (sock[i] == -1)
     98 			continue;
     99 		if (setsockopt(sock[i], SOL_SOCKET, SO_REUSEADDR, &on,
    100 		    sizeof(on)) == -1)
    101 			warning("setsockopt SO_REUSEADDR: %s",
    102 			    strerror(errno));
    103 		if (bind(sock[i], r->ai_addr, r->ai_addrlen) == -1)
    104 			continue;
    105 		if (listen(sock[i], SOMAXCONN) == -1)
    106 			continue;
    107 		i++;
    108 	}
    109 	if (i == 0)
    110 		error(1, "could not find any addresses to bind");
    111 	nsock = i;
    112 	freeaddrinfo(r0);
    113 
    114 	signal(SIGCHLD, sigchild);
    115 }
    116 
    117 /*
    118  * the parent never returns from this function, only children that
    119  * are ready to run...
    120  */
    121 void
    122 daemon_fork()
    123 {
    124 	struct pollfd *fds = NULL;
    125 
    126 	while (bflag) {
    127 		struct	sockaddr_storage ss;
    128 		socklen_t slen;
    129 		int fd;
    130 		int i;
    131 
    132 #ifndef POLLRDNORM
    133 #define POLLRDNORM 0
    134 #endif
    135 #ifndef POLLRDBAND
    136 #define POLLRDBAND 0
    137 #endif
    138 #ifndef INFTIM
    139 #define INFTIM -1
    140 #endif
    141 		if (fds == NULL) {
    142 			fds = bozomalloc(nsock * sizeof *fds);
    143 			for (i = 0; i < nsock; i++) {
    144 				fds[i].events = POLLIN | POLLPRI | POLLRDNORM |
    145 						POLLRDBAND | POLLERR;
    146 				fds[i].fd = sock[i];
    147 			}
    148 		}
    149 
    150 		/*
    151 		 * wait for a connection, then fork() and return NULL in
    152 		 * the parent, who will come back here waiting for another
    153 		 * connection.  read the request in in the child, and return
    154 		 * it, for processing.
    155 		 */
    156 again:
    157 		if (poll(fds, nsock, INFTIM) == -1) {
    158 			if (errno != EINTR)
    159 				error(1, "poll: %s", strerror(errno));
    160 			goto again;
    161 		}
    162 
    163 		for (i = 0; i < nsock; i++) {
    164 			if (fds[i].revents & (POLLNVAL|POLLERR|POLLHUP)) {
    165 				warning("poll on fd %d: %s", fds[i].fd,
    166 				    strerror(errno));
    167 				continue;
    168 			}
    169 			if (fds[i].revents == 0)
    170 				continue;
    171 
    172 			fd = accept(sock[i], (struct sockaddr *)&ss, &slen);
    173 			if (fd == -1) {
    174 				if (errno != EAGAIN)
    175 					error(1, "accept: %s", strerror(errno));
    176 				continue;
    177 			}
    178 			switch (fork()) {
    179 			case -1: /* eep, failure */
    180 				warning("fork() failed, sleeping for 10 seconds: %s",
    181 				    strerror(errno));
    182 				close(fd);
    183 				sleep(10);
    184 				continue;
    185 
    186 			case 0: /* child */
    187 				/* setup stdin/stdout/stderr */
    188 				dup2(fd, 0);
    189 				dup2(fd, 1);
    190 				/*dup2(fd, 2);*/
    191 				close(fd);
    192 				return;
    193 
    194 			default: /* parent */
    195 				close(fd);
    196 				continue;
    197 			}
    198 		}
    199 	}
    200 }
    201 
    202 #endif /* NO_DAEMON_MODE */
    203