[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.22

1.22    ! mrg         1: /*     $NetBSD: daemon-bozo.c,v 1.21 2019/01/17 07:46:16 mrg Exp $     */
1.2       tls         2:
1.15      mrg         3: /*     $eterna: daemon-bozo.c,v 1.24 2011/11/18 09:21:15 mrg Exp $     */
1.1       tls         4:
                      5: /*
1.21      mrg         6:  * Copyright (c) 1997-2019 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:
1.13      jmmv       43: #include <assert.h>
1.1       tls        44: #include <errno.h>
                     45: #include <netdb.h>
                     46: #include <poll.h>
1.13      jmmv       47: #include <stdio.h>
1.1       tls        48: #include <stdlib.h>
                     49: #include <string.h>
                     50: #include <unistd.h>
                     51:
                     52: #include "bozohttpd.h"
                     53:
                     54: static void    sigchild(int);  /* SIGCHLD handler */
                     55:
1.7       mrg        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
1.22    ! mrg        65: #ifndef USE_ARG
        !            66: #define USE_ARG(x)     /*LINTED*/(void)&(x)
        !            67: #endif
1.7       mrg        68:
1.13      jmmv       69: static const char* pidfile_path = NULL;
                     70: static pid_t pidfile_pid = 0;
                     71:
1.1       tls        72: static void
1.8       mrg        73: sigchild(int signo)
1.1       tls        74: {
1.22    ! mrg        75:        USE_ARG(signo);
1.19      mrg        76:        while (waitpid(-1, NULL, WNOHANG) > 0)
                     77:                /* nothing */;
1.1       tls        78: }
                     79:
1.13      jmmv       80: /* Signal handler to exit in a controlled manner.  This ensures that
                     81:  * any atexit(3) handlers are properly executed. */
1.14      joerg      82: BOZO_DEAD static void
1.13      jmmv       83: controlled_exit(int signo)
                     84: {
1.22    ! mrg        85:        USE_ARG(signo);
1.13      jmmv       86:        exit(EXIT_SUCCESS);
                     87: }
                     88:
                     89: static void
                     90: remove_pidfile(void)
                     91: {
                     92:
                     93:        if (pidfile_path != NULL && pidfile_pid == getpid()) {
                     94:                (void)unlink(pidfile_path);
                     95:                pidfile_path = NULL;
                     96:        }
                     97: }
                     98:
                     99: static void
                    100: create_pidfile(bozohttpd_t *httpd)
                    101: {
                    102:        FILE *file;
                    103:
                    104:        assert(pidfile_path == NULL);
                    105:
                    106:        if (httpd->pidfile == NULL)
                    107:                return;
                    108:
                    109:        if (atexit(remove_pidfile) == -1)
1.17      mrg       110:                bozoerr(httpd, 1, "Failed to install pidfile handler");
1.13      jmmv      111:
                    112:        if ((file = fopen(httpd->pidfile, "w")) == NULL)
1.17      mrg       113:                bozoerr(httpd, 1, "Failed to create pidfile '%s'",
1.13      jmmv      114:                    httpd->pidfile);
                    115:        (void)fprintf(file, "%d\n", getpid());
                    116:        (void)fclose(file);
                    117:
                    118:        pidfile_path = httpd->pidfile;
                    119:        pidfile_pid = getpid();
                    120:
                    121:        debug((httpd, DEBUG_FAT, "Created pid file '%s' for pid %d",
                    122:            pidfile_path, pidfile_pid));
                    123: }
                    124:
1.1       tls       125: void
1.8       mrg       126: bozo_daemon_init(bozohttpd_t *httpd)
1.1       tls       127: {
                    128:        struct addrinfo h, *r, *r0;
1.8       mrg       129:        const char      *portnum;
1.1       tls       130:        int e, i, on = 1;
                    131:
1.22    ! mrg       132:        if (!httpd->background && !httpd->foreground)
        !           133:                return;
        !           134:
1.8       mrg       135:        if (!httpd->background)
1.22    ! mrg       136:                httpd->background = 1;
1.1       tls       137:
1.8       mrg       138:        portnum = (httpd->bindport) ? httpd->bindport : "http";
1.1       tls       139:
1.8       mrg       140:        memset(&h, 0, sizeof(h));
1.1       tls       141:        h.ai_family = PF_UNSPEC;
                    142:        h.ai_socktype = SOCK_STREAM;
                    143:        h.ai_flags = AI_PASSIVE;
1.8       mrg       144:        e = getaddrinfo(httpd->bindaddress, portnum, &h, &r0);
1.1       tls       145:        if (e)
1.17      mrg       146:                bozoerr(httpd, 1, "getaddrinfo([%s]:%s): %s",
1.8       mrg       147:                    httpd->bindaddress ? httpd->bindaddress : "*",
                    148:                    portnum, gai_strerror(e));
1.1       tls       149:        for (r = r0; r != NULL; r = r->ai_next)
1.8       mrg       150:                httpd->nsock++;
                    151:        httpd->sock = bozomalloc(httpd, httpd->nsock * sizeof(*httpd->sock));
                    152:        httpd->fds = bozomalloc(httpd, httpd->nsock * sizeof(*httpd->fds));
1.1       tls       153:        for (i = 0, r = r0; r != NULL; r = r->ai_next) {
1.8       mrg       154:                httpd->sock[i] = socket(r->ai_family, SOCK_STREAM, 0);
                    155:                if (httpd->sock[i] == -1)
1.1       tls       156:                        continue;
1.8       mrg       157:                if (setsockopt(httpd->sock[i], SOL_SOCKET, SO_REUSEADDR, &on,
1.1       tls       158:                    sizeof(on)) == -1)
1.17      mrg       159:                        bozowarn(httpd, "setsockopt SO_REUSEADDR: %s",
1.1       tls       160:                            strerror(errno));
1.8       mrg       161:                if (bind(httpd->sock[i], r->ai_addr, r->ai_addrlen) == -1)
1.1       tls       162:                        continue;
1.8       mrg       163:                if (listen(httpd->sock[i], SOMAXCONN) == -1)
1.1       tls       164:                        continue;
1.8       mrg       165:                httpd->fds[i].events = POLLIN | POLLPRI | POLLRDNORM |
1.7       mrg       166:                                POLLRDBAND | POLLERR;
1.8       mrg       167:                httpd->fds[i].fd = httpd->sock[i];
1.1       tls       168:                i++;
                    169:        }
                    170:        if (i == 0)
1.17      mrg       171:                bozoerr(httpd, 1, "could not find any addresses to bind");
1.8       mrg       172:        httpd->nsock = i;
1.1       tls       173:        freeaddrinfo(r0);
                    174:
1.12      pooka     175:        if (httpd->foreground == 0)
                    176:                daemon(1, 0);
                    177:
1.13      jmmv      178:        create_pidfile(httpd);
                    179:
1.17      mrg       180:        bozowarn(httpd, "started in daemon mode as `%s' port `%s' root `%s'",
1.12      pooka     181:            httpd->virthostname, portnum, httpd->slashdir);
                    182:
1.13      jmmv      183:        signal(SIGHUP, controlled_exit);
                    184:        signal(SIGINT, controlled_exit);
                    185:        signal(SIGTERM, controlled_exit);
                    186:
1.1       tls       187:        signal(SIGCHLD, sigchild);
                    188: }
                    189:
1.7       mrg       190: void
1.8       mrg       191: bozo_daemon_closefds(bozohttpd_t *httpd)
1.7       mrg       192: {
                    193:        int i;
                    194:
1.8       mrg       195:        for (i = 0; i < httpd->nsock; i++)
                    196:                close(httpd->sock[i]);
1.7       mrg       197: }
                    198:
                    199: static void
1.8       mrg       200: daemon_runchild(bozohttpd_t *httpd, int fd)
1.7       mrg       201: {
1.8       mrg       202:        httpd->request_times++;
1.7       mrg       203:
                    204:        /* setup stdin/stdout/stderr */
                    205:        dup2(fd, 0);
                    206:        dup2(fd, 1);
                    207:        /*dup2(fd, 2);*/
                    208:        close(fd);
                    209: }
                    210:
1.9       mrg       211: static int
1.20      mrg       212: daemon_poll_err(bozohttpd_t *httpd, int idx)
1.9       mrg       213: {
                    214:        if ((httpd->fds[idx].revents & (POLLNVAL|POLLERR|POLLHUP)) == 0)
                    215:                return 0;
                    216:
1.17      mrg       217:        bozowarn(httpd, "poll on fd %d pid %d revents %d: %s",
1.9       mrg       218:            httpd->fds[idx].fd, getpid(), httpd->fds[idx].revents,
                    219:            strerror(errno));
1.17      mrg       220:        bozowarn(httpd, "nsock = %d", httpd->nsock);
1.9       mrg       221:        close(httpd->sock[idx]);
                    222:        httpd->nsock--;
1.17      mrg       223:        bozowarn(httpd, "nsock now = %d", httpd->nsock);
1.9       mrg       224:        /* no sockets left */
                    225:        if (httpd->nsock == 0)
                    226:                exit(0);
                    227:        /* last socket closed is the easy case */
                    228:        if (httpd->nsock != idx) {
                    229:                memmove(&httpd->fds[idx], &httpd->fds[idx+1],
                    230:                        (httpd->nsock - idx) * sizeof(*httpd->fds));
                    231:                memmove(&httpd->sock[idx], &httpd->sock[idx+1],
                    232:                        (httpd->nsock - idx) * sizeof(*httpd->sock));
                    233:        }
                    234:
                    235:        return 1;
                    236: }
                    237:
1.1       tls       238: /*
                    239:  * the parent never returns from this function, only children that
1.5       mrg       240:  * are ready to run... XXXMRG - still true in fork-lesser bozo?
1.1       tls       241:  */
1.10      mrg       242: int
1.8       mrg       243: bozo_daemon_fork(bozohttpd_t *httpd)
1.1       tls       244: {
1.7       mrg       245:        int i;
1.1       tls       246:
1.8       mrg       247:        debug((httpd, DEBUG_FAT, "%s: pid %u request_times %d",
                    248:                __func__, getpid(),
                    249:                httpd->request_times));
1.7       mrg       250:        /* if we've handled 5 files, exit and let someone else work */
1.8       mrg       251:        if (httpd->request_times > 5 ||
                    252:            (httpd->background == 2 && httpd->request_times > 0))
1.11      mrg       253:                _exit(0);
                    254:
                    255: #if 1
                    256:        if (httpd->request_times > 0)
                    257:                _exit(0);
                    258: #endif
1.6       mrg       259:
1.8       mrg       260:        while (httpd->background) {
1.6       mrg       261:                struct  sockaddr_storage ss;
                    262:                socklen_t slen;
                    263:                int fd;
                    264:
1.8       mrg       265:                if (httpd->nsock == 0)
1.6       mrg       266:                        exit(0);
1.1       tls       267:
                    268:                /*
                    269:                 * wait for a connection, then fork() and return NULL in
                    270:                 * the parent, who will come back here waiting for another
                    271:                 * connection.  read the request in in the child, and return
                    272:                 * it, for processing.
                    273:                 */
                    274: again:
1.8       mrg       275:                if (poll(httpd->fds, (unsigned)httpd->nsock, INFTIM) == -1) {
1.6       mrg       276:                        /* fail on programmer errors */
                    277:                        if (errno == EFAULT ||
                    278:                            errno == EINVAL)
1.17      mrg       279:                                bozoerr(httpd, 1, "poll: %s",
1.8       mrg       280:                                        strerror(errno));
1.6       mrg       281:
                    282:                        /* sleep on some temporary kernel failures */
                    283:                        if (errno == ENOMEM ||
                    284:                            errno == EAGAIN)
                    285:                                sleep(1);
                    286:
1.1       tls       287:                        goto again;
                    288:                }
                    289:
1.8       mrg       290:                for (i = 0; i < httpd->nsock; i++) {
1.20      mrg       291:                        if (daemon_poll_err(httpd, i))
1.6       mrg       292:                                break;
1.8       mrg       293:                        if (httpd->fds[i].revents == 0)
1.1       tls       294:                                continue;
                    295:
1.4       degroote  296:                        slen = sizeof(ss);
1.8       mrg       297:                        fd = accept(httpd->fds[i].fd,
                    298:                                        (struct sockaddr *)(void *)&ss, &slen);
1.1       tls       299:                        if (fd == -1) {
1.6       mrg       300:                                if (errno == EFAULT ||
                    301:                                    errno == EINVAL)
1.17      mrg       302:                                        bozoerr(httpd, 1, "accept: %s",
1.8       mrg       303:                                                strerror(errno));
1.6       mrg       304:
                    305:                                if (errno == ENOMEM ||
                    306:                                    errno == EAGAIN)
                    307:                                        sleep(1);
                    308:
1.1       tls       309:                                continue;
                    310:                        }
1.7       mrg       311:
1.10      mrg       312: #if 0
                    313:                        /*
                    314:                         * This code doesn't work.  It interacts very poorly
                    315:                         * with ~user translation and needs to be fixed.
                    316:                         */
1.8       mrg       317:                        if (httpd->request_times > 0) {
                    318:                                daemon_runchild(httpd, fd);
1.10      mrg       319:                                return 0;
1.7       mrg       320:                        }
1.10      mrg       321: #endif
1.7       mrg       322:
1.1       tls       323:                        switch (fork()) {
                    324:                        case -1: /* eep, failure */
1.17      mrg       325:                                bozowarn(httpd, "fork() failed, sleeping for "
1.7       mrg       326:                                        "10 seconds: %s", strerror(errno));
1.1       tls       327:                                close(fd);
                    328:                                sleep(10);
1.7       mrg       329:                                break;
1.1       tls       330:
                    331:                        case 0: /* child */
1.8       mrg       332:                                daemon_runchild(httpd, fd);
1.10      mrg       333:                                return 0;
1.1       tls       334:
                    335:                        default: /* parent */
                    336:                                close(fd);
1.7       mrg       337:                                break;
1.1       tls       338:                        }
                    339:                }
                    340:        }
1.10      mrg       341:        return 0;
1.1       tls       342: }
                    343:
                    344: #endif /* NO_DAEMON_MODE */

CVSweb <webmaster@jp.NetBSD.org>