xref: /netbsd-src/libexec/httpd/daemon-bozo.c (revision c8da0e5fefd3800856b306200a18b2315c7fbb9f)
1 /*	$NetBSD: daemon-bozo.c,v 1.6 2009/04/18 21:22:03 mrg Exp $	*/
2 
3 /*	$eterna: daemon-bozo.c,v 1.16 2009/04/18 13:06:45 mrg Exp $	*/
4 
5 /*
6  * Copyright (c) 1997-2009 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  *
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... XXXMRG - still true in fork-lesser bozo?
118  */
119 void
120 daemon_fork()
121 {
122 	struct pollfd *fds = NULL;
123 	int i, j;
124 
125 #ifndef POLLRDNORM
126 #define POLLRDNORM 0
127 #endif
128 #ifndef POLLRDBAND
129 #define POLLRDBAND 0
130 #endif
131 #ifndef INFTIM
132 #define INFTIM -1
133 #endif
134 
135 	fds = bozomalloc(nsock * sizeof *fds);
136 	for (i = 0; i < nsock; i++) {
137 		if (sock[i] == -1)
138 			continue;
139 		fds[i].events = POLLIN | POLLPRI | POLLRDNORM |
140 				POLLRDBAND | POLLERR;
141 		fds[i].fd = sock[i];
142 	}
143 
144 	while (bflag) {
145 		struct	sockaddr_storage ss;
146 		socklen_t slen;
147 		int fd;
148 
149 		if (nsock == 0)
150 			exit(0);
151 
152 		/*
153 		 * wait for a connection, then fork() and return NULL in
154 		 * the parent, who will come back here waiting for another
155 		 * connection.  read the request in in the child, and return
156 		 * it, for processing.
157 		 */
158 again:
159 		if (poll(fds, nsock, INFTIM) == -1) {
160 			/* fail on programmer errors */
161 			if (errno == EFAULT ||
162 			    errno == EINVAL)
163 				error(1, "poll: %s", strerror(errno));
164 
165 			/* sleep on some temporary kernel failures */
166 			if (errno == ENOMEM ||
167 			    errno == EAGAIN)
168 				sleep(1);
169 
170 			goto again;
171 		}
172 
173 		for (i = 0; i < nsock; i++) {
174 			if (fds[i].revents & (POLLNVAL|POLLERR|POLLHUP)) {
175 				warning("poll on fd %d pid %d revents %d: %s",
176 				    fds[i].fd, getpid(), fds[i].revents, strerror(errno));
177 				warning("nsock = %d", nsock);
178 				close(sock[i]);
179 				nsock--;
180 				warning("nsock now = %d", nsock);
181 				/* no sockets left */
182 				if (nsock == 0)
183 					exit(0);
184 				/* last socket; easy case */
185 				if (nsock == i)
186 					break;
187 				memmove(&fds[i], &fds[i+i],
188 					(nsock - i) * sizeof(*fds));
189 				memmove(&sock[i], &sock[i+i],
190 					(nsock - i) * sizeof(*sock));
191 				break;
192 			}
193 			if (fds[i].revents == 0)
194 				continue;
195 
196 			slen = sizeof(ss);
197 			fd = accept(fds[i].fd, (struct sockaddr *)&ss, &slen);
198 			if (fd == -1) {
199 				if (errno == EFAULT ||
200 				    errno == EINVAL)
201 					error(1, "accept: %s", strerror(errno));
202 
203 				if (errno == ENOMEM ||
204 				    errno == EAGAIN)
205 					sleep(1);
206 
207 				continue;
208 			}
209 			switch (fork()) {
210 			case -1: /* eep, failure */
211 				warning("fork() failed, sleeping for 10 seconds: %s",
212 				    strerror(errno));
213 				close(fd);
214 				sleep(10);
215 				continue;
216 
217 			case 0: /* child */
218 				/* setup stdin/stdout/stderr */
219 				dup2(fd, 0);
220 				dup2(fd, 1);
221 				/*dup2(fd, 2);*/
222 				free(fds);
223 				free(sock);
224 				close(fd);
225 				for (j = 0; j < nsock; j++)
226 					close(sock[j]);
227 				return;
228 
229 			default: /* parent */
230 				close(fd);
231 				continue;
232 			}
233 		}
234 	}
235 	free(fds);
236 }
237 
238 #endif /* NO_DAEMON_MODE */
239