Fix up mix of man(7)/mdoc(7).
[netbsd-mini2440.git] / libexec / httpd / daemon-bozo.c
blobdcedcf2c0be607a7b2a3d6e7e4befb0f6d6c47a2
1 /* $NetBSD: daemon-bozo.c,v 1.6 2009/04/18 21:22:03 mrg Exp $ */
3 /* $eterna: daemon-bozo.c,v 1.17 2009/05/22 21:51:38 mrg Exp $ */
5 /*
6 * Copyright (c) 1997-2009 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 <errno.h>
44 #include <netdb.h>
45 #include <poll.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <unistd.h>
50 #include "bozohttpd.h"
52 char *iflag; /* bind address; default INADDR_ANY */
53 static int *sock; /* bound sockets */
54 static int nsock; /* number of above */
55 static struct pollfd *fds; /* current poll fd set */
56 static int request_times; /* how many times this proc has processed
57 a request */
59 static void daemon_runchild(int);
60 static void sigchild(int); /* SIGCHLD handler */
62 #ifndef POLLRDNORM
63 #define POLLRDNORM 0
64 #endif
65 #ifndef POLLRDBAND
66 #define POLLRDBAND 0
67 #endif
68 #ifndef INFTIM
69 #define INFTIM -1
70 #endif
72 /* ARGSUSED */
73 static void
74 sigchild(signo)
75 int signo;
77 while (waitpid(-1, NULL, WNOHANG) > 0)
81 void
82 daemon_init()
84 struct addrinfo h, *r, *r0;
85 int e, i, on = 1;
87 if (!bflag)
88 return;
90 if (fflag == 0)
91 daemon(1, 0);
93 warning("started in daemon mode as `%s' port `%s' root `%s'",
94 myname, Iflag, slashdir);
96 memset(&h, 0, sizeof h);
97 h.ai_family = PF_UNSPEC;
98 h.ai_socktype = SOCK_STREAM;
99 h.ai_flags = AI_PASSIVE;
100 e = getaddrinfo(iflag, Iflag, &h, &r0);
101 if (e)
102 error(1, "getaddrinfo([%s]:%s): %s",
103 iflag ? iflag : "*", Iflag, gai_strerror(e));
104 for (r = r0; r != NULL; r = r->ai_next)
105 nsock++;
106 sock = bozomalloc(nsock * sizeof *sock);
107 fds = bozomalloc(nsock * sizeof *fds);
108 for (i = 0, r = r0; r != NULL; r = r->ai_next) {
109 sock[i] = socket(r->ai_family, SOCK_STREAM, 0);
110 if (sock[i] == -1)
111 continue;
112 if (setsockopt(sock[i], SOL_SOCKET, SO_REUSEADDR, &on,
113 sizeof(on)) == -1)
114 warning("setsockopt SO_REUSEADDR: %s",
115 strerror(errno));
116 if (bind(sock[i], r->ai_addr, r->ai_addrlen) == -1)
117 continue;
118 if (listen(sock[i], SOMAXCONN) == -1)
119 continue;
120 fds[i].events = POLLIN | POLLPRI | POLLRDNORM |
121 POLLRDBAND | POLLERR;
122 fds[i].fd = sock[i];
123 i++;
125 if (i == 0)
126 error(1, "could not find any addresses to bind");
127 nsock = i;
128 freeaddrinfo(r0);
130 signal(SIGCHLD, sigchild);
133 void
134 daemon_closefds(void)
136 int i;
138 for (i = 0; i < nsock; i++)
139 close(sock[i]);
142 static void
143 daemon_runchild(int fd)
146 request_times++;
148 /* setup stdin/stdout/stderr */
149 dup2(fd, 0);
150 dup2(fd, 1);
151 /*dup2(fd, 2);*/
152 close(fd);
156 * the parent never returns from this function, only children that
157 * are ready to run... XXXMRG - still true in fork-lesser bozo?
159 void
160 daemon_fork()
162 int i;
164 debug((DEBUG_FAT, "%s: pid %u request_times %d", __func__, getpid(),
165 request_times));
166 /* if we've handled 5 files, exit and let someone else work */
167 if (request_times > 5 || (bflag == 2 && request_times > 0))
168 exit(0);
170 while (bflag) {
171 struct sockaddr_storage ss;
172 socklen_t slen;
173 int fd;
175 if (nsock == 0)
176 exit(0);
179 * wait for a connection, then fork() and return NULL in
180 * the parent, who will come back here waiting for another
181 * connection. read the request in in the child, and return
182 * it, for processing.
184 again:
185 if (poll(fds, nsock, INFTIM) == -1) {
186 /* fail on programmer errors */
187 if (errno == EFAULT ||
188 errno == EINVAL)
189 error(1, "poll: %s", strerror(errno));
191 /* sleep on some temporary kernel failures */
192 if (errno == ENOMEM ||
193 errno == EAGAIN)
194 sleep(1);
196 goto again;
199 for (i = 0; i < nsock; i++) {
200 if (fds[i].revents & (POLLNVAL|POLLERR|POLLHUP)) {
201 warning("poll on fd %d pid %d revents %d: %s",
202 fds[i].fd, getpid(), fds[i].revents,
203 strerror(errno));
204 warning("nsock = %d", nsock);
205 close(sock[i]);
206 nsock--;
207 warning("nsock now = %d", nsock);
208 /* no sockets left */
209 if (nsock == 0)
210 exit(0);
211 /* last socket; easy case */
212 if (nsock == i)
213 break;
214 memmove(&fds[i], &fds[i+i],
215 (nsock - i) * sizeof(*fds));
216 memmove(&sock[i], &sock[i+i],
217 (nsock - i) * sizeof(*sock));
218 break;
220 if (fds[i].revents == 0)
221 continue;
223 slen = sizeof(ss);
224 fd = accept(fds[i].fd, (struct sockaddr *)&ss, &slen);
225 if (fd == -1) {
226 if (errno == EFAULT ||
227 errno == EINVAL)
228 error(1, "accept: %s", strerror(errno));
230 if (errno == ENOMEM ||
231 errno == EAGAIN)
232 sleep(1);
234 continue;
237 if (request_times > 0) {
238 daemon_runchild(fd);
239 return;
242 switch (fork()) {
243 case -1: /* eep, failure */
244 warning("fork() failed, sleeping for "
245 "10 seconds: %s", strerror(errno));
246 close(fd);
247 sleep(10);
248 break;
250 case 0: /* child */
251 daemon_runchild(fd);
252 return;
254 default: /* parent */
255 close(fd);
256 break;
262 #endif /* NO_DAEMON_MODE */