[BACK]Return to daemon-bozo.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / libexec / httpd

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>