Annotation of embedaddon/tmux/proc.c, revision 1.1

1.1     ! misho       1: /* $OpenBSD$ */
        !             2: 
        !             3: /*
        !             4:  * Copyright (c) 2015 Nicholas Marriott <nicholas.marriott@gmail.com>
        !             5:  *
        !             6:  * Permission to use, copy, modify, and distribute this software for any
        !             7:  * purpose with or without fee is hereby granted, provided that the above
        !             8:  * copyright notice and this permission notice appear in all copies.
        !             9:  *
        !            10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        !            11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        !            13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            14:  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
        !            15:  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
        !            16:  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            17:  */
        !            18: 
        !            19: #include <sys/types.h>
        !            20: #include <sys/uio.h>
        !            21: #include <sys/utsname.h>
        !            22: 
        !            23: #include <errno.h>
        !            24: #include <event.h>
        !            25: #include <stdlib.h>
        !            26: #include <string.h>
        !            27: #include <unistd.h>
        !            28: 
        !            29: #include "tmux.h"
        !            30: 
        !            31: struct tmuxproc {
        !            32:        const char       *name;
        !            33:        int               exit;
        !            34: 
        !            35:        void            (*signalcb)(int);
        !            36: };
        !            37: 
        !            38: struct tmuxpeer {
        !            39:        struct tmuxproc *parent;
        !            40: 
        !            41:        struct imsgbuf   ibuf;
        !            42:        struct event     event;
        !            43: 
        !            44:        int              flags;
        !            45: #define PEER_BAD 0x1
        !            46: 
        !            47:        void            (*dispatchcb)(struct imsg *, void *);
        !            48:        void            *arg;
        !            49: };
        !            50: 
        !            51: static int     peer_check_version(struct tmuxpeer *, struct imsg *);
        !            52: static void    proc_update_event(struct tmuxpeer *);
        !            53: 
        !            54: static void
        !            55: proc_event_cb(__unused int fd, short events, void *arg)
        !            56: {
        !            57:        struct tmuxpeer *peer = arg;
        !            58:        ssize_t          n;
        !            59:        struct imsg      imsg;
        !            60: 
        !            61:        if (!(peer->flags & PEER_BAD) && (events & EV_READ)) {
        !            62:                if (((n = imsg_read(&peer->ibuf)) == -1 && errno != EAGAIN) ||
        !            63:                    n == 0) {
        !            64:                        peer->dispatchcb(NULL, peer->arg);
        !            65:                        return;
        !            66:                }
        !            67:                for (;;) {
        !            68:                        if ((n = imsg_get(&peer->ibuf, &imsg)) == -1) {
        !            69:                                peer->dispatchcb(NULL, peer->arg);
        !            70:                                return;
        !            71:                        }
        !            72:                        if (n == 0)
        !            73:                                break;
        !            74:                        log_debug("peer %p message %d", peer, imsg.hdr.type);
        !            75: 
        !            76:                        if (peer_check_version(peer, &imsg) != 0) {
        !            77:                                if (imsg.fd != -1)
        !            78:                                        close(imsg.fd);
        !            79:                                imsg_free(&imsg);
        !            80:                                break;
        !            81:                        }
        !            82: 
        !            83:                        peer->dispatchcb(&imsg, peer->arg);
        !            84:                        imsg_free(&imsg);
        !            85:                }
        !            86:        }
        !            87: 
        !            88:        if (events & EV_WRITE) {
        !            89:                if (msgbuf_write(&peer->ibuf.w) <= 0 && errno != EAGAIN) {
        !            90:                        peer->dispatchcb(NULL, peer->arg);
        !            91:                        return;
        !            92:                }
        !            93:        }
        !            94: 
        !            95:        if ((peer->flags & PEER_BAD) && peer->ibuf.w.queued == 0) {
        !            96:                peer->dispatchcb(NULL, peer->arg);
        !            97:                return;
        !            98:        }
        !            99: 
        !           100:        proc_update_event(peer);
        !           101: }
        !           102: 
        !           103: static void
        !           104: proc_signal_cb(int signo, __unused short events, void *arg)
        !           105: {
        !           106:        struct tmuxproc *tp = arg;
        !           107: 
        !           108:        tp->signalcb(signo);
        !           109: }
        !           110: 
        !           111: static int
        !           112: peer_check_version(struct tmuxpeer *peer, struct imsg *imsg)
        !           113: {
        !           114:        int     version;
        !           115: 
        !           116:        version = imsg->hdr.peerid & 0xff;
        !           117:        if (imsg->hdr.type != MSG_VERSION && version != PROTOCOL_VERSION) {
        !           118:                log_debug("peer %p bad version %d", peer, version);
        !           119: 
        !           120:                proc_send(peer, MSG_VERSION, -1, NULL, 0);
        !           121:                peer->flags |= PEER_BAD;
        !           122: 
        !           123:                return (-1);
        !           124:        }
        !           125:        return (0);
        !           126: }
        !           127: 
        !           128: static void
        !           129: proc_update_event(struct tmuxpeer *peer)
        !           130: {
        !           131:        short   events;
        !           132: 
        !           133:        event_del(&peer->event);
        !           134: 
        !           135:        events = EV_READ;
        !           136:        if (peer->ibuf.w.queued > 0)
        !           137:                events |= EV_WRITE;
        !           138:        event_set(&peer->event, peer->ibuf.fd, events, proc_event_cb, peer);
        !           139: 
        !           140:        event_add(&peer->event, NULL);
        !           141: }
        !           142: 
        !           143: int
        !           144: proc_send(struct tmuxpeer *peer, enum msgtype type, int fd, const void *buf,
        !           145:     size_t len)
        !           146: {
        !           147:        struct imsgbuf  *ibuf = &peer->ibuf;
        !           148:        void            *vp = (void *)buf;
        !           149:        int              retval;
        !           150: 
        !           151:        if (peer->flags & PEER_BAD)
        !           152:                return (-1);
        !           153:        log_debug("sending message %d to peer %p (%zu bytes)", type, peer, len);
        !           154: 
        !           155:        retval = imsg_compose(ibuf, type, PROTOCOL_VERSION, -1, fd, vp, len);
        !           156:        if (retval != 1)
        !           157:                return (-1);
        !           158:        proc_update_event(peer);
        !           159:        return (0);
        !           160: }
        !           161: 
        !           162: int
        !           163: proc_send_s(struct tmuxpeer *peer, enum msgtype type, const char *s)
        !           164: {
        !           165:        return (proc_send(peer, type, -1, s, strlen(s) + 1));
        !           166: }
        !           167: 
        !           168: struct tmuxproc *
        !           169: proc_start(const char *name, struct event_base *base, int forkflag,
        !           170:     void (*signalcb)(int))
        !           171: {
        !           172:        struct tmuxproc *tp;
        !           173:        struct utsname   u;
        !           174: 
        !           175:        if (forkflag) {
        !           176:                switch (fork()) {
        !           177:                case -1:
        !           178:                        fatal("fork failed");
        !           179:                case 0:
        !           180:                        break;
        !           181:                default:
        !           182:                        return (NULL);
        !           183:                }
        !           184:                if (daemon(1, 0) != 0)
        !           185:                        fatal("daemon failed");
        !           186: 
        !           187:                clear_signals(0);
        !           188:                if (event_reinit(base) != 0)
        !           189:                        fatalx("event_reinit failed");
        !           190:        }
        !           191: 
        !           192:        log_open(name);
        !           193:        setproctitle("%s (%s)", name, socket_path);
        !           194: 
        !           195:        if (uname(&u) < 0)
        !           196:                memset(&u, 0, sizeof u);
        !           197: 
        !           198:        log_debug("%s started (%ld): version %s, socket %s, protocol %d", name,
        !           199:            (long)getpid(), VERSION, socket_path, PROTOCOL_VERSION);
        !           200:        log_debug("on %s %s %s; libevent %s (%s)", u.sysname, u.release,
        !           201:            u.version, event_get_version(), event_get_method());
        !           202: 
        !           203:        tp = xcalloc(1, sizeof *tp);
        !           204:        tp->name = xstrdup(name);
        !           205: 
        !           206:        tp->signalcb = signalcb;
        !           207:        set_signals(proc_signal_cb, tp);
        !           208: 
        !           209:        return (tp);
        !           210: }
        !           211: 
        !           212: void
        !           213: proc_loop(struct tmuxproc *tp, int (*loopcb)(void))
        !           214: {
        !           215:        log_debug("%s loop enter", tp->name);
        !           216:        do
        !           217:                event_loop(EVLOOP_ONCE);
        !           218:        while (!tp->exit && (loopcb == NULL || !loopcb ()));
        !           219:        log_debug("%s loop exit", tp->name);
        !           220: }
        !           221: 
        !           222: void
        !           223: proc_exit(struct tmuxproc *tp)
        !           224: {
        !           225:        tp->exit = 1;
        !           226: }
        !           227: 
        !           228: struct tmuxpeer *
        !           229: proc_add_peer(struct tmuxproc *tp, int fd,
        !           230:     void (*dispatchcb)(struct imsg *, void *), void *arg)
        !           231: {
        !           232:        struct tmuxpeer *peer;
        !           233: 
        !           234:        peer = xcalloc(1, sizeof *peer);
        !           235:        peer->parent = tp;
        !           236: 
        !           237:        peer->dispatchcb = dispatchcb;
        !           238:        peer->arg = arg;
        !           239: 
        !           240:        imsg_init(&peer->ibuf, fd);
        !           241:        event_set(&peer->event, fd, EV_READ, proc_event_cb, peer);
        !           242: 
        !           243:        log_debug("add peer %p: %d (%p)", peer, fd, arg);
        !           244: 
        !           245:        proc_update_event(peer);
        !           246:        return (peer);
        !           247: }
        !           248: 
        !           249: void
        !           250: proc_remove_peer(struct tmuxpeer *peer)
        !           251: {
        !           252:        log_debug("remove peer %p", peer);
        !           253: 
        !           254:        event_del(&peer->event);
        !           255:        imsg_clear(&peer->ibuf);
        !           256: 
        !           257:        close(peer->ibuf.fd);
        !           258:        free(peer);
        !           259: }
        !           260: 
        !           261: void
        !           262: proc_kill_peer(struct tmuxpeer *peer)
        !           263: {
        !           264:        peer->flags |= PEER_BAD;
        !           265: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>