Update post installation article url
[minix3.git] / libexec / httpd / daemon-bozo.c
blobff3109af3f7df3eebcaaa1e938a77cf420cd034a
1 /* $NetBSD: daemon-bozo.c,v 1.16 2014/01/02 08:21:38 mrg Exp $ */
3 /* $eterna: daemon-bozo.c,v 1.24 2011/11/18 09:21:15 mrg Exp $ */
5 /*
6 * Copyright (c) 1997-2014 Matthew R. Green
7 * All rights reserved.
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.
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.
33 /* this code implements daemon mode for bozohttpd */
35 #ifndef NO_DAEMON_MODE
37 #include <sys/param.h>
38 #include <sys/socket.h>
39 #include <sys/wait.h>
41 #include <netinet/in.h>
43 #include <assert.h>
44 #include <errno.h>
45 #include <netdb.h>
46 #include <poll.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <unistd.h>
52 #include "bozohttpd.h"
54 static void sigchild(int); /* SIGCHLD handler */
56 #ifndef POLLRDNORM
57 #define POLLRDNORM 0
58 #endif
59 #ifndef POLLRDBAND
60 #define POLLRDBAND 0
61 #endif
62 #ifndef INFTIM
63 #define INFTIM -1
64 #endif
66 static const char* pidfile_path = NULL;
67 static pid_t pidfile_pid = 0;
69 /* ARGSUSED */
70 static void
71 sigchild(int signo)
73 while (waitpid(-1, NULL, WNOHANG) > 0) {
77 /* Signal handler to exit in a controlled manner. This ensures that
78 * any atexit(3) handlers are properly executed. */
79 /* ARGSUSED */
80 BOZO_DEAD static void
81 controlled_exit(int signo)
84 exit(EXIT_SUCCESS);
87 static void
88 remove_pidfile(void)
91 if (pidfile_path != NULL && pidfile_pid == getpid()) {
92 (void)unlink(pidfile_path);
93 pidfile_path = NULL;
97 static void
98 create_pidfile(bozohttpd_t *httpd)
100 FILE *file;
102 assert(pidfile_path == NULL);
104 if (httpd->pidfile == NULL)
105 return;
107 if (atexit(remove_pidfile) == -1)
108 bozo_err(httpd, 1, "Failed to install pidfile handler");
110 if ((file = fopen(httpd->pidfile, "w")) == NULL)
111 bozo_err(httpd, 1, "Failed to create pidfile '%s'",
112 httpd->pidfile);
113 (void)fprintf(file, "%d\n", getpid());
114 (void)fclose(file);
116 pidfile_path = httpd->pidfile;
117 pidfile_pid = getpid();
119 debug((httpd, DEBUG_FAT, "Created pid file '%s' for pid %d",
120 pidfile_path, pidfile_pid));
123 void
124 bozo_daemon_init(bozohttpd_t *httpd)
126 struct addrinfo h, *r, *r0;
127 const char *portnum;
128 int e, i, on = 1;
130 if (!httpd->background)
131 return;
133 portnum = (httpd->bindport) ? httpd->bindport : "http";
135 memset(&h, 0, sizeof(h));
136 h.ai_family = PF_UNSPEC;
137 h.ai_socktype = SOCK_STREAM;
138 h.ai_flags = AI_PASSIVE;
139 e = getaddrinfo(httpd->bindaddress, portnum, &h, &r0);
140 if (e)
141 bozo_err(httpd, 1, "getaddrinfo([%s]:%s): %s",
142 httpd->bindaddress ? httpd->bindaddress : "*",
143 portnum, gai_strerror(e));
144 for (r = r0; r != NULL; r = r->ai_next)
145 httpd->nsock++;
146 httpd->sock = bozomalloc(httpd, httpd->nsock * sizeof(*httpd->sock));
147 httpd->fds = bozomalloc(httpd, httpd->nsock * sizeof(*httpd->fds));
148 for (i = 0, r = r0; r != NULL; r = r->ai_next) {
149 httpd->sock[i] = socket(r->ai_family, SOCK_STREAM, 0);
150 if (httpd->sock[i] == -1)
151 continue;
152 if (setsockopt(httpd->sock[i], SOL_SOCKET, SO_REUSEADDR, &on,
153 sizeof(on)) == -1)
154 bozo_warn(httpd, "setsockopt SO_REUSEADDR: %s",
155 strerror(errno));
156 if (bind(httpd->sock[i], r->ai_addr, r->ai_addrlen) == -1)
157 continue;
158 if (listen(httpd->sock[i], SOMAXCONN) == -1)
159 continue;
160 httpd->fds[i].events = POLLIN | POLLPRI | POLLRDNORM |
161 POLLRDBAND | POLLERR;
162 httpd->fds[i].fd = httpd->sock[i];
163 i++;
165 if (i == 0)
166 bozo_err(httpd, 1, "could not find any addresses to bind");
167 httpd->nsock = i;
168 freeaddrinfo(r0);
170 if (httpd->foreground == 0)
171 daemon(1, 0);
173 create_pidfile(httpd);
175 bozo_warn(httpd, "started in daemon mode as `%s' port `%s' root `%s'",
176 httpd->virthostname, portnum, httpd->slashdir);
178 signal(SIGHUP, controlled_exit);
179 signal(SIGINT, controlled_exit);
180 signal(SIGTERM, controlled_exit);
182 signal(SIGCHLD, sigchild);
185 void
186 bozo_daemon_closefds(bozohttpd_t *httpd)
188 int i;
190 for (i = 0; i < httpd->nsock; i++)
191 close(httpd->sock[i]);
194 static void
195 daemon_runchild(bozohttpd_t *httpd, int fd)
197 httpd->request_times++;
199 /* setup stdin/stdout/stderr */
200 dup2(fd, 0);
201 dup2(fd, 1);
202 /*dup2(fd, 2);*/
203 close(fd);
206 static int
207 daemon_poll_err(bozohttpd_t *httpd, int fd, int idx)
209 if ((httpd->fds[idx].revents & (POLLNVAL|POLLERR|POLLHUP)) == 0)
210 return 0;
212 bozo_warn(httpd, "poll on fd %d pid %d revents %d: %s",
213 httpd->fds[idx].fd, getpid(), httpd->fds[idx].revents,
214 strerror(errno));
215 bozo_warn(httpd, "nsock = %d", httpd->nsock);
216 close(httpd->sock[idx]);
217 httpd->nsock--;
218 bozo_warn(httpd, "nsock now = %d", httpd->nsock);
219 /* no sockets left */
220 if (httpd->nsock == 0)
221 exit(0);
222 /* last socket closed is the easy case */
223 if (httpd->nsock != idx) {
224 memmove(&httpd->fds[idx], &httpd->fds[idx+1],
225 (httpd->nsock - idx) * sizeof(*httpd->fds));
226 memmove(&httpd->sock[idx], &httpd->sock[idx+1],
227 (httpd->nsock - idx) * sizeof(*httpd->sock));
230 return 1;
234 * the parent never returns from this function, only children that
235 * are ready to run... XXXMRG - still true in fork-lesser bozo?
238 bozo_daemon_fork(bozohttpd_t *httpd)
240 int i;
242 debug((httpd, DEBUG_FAT, "%s: pid %u request_times %d",
243 __func__, getpid(),
244 httpd->request_times));
245 /* if we've handled 5 files, exit and let someone else work */
246 if (httpd->request_times > 5 ||
247 (httpd->background == 2 && httpd->request_times > 0))
248 _exit(0);
250 #if 1
251 if (httpd->request_times > 0)
252 _exit(0);
253 #endif
255 while (httpd->background) {
256 struct sockaddr_storage ss;
257 socklen_t slen;
258 int fd;
260 if (httpd->nsock == 0)
261 exit(0);
264 * wait for a connection, then fork() and return NULL in
265 * the parent, who will come back here waiting for another
266 * connection. read the request in in the child, and return
267 * it, for processing.
269 again:
270 if (poll(httpd->fds, (unsigned)httpd->nsock, INFTIM) == -1) {
271 /* fail on programmer errors */
272 if (errno == EFAULT ||
273 errno == EINVAL)
274 bozo_err(httpd, 1, "poll: %s",
275 strerror(errno));
277 /* sleep on some temporary kernel failures */
278 if (errno == ENOMEM ||
279 errno == EAGAIN)
280 sleep(1);
282 goto again;
285 for (i = 0; i < httpd->nsock; i++) {
286 if (daemon_poll_err(httpd, fd, i))
287 break;
288 if (httpd->fds[i].revents == 0)
289 continue;
291 slen = sizeof(ss);
292 fd = accept(httpd->fds[i].fd,
293 (struct sockaddr *)(void *)&ss, &slen);
294 if (fd == -1) {
295 if (errno == EFAULT ||
296 errno == EINVAL)
297 bozo_err(httpd, 1, "accept: %s",
298 strerror(errno));
300 if (errno == ENOMEM ||
301 errno == EAGAIN)
302 sleep(1);
304 continue;
307 #if 0
309 * This code doesn't work. It interacts very poorly
310 * with ~user translation and needs to be fixed.
312 if (httpd->request_times > 0) {
313 daemon_runchild(httpd, fd);
314 return 0;
316 #endif
318 switch (fork()) {
319 case -1: /* eep, failure */
320 bozo_warn(httpd, "fork() failed, sleeping for "
321 "10 seconds: %s", strerror(errno));
322 close(fd);
323 sleep(10);
324 break;
326 case 0: /* child */
327 daemon_runchild(httpd, fd);
328 return 0;
330 default: /* parent */
331 close(fd);
332 break;
336 return 0;
339 #endif /* NO_DAEMON_MODE */