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