[BACK]Return to listen.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / sndiod

Annotation of src/usr.bin/sndiod/listen.c, Revision 1.1

1.1     ! ratchov     1: /*     $OpenBSD$       */
        !             2: /*
        !             3:  * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
        !             4:  *
        !             5:  * Permission to use, copy, modify, and distribute this software for any
        !             6:  * purpose with or without fee is hereby granted, provided that the above
        !             7:  * copyright notice and this permission notice appear in all copies.
        !             8:  *
        !             9:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        !            10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            11:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        !            12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
        !            15:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            16:  */
        !            17: #include <sys/types.h>
        !            18: #include <sys/socket.h>
        !            19: #include <sys/signal.h>
        !            20: #include <sys/stat.h>
        !            21: #include <sys/un.h>
        !            22:
        !            23: #include <netinet/in.h>
        !            24: #include <netinet/tcp.h>
        !            25: #include <netdb.h>
        !            26:
        !            27: #include <err.h>
        !            28: #include <errno.h>
        !            29: #include <fcntl.h>
        !            30: #include <poll.h>
        !            31: #include <stdio.h>
        !            32: #include <stdlib.h>
        !            33: #include <string.h>
        !            34: #include <unistd.h>
        !            35:
        !            36: #include "listen.h"
        !            37: #include "file.h"
        !            38: #include "sock.h"
        !            39: #include "utils.h"
        !            40:
        !            41: int listen_pollfd(void *, struct pollfd *);
        !            42: int listen_revents(void *, struct pollfd *);
        !            43: void listen_in(void *);
        !            44: void listen_out(void *);
        !            45: void listen_hup(void *);
        !            46:
        !            47: struct fileops listen_fileops = {
        !            48:        "listen",
        !            49:        listen_pollfd,
        !            50:        listen_revents,
        !            51:        listen_in,
        !            52:        listen_out,
        !            53:        listen_hup
        !            54: };
        !            55:
        !            56: struct listen *listen_list = NULL;
        !            57:
        !            58: void
        !            59: listen_close(struct listen *f)
        !            60: {
        !            61:        struct listen **pf;
        !            62:
        !            63:        for (pf = &listen_list; *pf != f; pf = &(*pf)->next) {
        !            64: #ifdef DEBUG
        !            65:                if (*pf == NULL) {
        !            66:                        log_puts("listen_close: not on list\n");
        !            67:                        panic();
        !            68:                }
        !            69: #endif
        !            70:        }
        !            71:        *pf = f->next;
        !            72:
        !            73:        if (f->path != NULL) {
        !            74:                unlink(f->path);
        !            75:                xfree(f->path);
        !            76:        }
        !            77:        file_del(f->file);
        !            78:        close(f->fd);
        !            79:        xfree(f);
        !            80: }
        !            81:
        !            82: void
        !            83: listen_new_un(char *path)
        !            84: {
        !            85:        int sock, oldumask;
        !            86:        struct sockaddr_un sockname;
        !            87:        struct listen *f;
        !            88:
        !            89:        sock = socket(AF_UNIX, SOCK_STREAM, 0);
        !            90:        if (sock < 0) {
        !            91:                perror("socket");
        !            92:                exit(1);
        !            93:        }
        !            94:        if (unlink(path) < 0 && errno != ENOENT) {
        !            95:                perror("unlink");
        !            96:                goto bad_close;
        !            97:        }
        !            98:        sockname.sun_family = AF_UNIX;
        !            99:        strlcpy(sockname.sun_path, path, sizeof(sockname.sun_path));
        !           100:        oldumask = umask(0111);
        !           101:        if (bind(sock, (struct sockaddr *)&sockname,
        !           102:                sizeof(struct sockaddr_un)) < 0) {
        !           103:                perror("bind");
        !           104:                goto bad_close;
        !           105:        }
        !           106:        if (listen(sock, 1) < 0) {
        !           107:                perror("listen");
        !           108:                goto bad_close;
        !           109:        }
        !           110:        umask(oldumask);
        !           111:        f = xmalloc(sizeof(struct listen));
        !           112:        f->file = file_new(&listen_fileops, f, path, 1);
        !           113:        if (f->file == NULL)
        !           114:                goto bad_close;
        !           115:        f->path = xstrdup(path);
        !           116:        if (f->path == NULL) {
        !           117:                perror("strdup");
        !           118:                exit(1);
        !           119:        }
        !           120:        f->fd = sock;
        !           121:        f->next = listen_list;
        !           122:        listen_list = f;
        !           123:        return;
        !           124:  bad_close:
        !           125:        close(sock);
        !           126:        exit(1);
        !           127: }
        !           128:
        !           129: void
        !           130: listen_new_tcp(char *addr, unsigned int port)
        !           131: {
        !           132:        char *host, serv[sizeof(unsigned int) * 3 + 1];
        !           133:        struct addrinfo *ailist, *ai, aihints;
        !           134:        struct listen *f;
        !           135:        int s, error, opt = 1, n = 0;
        !           136:
        !           137:        /*
        !           138:         * obtain a list of possible addresses for the host/port
        !           139:         */
        !           140:        memset(&aihints, 0, sizeof(struct addrinfo));
        !           141:        snprintf(serv, sizeof(serv), "%u", port);
        !           142:        host = strcmp(addr, "-") == 0 ? NULL : addr;
        !           143:        aihints.ai_flags |= AI_PASSIVE;
        !           144:        aihints.ai_socktype = SOCK_STREAM;
        !           145:        aihints.ai_protocol = IPPROTO_TCP;
        !           146:        error = getaddrinfo(host, serv, &aihints, &ailist);
        !           147:        if (error) {
        !           148:                fprintf(stderr, "%s: %s\n", addr, gai_strerror(error));
        !           149:                exit(1);
        !           150:        }
        !           151:
        !           152:        /*
        !           153:         * for each address, try create a listening socket bound on
        !           154:         * that address
        !           155:         */
        !           156:        for (ai = ailist; ai != NULL; ai = ai->ai_next) {
        !           157:                s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
        !           158:                if (s < 0) {
        !           159:                        perror("socket");
        !           160:                        continue;
        !           161:                }
        !           162:                opt = 1;
        !           163:                if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
        !           164:                        &opt, sizeof(int)) < 0) {
        !           165:                        perror("setsockopt");
        !           166:                        goto bad_close;
        !           167:                }
        !           168:                if (ai->ai_family == AF_INET6) {
        !           169:                        /*
        !           170:                         * make sure IPv6 sockets are restricted to IPv6
        !           171:                         * addresses because we already use a IP socket
        !           172:                         * for IP addresses
        !           173:                         */
        !           174:                        opt = 1;
        !           175:                        if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
        !           176:                                &opt, sizeof(int)) < 0) {
        !           177:                                perror("setsockopt");
        !           178:                                goto bad_close;
        !           179:                        }
        !           180:                }
        !           181:
        !           182:                if (bind(s, ai->ai_addr, ai->ai_addrlen) < 0) {
        !           183:                        perror("bind");
        !           184:                        goto bad_close;
        !           185:                }
        !           186:                if (listen(s, 1) < 0) {
        !           187:                        perror("listen");
        !           188:                        goto bad_close;
        !           189:                }
        !           190:                f = xmalloc(sizeof(struct listen));
        !           191:                f->file = file_new(&listen_fileops, f, addr, 1);
        !           192:                if (f == NULL) {
        !           193:                bad_close:
        !           194:                        close(s);
        !           195:                        continue;
        !           196:                }
        !           197:                f->path = NULL;
        !           198:                f->fd = s;
        !           199:                f->next = listen_list;
        !           200:                listen_list = f;
        !           201:                n++;
        !           202:        }
        !           203:        freeaddrinfo(ailist);
        !           204:        if (n == 0)
        !           205:                exit(1);
        !           206: }
        !           207:
        !           208: int
        !           209: listen_init(struct listen *f)
        !           210: {
        !           211:        return 1;
        !           212: }
        !           213:
        !           214: int
        !           215: listen_pollfd(void *arg, struct pollfd *pfd)
        !           216: {
        !           217:        struct listen *f = arg;
        !           218:
        !           219:        if (file_slowaccept)
        !           220:                return 0;
        !           221:        pfd->fd = f->fd;
        !           222:        pfd->events = POLLIN;
        !           223:        return 1;
        !           224: }
        !           225:
        !           226: int
        !           227: listen_revents(void *arg, struct pollfd *pfd)
        !           228: {
        !           229:        return pfd->revents;
        !           230: }
        !           231:
        !           232: void
        !           233: listen_in(void *arg)
        !           234: {
        !           235:        struct listen *f = arg;
        !           236:        struct sockaddr caddr;
        !           237:        socklen_t caddrlen;
        !           238:        int sock, opt;
        !           239:
        !           240:        caddrlen = sizeof(caddrlen);
        !           241:        while ((sock = accept(f->fd, &caddr, &caddrlen)) < 0) {
        !           242:                if (errno == EINTR)
        !           243:                        continue;
        !           244:                if (errno == ENFILE || errno == EMFILE)
        !           245:                        file_slowaccept = 1;
        !           246:                else
        !           247:                        perror("accept");
        !           248:                return;
        !           249:        }
        !           250:        if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
        !           251:                perror("fcntl(sock, O_NONBLOCK)");
        !           252:                close(sock);
        !           253:                return;
        !           254:        }
        !           255:        if (f->path == NULL) {
        !           256:                opt = 1;
        !           257:                if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
        !           258:                        &opt, sizeof(int)) < 0) {
        !           259:                        perror("setsockopt");
        !           260:                        close(sock);
        !           261:                        return;
        !           262:                }
        !           263:        }
        !           264:        if (sock_new(sock) == NULL) {
        !           265:                close(sock);
        !           266:                return;
        !           267:        }
        !           268: }
        !           269:
        !           270: void
        !           271: listen_out(void *arg)
        !           272: {
        !           273: }
        !           274:
        !           275: void
        !           276: listen_hup(void *arg)
        !           277: {
        !           278:        struct listen *f = arg;
        !           279:
        !           280:        listen_close(f);
        !           281: }