Annotation of src/libexec/httpd/daemon-bozo.c, Revision 1.11
1.11 ! mrg 1: /* $NetBSD: daemon-bozo.c,v 1.10 2010/06/17 19:43:30 mrg Exp $ */
1.2 tls 2:
1.11 ! mrg 3: /* $eterna: daemon-bozo.c,v 1.22 2010/06/21 06:45:45 mrg Exp $ */
1.1 tls 4:
5: /*
1.8 mrg 6: * Copyright (c) 1997-2010 Matthew R. Green
1.1 tls 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: static void sigchild(int); /* SIGCHLD handler */
53:
1.7 mrg 54: #ifndef POLLRDNORM
55: #define POLLRDNORM 0
56: #endif
57: #ifndef POLLRDBAND
58: #define POLLRDBAND 0
59: #endif
60: #ifndef INFTIM
61: #define INFTIM -1
62: #endif
63:
1.1 tls 64: /* ARGSUSED */
65: static void
1.8 mrg 66: sigchild(int signo)
1.1 tls 67: {
1.8 mrg 68: while (waitpid(-1, NULL, WNOHANG) > 0) {
69: }
1.1 tls 70: }
71:
72: void
1.8 mrg 73: bozo_daemon_init(bozohttpd_t *httpd)
1.1 tls 74: {
75: struct addrinfo h, *r, *r0;
1.8 mrg 76: const char *portnum;
1.1 tls 77: int e, i, on = 1;
78:
1.8 mrg 79: if (!httpd->background)
1.1 tls 80: return;
81:
1.8 mrg 82: if (httpd->foreground == 0)
1.1 tls 83: daemon(1, 0);
84:
1.8 mrg 85: portnum = (httpd->bindport) ? httpd->bindport : "http";
86: bozo_warn(httpd, "started in daemon mode as `%s' port `%s' root `%s'",
87: httpd->virthostname, portnum, httpd->slashdir);
1.1 tls 88:
1.8 mrg 89: memset(&h, 0, sizeof(h));
1.1 tls 90: h.ai_family = PF_UNSPEC;
91: h.ai_socktype = SOCK_STREAM;
92: h.ai_flags = AI_PASSIVE;
1.8 mrg 93: e = getaddrinfo(httpd->bindaddress, portnum, &h, &r0);
1.1 tls 94: if (e)
1.8 mrg 95: bozo_err(httpd, 1, "getaddrinfo([%s]:%s): %s",
96: httpd->bindaddress ? httpd->bindaddress : "*",
97: portnum, gai_strerror(e));
1.1 tls 98: for (r = r0; r != NULL; r = r->ai_next)
1.8 mrg 99: httpd->nsock++;
100: httpd->sock = bozomalloc(httpd, httpd->nsock * sizeof(*httpd->sock));
101: httpd->fds = bozomalloc(httpd, httpd->nsock * sizeof(*httpd->fds));
1.1 tls 102: for (i = 0, r = r0; r != NULL; r = r->ai_next) {
1.8 mrg 103: httpd->sock[i] = socket(r->ai_family, SOCK_STREAM, 0);
104: if (httpd->sock[i] == -1)
1.1 tls 105: continue;
1.8 mrg 106: if (setsockopt(httpd->sock[i], SOL_SOCKET, SO_REUSEADDR, &on,
1.1 tls 107: sizeof(on)) == -1)
1.8 mrg 108: bozo_warn(httpd, "setsockopt SO_REUSEADDR: %s",
1.1 tls 109: strerror(errno));
1.8 mrg 110: if (bind(httpd->sock[i], r->ai_addr, r->ai_addrlen) == -1)
1.1 tls 111: continue;
1.8 mrg 112: if (listen(httpd->sock[i], SOMAXCONN) == -1)
1.1 tls 113: continue;
1.8 mrg 114: httpd->fds[i].events = POLLIN | POLLPRI | POLLRDNORM |
1.7 mrg 115: POLLRDBAND | POLLERR;
1.8 mrg 116: httpd->fds[i].fd = httpd->sock[i];
1.1 tls 117: i++;
118: }
119: if (i == 0)
1.8 mrg 120: bozo_err(httpd, 1, "could not find any addresses to bind");
121: httpd->nsock = i;
1.1 tls 122: freeaddrinfo(r0);
123:
124: signal(SIGCHLD, sigchild);
125: }
126:
1.7 mrg 127: void
1.8 mrg 128: bozo_daemon_closefds(bozohttpd_t *httpd)
1.7 mrg 129: {
130: int i;
131:
1.8 mrg 132: for (i = 0; i < httpd->nsock; i++)
133: close(httpd->sock[i]);
1.7 mrg 134: }
135:
136: static void
1.8 mrg 137: daemon_runchild(bozohttpd_t *httpd, int fd)
1.7 mrg 138: {
1.8 mrg 139: httpd->request_times++;
1.7 mrg 140:
141: /* setup stdin/stdout/stderr */
142: dup2(fd, 0);
143: dup2(fd, 1);
144: /*dup2(fd, 2);*/
145: close(fd);
146: }
147:
1.9 mrg 148: static int
149: daemon_poll_err(bozohttpd_t *httpd, int fd, int idx)
150: {
151: if ((httpd->fds[idx].revents & (POLLNVAL|POLLERR|POLLHUP)) == 0)
152: return 0;
153:
154: bozo_warn(httpd, "poll on fd %d pid %d revents %d: %s",
155: httpd->fds[idx].fd, getpid(), httpd->fds[idx].revents,
156: strerror(errno));
157: bozo_warn(httpd, "nsock = %d", httpd->nsock);
158: close(httpd->sock[idx]);
159: httpd->nsock--;
160: bozo_warn(httpd, "nsock now = %d", httpd->nsock);
161: /* no sockets left */
162: if (httpd->nsock == 0)
163: exit(0);
164: /* last socket closed is the easy case */
165: if (httpd->nsock != idx) {
166: memmove(&httpd->fds[idx], &httpd->fds[idx+1],
167: (httpd->nsock - idx) * sizeof(*httpd->fds));
168: memmove(&httpd->sock[idx], &httpd->sock[idx+1],
169: (httpd->nsock - idx) * sizeof(*httpd->sock));
170: }
171:
172: return 1;
173: }
174:
1.1 tls 175: /*
176: * the parent never returns from this function, only children that
1.5 mrg 177: * are ready to run... XXXMRG - still true in fork-lesser bozo?
1.1 tls 178: */
1.10 mrg 179: int
1.8 mrg 180: bozo_daemon_fork(bozohttpd_t *httpd)
1.1 tls 181: {
1.7 mrg 182: int i;
1.1 tls 183:
1.8 mrg 184: debug((httpd, DEBUG_FAT, "%s: pid %u request_times %d",
185: __func__, getpid(),
186: httpd->request_times));
1.7 mrg 187: /* if we've handled 5 files, exit and let someone else work */
1.8 mrg 188: if (httpd->request_times > 5 ||
189: (httpd->background == 2 && httpd->request_times > 0))
1.11 ! mrg 190: _exit(0);
! 191:
! 192: #if 1
! 193: if (httpd->request_times > 0)
! 194: _exit(0);
! 195: #endif
1.6 mrg 196:
1.8 mrg 197: while (httpd->background) {
1.6 mrg 198: struct sockaddr_storage ss;
199: socklen_t slen;
200: int fd;
201:
1.8 mrg 202: if (httpd->nsock == 0)
1.6 mrg 203: exit(0);
1.1 tls 204:
205: /*
206: * wait for a connection, then fork() and return NULL in
207: * the parent, who will come back here waiting for another
208: * connection. read the request in in the child, and return
209: * it, for processing.
210: */
211: again:
1.8 mrg 212: if (poll(httpd->fds, (unsigned)httpd->nsock, INFTIM) == -1) {
1.6 mrg 213: /* fail on programmer errors */
214: if (errno == EFAULT ||
215: errno == EINVAL)
1.8 mrg 216: bozo_err(httpd, 1, "poll: %s",
217: strerror(errno));
1.6 mrg 218:
219: /* sleep on some temporary kernel failures */
220: if (errno == ENOMEM ||
221: errno == EAGAIN)
222: sleep(1);
223:
1.1 tls 224: goto again;
225: }
226:
1.8 mrg 227: for (i = 0; i < httpd->nsock; i++) {
1.9 mrg 228: if (daemon_poll_err(httpd, fd, i))
1.6 mrg 229: break;
1.8 mrg 230: if (httpd->fds[i].revents == 0)
1.1 tls 231: continue;
232:
1.4 degroote 233: slen = sizeof(ss);
1.8 mrg 234: fd = accept(httpd->fds[i].fd,
235: (struct sockaddr *)(void *)&ss, &slen);
1.1 tls 236: if (fd == -1) {
1.6 mrg 237: if (errno == EFAULT ||
238: errno == EINVAL)
1.8 mrg 239: bozo_err(httpd, 1, "accept: %s",
240: strerror(errno));
1.6 mrg 241:
242: if (errno == ENOMEM ||
243: errno == EAGAIN)
244: sleep(1);
245:
1.1 tls 246: continue;
247: }
1.7 mrg 248:
1.10 mrg 249: #if 0
250: /*
251: * This code doesn't work. It interacts very poorly
252: * with ~user translation and needs to be fixed.
253: */
1.8 mrg 254: if (httpd->request_times > 0) {
255: daemon_runchild(httpd, fd);
1.10 mrg 256: return 0;
1.7 mrg 257: }
1.10 mrg 258: #endif
1.7 mrg 259:
1.1 tls 260: switch (fork()) {
261: case -1: /* eep, failure */
1.8 mrg 262: bozo_warn(httpd, "fork() failed, sleeping for "
1.7 mrg 263: "10 seconds: %s", strerror(errno));
1.1 tls 264: close(fd);
265: sleep(10);
1.7 mrg 266: break;
1.1 tls 267:
268: case 0: /* child */
1.8 mrg 269: daemon_runchild(httpd, fd);
1.10 mrg 270: return 0;
1.1 tls 271:
272: default: /* parent */
273: close(fd);
1.7 mrg 274: break;
1.1 tls 275: }
276: }
277: }
1.10 mrg 278: return 0;
1.1 tls 279: }
280:
281: #endif /* NO_DAEMON_MODE */
CVSweb <webmaster@jp.NetBSD.org>