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