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

Annotation of src/usr.bin/aucat/sock.c, Revision 1.31

1.31    ! ratchov     1: /*     $OpenBSD: sock.c,v 1.30 2009/10/05 07:05:24 ratchov Exp $       */
1.1       ratchov     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: /*
                     18:  * TODO:
                     19:  *
                     20:  *     change f->bufsz to contain only socket-side buffer,
                     21:  *     because it's less error prone
                     22:  */
                     23:
                     24: #include <stdio.h>
                     25: #include <stdlib.h>
                     26: #include <string.h>
1.20      ratchov    27:
                     28: #include "abuf.h"
1.1       ratchov    29: #include "aproc.h"
1.20      ratchov    30: #include "conf.h"
1.1       ratchov    31: #include "dev.h"
1.19      ratchov    32: #include "midi.h"
                     33: #include "opt.h"
1.20      ratchov    34: #include "sock.h"
1.1       ratchov    35:
                     36: int sock_attach(struct sock *, int);
                     37: int sock_read(struct sock *);
                     38: int sock_write(struct sock *);
                     39: int sock_execmsg(struct sock *);
                     40: void sock_reset(struct sock *);
                     41:
                     42: struct fileops sock_ops = {
                     43:        "sock",
                     44:        sizeof(struct sock),
                     45:                pipe_close,
                     46:        pipe_read,
                     47:        pipe_write,
                     48:        NULL, /* start */
                     49:        NULL, /* stop */
                     50:        pipe_nfds,
                     51:        pipe_pollfd,
                     52:        pipe_revents
                     53: };
1.30      ratchov    54:
1.1       ratchov    55:
                     56: void
                     57: rsock_done(struct aproc *p)
                     58: {
                     59:        struct sock *f = (struct sock *)p->u.io.file;
                     60:
1.11      ratchov    61:        if (f == NULL)
                     62:                return;
1.1       ratchov    63:        sock_reset(f);
                     64:        f->pipe.file.rproc = NULL;
                     65:        if (f->pipe.file.wproc) {
1.24      ratchov    66:                if (dev_midi && f->slot >= 0)
                     67:                        ctl_slotdel(dev_midi, f->slot);
1.1       ratchov    68:                aproc_del(f->pipe.file.wproc);
                     69:                file_del(&f->pipe.file);
                     70:        }
1.11      ratchov    71:        p->u.io.file = NULL;
1.1       ratchov    72: }
                     73:
                     74: int
                     75: rsock_in(struct aproc *p, struct abuf *ibuf_dummy)
                     76: {
                     77:        struct sock *f = (struct sock *)p->u.io.file;
                     78:        struct abuf *obuf;
                     79:
                     80:        if (!sock_read(f))
                     81:                return 0;
                     82:        obuf = LIST_FIRST(&p->obuflist);
                     83:        if (obuf) {
                     84:                if (!abuf_flush(obuf))
                     85:                        return 0;
                     86:        }
                     87:        return 1;
                     88: }
                     89:
                     90: int
                     91: rsock_out(struct aproc *p, struct abuf *obuf)
                     92: {
                     93:        struct sock *f = (struct sock *)p->u.io.file;
                     94:
1.19      ratchov    95:        if (f->pipe.file.state & FILE_RINUSE)
1.1       ratchov    96:                return 0;
                     97:
1.12      ratchov    98:        /*
1.20      ratchov    99:         * When calling sock_read(), we may receive a ``STOP'' command,
1.1       ratchov   100:         * and detach ``obuf''. In this case, there's no more caller and
1.20      ratchov   101:         * we'll stop processing further messages, resulting in a deadlock.
1.1       ratchov   102:         * The solution is to iterate over sock_read() in order to
                    103:         * consume all messages().
                    104:         */
                    105:        for (;;) {
                    106:                if (!sock_read(f))
1.12      ratchov   107:                        return 0;
1.1       ratchov   108:        }
                    109:        return 1;
                    110: }
                    111:
                    112: void
                    113: rsock_eof(struct aproc *p, struct abuf *ibuf_dummy)
                    114: {
                    115:        aproc_del(p);
                    116: }
                    117:
                    118: void
                    119: rsock_hup(struct aproc *p, struct abuf *ibuf)
                    120: {
                    121:        aproc_del(p);
                    122: }
                    123:
                    124: void
                    125: rsock_opos(struct aproc *p, struct abuf *obuf, int delta)
                    126: {
                    127:        struct sock *f = (struct sock *)p->u.io.file;
                    128:
1.15      ratchov   129:        if (f->mode & AMSG_REC)
1.14      ratchov   130:                return;
                    131:
                    132:        f->delta += delta;
1.1       ratchov   133:        /*
1.16      jakemsr   134:         * Negative deltas are xrun notifications for internal uses
                    135:         * only. Don't generate a packet for this, the client will be
1.1       ratchov   136:         * notified later.
                    137:         */
1.14      ratchov   138:        if (delta < 0)
1.1       ratchov   139:                return;
1.14      ratchov   140:        f->tickpending++;
1.1       ratchov   141:        for (;;) {
                    142:                if (!sock_write(f))
                    143:                        break;
                    144:        }
                    145: }
                    146:
                    147: struct aproc_ops rsock_ops = {
                    148:        "rsock",
                    149:        rsock_in,
                    150:        rsock_out,
                    151:        rsock_eof,
                    152:        rsock_hup,
                    153:        NULL, /* newin */
                    154:        NULL, /* newout */
                    155:        NULL, /* ipos */
                    156:        rsock_opos,
                    157:        rsock_done
                    158: };
                    159:
                    160: void
                    161: wsock_done(struct aproc *p)
                    162: {
                    163:        struct sock *f = (struct sock *)p->u.io.file;
                    164:
1.11      ratchov   165:        if (f == NULL)
                    166:                return;
1.1       ratchov   167:        sock_reset(f);
                    168:        f->pipe.file.wproc = NULL;
                    169:        if (f->pipe.file.rproc) {
1.24      ratchov   170:                if (dev_midi && f->slot >= 0)
                    171:                        ctl_slotdel(dev_midi, f->slot);
1.1       ratchov   172:                aproc_del(f->pipe.file.rproc);
                    173:                file_del(&f->pipe.file);
                    174:        }
1.11      ratchov   175:        p->u.io.file = NULL;
1.1       ratchov   176: }
                    177:
                    178: int
                    179: wsock_in(struct aproc *p, struct abuf *ibuf)
                    180: {
                    181:        struct sock *f = (struct sock *)p->u.io.file;
                    182:
1.19      ratchov   183:        if (f->pipe.file.state & FILE_WINUSE)
1.1       ratchov   184:                return 0;
                    185:        /*
1.20      ratchov   186:         * See remark in rsock_out().
1.1       ratchov   187:         */
                    188:        for (;;) {
                    189:                if (!sock_write(f))
                    190:                        return 0;
                    191:        }
                    192:        return 1;
                    193: }
                    194:
                    195: int
                    196: wsock_out(struct aproc *p, struct abuf *obuf_dummy)
                    197: {
                    198:        struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
                    199:        struct sock *f = (struct sock *)p->u.io.file;
                    200:
                    201:        if (ibuf) {
                    202:                if (!abuf_fill(ibuf))
                    203:                        return 0;
                    204:        }
                    205:        if (!sock_write(f))
                    206:                return 0;
                    207:        return 1;
                    208: }
                    209:
                    210: void
                    211: wsock_eof(struct aproc *p, struct abuf *obuf)
                    212: {
                    213:        aproc_del(p);
                    214: }
                    215:
                    216: void
                    217: wsock_hup(struct aproc *p, struct abuf *obuf_dummy)
                    218: {
                    219:        aproc_del(p);
                    220: }
                    221:
                    222: void
                    223: wsock_ipos(struct aproc *p, struct abuf *obuf, int delta)
                    224: {
                    225:        struct sock *f = (struct sock *)p->u.io.file;
                    226:
1.14      ratchov   227:        if (!(f->mode & AMSG_REC))
                    228:                return;
1.1       ratchov   229:
1.14      ratchov   230:        f->delta += delta;
1.1       ratchov   231:        /*
1.16      jakemsr   232:         * Negative deltas are xrun notifications for internal uses
                    233:         * only. Don't generate a packet for this, the client will be
1.1       ratchov   234:         * notified later.
                    235:         */
1.14      ratchov   236:        if (delta < 0)
1.1       ratchov   237:                return;
1.14      ratchov   238:        f->tickpending++;
1.1       ratchov   239:        for (;;) {
                    240:                if (!sock_write(f))
                    241:                        break;
                    242:        }
                    243: }
                    244:
                    245: struct aproc_ops wsock_ops = {
                    246:        "wsock",
                    247:        wsock_in,
                    248:        wsock_out,
                    249:        wsock_eof,
                    250:        wsock_hup,
                    251:        NULL, /* newin */
                    252:        NULL, /* newout */
                    253:        wsock_ipos,
                    254:        NULL, /* opos */
                    255:        wsock_done
                    256: };
                    257:
                    258: /*
1.20      ratchov   259:  * Initialise socket in the SOCK_HELLO state with default
                    260:  * parameters.
1.1       ratchov   261:  */
                    262: struct sock *
1.19      ratchov   263: sock_new(struct fileops *ops, int fd)
1.1       ratchov   264: {
                    265:        struct aproc *rproc, *wproc;
                    266:        struct sock *f;
                    267:
1.19      ratchov   268:        f = (struct sock *)pipe_new(ops, fd, "sock");
1.13      ratchov   269:        if (f == NULL)
                    270:                return NULL;
1.18      ratchov   271:        f->pstate = SOCK_HELLO;
1.1       ratchov   272:        f->mode = 0;
1.19      ratchov   273:        f->opt = opt_byname("default");
                    274:        if (f->opt) {
1.31    ! ratchov   275:                if (dev_sub)
1.19      ratchov   276:                        f->wpar = f->opt->wpar;
1.31    ! ratchov   277:                if (dev_mix)
1.19      ratchov   278:                        f->rpar = f->opt->rpar;
1.1       ratchov   279:        }
                    280:        f->xrun = AMSG_IGNORE;
1.10      ratchov   281:        f->bufsz = dev_bufsz;
1.1       ratchov   282:        f->round = dev_round;
1.14      ratchov   283:        f->delta = 0;
                    284:        f->tickpending = 0;
1.25      ratchov   285:        f->vol = f->lastvol = MIDI_MAXCTL;
1.24      ratchov   286:        f->slot = -1;
1.1       ratchov   287:
1.19      ratchov   288:        wproc = aproc_new(&wsock_ops, f->pipe.file.name);
1.1       ratchov   289:        wproc->u.io.file = &f->pipe.file;
                    290:        f->pipe.file.wproc = wproc;
                    291:        f->wstate = SOCK_WIDLE;
                    292:        f->wtodo = 0xdeadbeef;
                    293:
1.19      ratchov   294:        rproc = aproc_new(&rsock_ops, f->pipe.file.name);
1.1       ratchov   295:        rproc->u.io.file = &f->pipe.file;
                    296:        f->pipe.file.rproc = rproc;
                    297:        f->rstate = SOCK_RMSG;
                    298:        f->rtodo = sizeof(struct amsg);
                    299:        return f;
                    300: }
                    301:
                    302: /*
1.20      ratchov   303:  * Free buffers.
1.1       ratchov   304:  */
                    305: void
                    306: sock_freebuf(struct sock *f)
                    307: {
                    308:        struct abuf *rbuf, *wbuf;
1.12      ratchov   309:
1.1       ratchov   310:        f->pstate = SOCK_INIT;
                    311:        rbuf = LIST_FIRST(&f->pipe.file.rproc->obuflist);
                    312:        if (rbuf)
                    313:                abuf_eof(rbuf);
                    314:        wbuf = LIST_FIRST(&f->pipe.file.wproc->ibuflist);
                    315:        if (wbuf)
                    316:                abuf_hup(wbuf);
                    317: }
                    318:
                    319: /*
1.20      ratchov   320:  * Allocate buffers, so client can start filling write-end.
1.1       ratchov   321:  */
                    322: void
                    323: sock_allocbuf(struct sock *f)
                    324: {
                    325:        struct abuf *rbuf = NULL, *wbuf = NULL;
                    326:
                    327:        if (f->mode & AMSG_PLAY) {
1.10      ratchov   328:                rbuf = abuf_new(f->bufsz, &f->rpar);
1.1       ratchov   329:                aproc_setout(f->pipe.file.rproc, rbuf);
                    330:        }
                    331:        if (f->mode & AMSG_REC) {
1.10      ratchov   332:                wbuf = abuf_new(f->bufsz, &f->wpar);
1.1       ratchov   333:                aproc_setin(f->pipe.file.wproc, wbuf);
                    334:        }
1.14      ratchov   335:        f->delta = 0;
                    336:        f->tickpending = 0;
1.1       ratchov   337:        f->pstate = SOCK_START;
                    338:        if (!(f->mode & AMSG_PLAY))
                    339:                (void)sock_attach(f, 0);
                    340: }
                    341:
                    342: /*
1.25      ratchov   343:  * Set volume. Callback invoked when volume is modified externally
1.3       ratchov   344:  */
                    345: void
1.25      ratchov   346: sock_setvol(void *arg, unsigned vol)
1.3       ratchov   347: {
1.25      ratchov   348:        struct sock *f = (struct sock *)arg;
1.3       ratchov   349:        struct abuf *rbuf;
1.12      ratchov   350:
1.3       ratchov   351:        f->vol = vol;
1.12      ratchov   352:        rbuf = LIST_FIRST(&f->pipe.file.rproc->obuflist);
1.3       ratchov   353:        if (!rbuf) {
                    354:                return;
                    355:        }
1.25      ratchov   356:        dev_setvol(rbuf, MIDI_TO_ADATA(vol));
1.3       ratchov   357: }
                    358:
                    359: /*
1.20      ratchov   360:  * Attach play and/or record buffers to dev_mix and/or dev_sub.
1.1       ratchov   361:  */
                    362: int
                    363: sock_attach(struct sock *f, int force)
                    364: {
                    365:        struct abuf *rbuf, *wbuf;
                    366:
                    367:        rbuf = LIST_FIRST(&f->pipe.file.rproc->obuflist);
                    368:        wbuf = LIST_FIRST(&f->pipe.file.wproc->ibuflist);
                    369:
                    370:        /*
1.20      ratchov   371:         * If in SOCK_START state, dont attach until
                    372:         * the buffer isn't completely filled.
1.1       ratchov   373:         */
                    374:        if (!force && rbuf && ABUF_WOK(rbuf))
                    375:                return 0;
1.12      ratchov   376:
1.1       ratchov   377:        f->pstate = SOCK_RUN;
                    378:
                    379:        /*
1.20      ratchov   380:         * Attach them to the device.
1.1       ratchov   381:         */
                    382:        dev_attach(f->pipe.file.name,
                    383:            (f->mode & AMSG_PLAY) ? rbuf : NULL, &f->rpar, f->xrun,
1.4       ratchov   384:            (f->mode & AMSG_REC)  ? wbuf : NULL, &f->wpar, f->xrun,
1.19      ratchov   385:            f->opt->maxweight);
1.3       ratchov   386:        if (f->mode & AMSG_PLAY)
1.25      ratchov   387:                dev_setvol(rbuf, MIDI_TO_ADATA(f->vol));
1.3       ratchov   388:
1.1       ratchov   389:        /*
1.20      ratchov   390:         * Send the initial position, if needed.
1.1       ratchov   391:         */
                    392:        for (;;) {
                    393:                if (!sock_write(f))
                    394:                        break;
                    395:        }
                    396:        return 1;
                    397: }
                    398:
                    399: void
                    400: sock_reset(struct sock *f)
                    401: {
                    402:        switch (f->pstate) {
                    403:        case SOCK_START:
                    404:                (void)sock_attach(f, 1);
                    405:                f->pstate = SOCK_RUN;
                    406:                /* PASSTHROUGH */
                    407:        case SOCK_RUN:
                    408:                sock_freebuf(f);
                    409:                f->pstate = SOCK_INIT;
                    410:                /* PASSTHROUGH */
                    411:        case SOCK_INIT:
                    412:                /* nothing yet */
                    413:                break;
                    414:        }
                    415: }
                    416:
                    417: /*
1.20      ratchov   418:  * Read a message from the file descriptor, return 1 if done, 0
                    419:  * otherwise. The message is stored in f->rmsg.
1.1       ratchov   420:  */
                    421: int
                    422: sock_rmsg(struct sock *f)
                    423: {
                    424:        unsigned count;
                    425:        unsigned char *data;
                    426:
                    427:        while (f->rtodo > 0) {
                    428:                if (!(f->pipe.file.state & FILE_ROK)) {
                    429:                        return 0;
                    430:                }
                    431:                data = (unsigned char *)&f->rmsg;
                    432:                data += sizeof(struct amsg) - f->rtodo;
                    433:                count = file_read(&f->pipe.file, data, f->rtodo);
                    434:                if (count == 0)
                    435:                        return 0;
                    436:                f->rtodo -= count;
                    437:        }
                    438:        return 1;
                    439: }
                    440:
                    441: /*
1.20      ratchov   442:  * Write a message to the file descriptor, return 1 if done, 0
1.1       ratchov   443:  * otherwise.  The "m" argument is f->rmsg or f->wmsg, and the "ptodo"
                    444:  * points to the f->rtodo or f->wtodo respectively.
                    445:  */
                    446: int
                    447: sock_wmsg(struct sock *f, struct amsg *m, unsigned *ptodo)
                    448: {
                    449:        unsigned count;
                    450:        unsigned char *data;
                    451:
                    452:        while (*ptodo > 0) {
                    453:                if (!(f->pipe.file.state & FILE_WOK)) {
                    454:                        return 0;
                    455:                }
                    456:                data = (unsigned char *)m;
                    457:                data += sizeof(struct amsg) - *ptodo;
                    458:                count = file_write(&f->pipe.file, data, *ptodo);
                    459:                if (count == 0)
                    460:                        return 0;
                    461:                *ptodo -= count;
                    462:        }
                    463:        return 1;
                    464: }
                    465:
                    466: /*
1.20      ratchov   467:  * Read data chunk from the file descriptor, return 1 if at least one
1.1       ratchov   468:  * byte was read, 0 if the file blocked.
                    469:  */
                    470: int
                    471: sock_rdata(struct sock *f)
                    472: {
                    473:        struct aproc *p;
                    474:        struct abuf *obuf;
                    475:        unsigned char *data;
                    476:        unsigned count, n;
                    477:
                    478:        p = f->pipe.file.rproc;
                    479:        obuf = LIST_FIRST(&p->obuflist);
1.19      ratchov   480:        if (obuf == NULL)
                    481:                return 0;
1.1       ratchov   482:        if (ABUF_FULL(obuf) || !(f->pipe.file.state & FILE_ROK))
                    483:                return 0;
                    484:        data = abuf_wgetblk(obuf, &count, 0);
1.19      ratchov   485:        if (f->pstate != SOCK_MIDI && count > f->rtodo)
1.1       ratchov   486:                count = f->rtodo;
                    487:        n = file_read(&f->pipe.file, data, count);
                    488:        if (n == 0)
                    489:                return 0;
                    490:        abuf_wcommit(obuf, n);
1.19      ratchov   491:        if (f->pstate != SOCK_MIDI)
                    492:                f->rtodo -= n;
1.1       ratchov   493:        return 1;
                    494: }
                    495:
                    496: /*
1.20      ratchov   497:  * Write data chunk to the file descriptor, return 1 if at least one
1.1       ratchov   498:  * byte was written, 0 if the file blocked.
                    499:  */
                    500: int
                    501: sock_wdata(struct sock *f)
                    502: {
                    503:        struct aproc *p;
                    504:        struct abuf *ibuf;
                    505:        unsigned char *data;
                    506:        unsigned count, n;
                    507: #define ZERO_MAX 0x1000
                    508:        static char zero[ZERO_MAX];
                    509:
                    510:        if (!(f->pipe.file.state & FILE_WOK))
                    511:                return 0;
                    512:        p = f->pipe.file.wproc;
                    513:        ibuf = LIST_FIRST(&p->ibuflist);
                    514:        if (ibuf) {
                    515:                if (ABUF_EMPTY(ibuf))
                    516:                        return 0;
                    517:                data = abuf_rgetblk(ibuf, &count, 0);
1.19      ratchov   518:                if (f->pstate != SOCK_MIDI && count > f->wtodo)
1.1       ratchov   519:                        count = f->wtodo;
                    520:                n = file_write(&f->pipe.file, data, count);
                    521:                if (n == 0)
                    522:                        return 0;
                    523:                abuf_rdiscard(ibuf, n);
1.19      ratchov   524:                if (f->pstate != SOCK_MIDI)
                    525:                        f->wtodo -= n;
1.1       ratchov   526:        } else {
1.19      ratchov   527:                if (f->pstate == SOCK_MIDI)
                    528:                        return 0;
1.1       ratchov   529:                /*
1.20      ratchov   530:                 * There's no dev_detach() routine yet,
1.1       ratchov   531:                 * so now we abruptly destroy the buffer.
                    532:                 * Until we implement dev_detach, complete
                    533:                 * the packet with zeros...
                    534:                 */
                    535:                count = ZERO_MAX;
                    536:                if (count > f->wtodo)
                    537:                        count = f->wtodo;
                    538:                n = file_write(&f->pipe.file, zero, count);
                    539:                if (n == 0)
                    540:                        return 0;
                    541:                f->wtodo -= n;
1.12      ratchov   542:        }
1.1       ratchov   543:        return 1;
                    544: }
                    545:
                    546: int
                    547: sock_setpar(struct sock *f)
                    548: {
                    549:        struct amsg_par *p = &f->rmsg.u.par;
1.9       ratchov   550:        unsigned min, max, rate;
1.12      ratchov   551:
1.18      ratchov   552:        if (AMSG_ISSET(p->legacy_mode)) {
                    553:                /*
1.29      ratchov   554:                 * allow old clients that don't support HELLO to work
                    555:                 * XXX: remove this.
1.18      ratchov   556:                 */
                    557:                if ((p->legacy_mode & ~(AMSG_PLAY | AMSG_REC)) ||
                    558:                    (p->legacy_mode == 0)) {
1.1       ratchov   559:                        return 0;
                    560:                }
                    561:                f->mode = 0;
1.18      ratchov   562:                if ((p->legacy_mode & AMSG_PLAY) && dev_mix)
1.1       ratchov   563:                        f->mode |= AMSG_PLAY;
1.18      ratchov   564:                if ((p->legacy_mode & AMSG_REC) && dev_sub)
1.1       ratchov   565:                        f->mode |= AMSG_REC;
                    566:        }
                    567:        if (AMSG_ISSET(p->bits)) {
                    568:                if (p->bits < BITS_MIN || p->bits > BITS_MAX) {
                    569:                        return 0;
                    570:                }
                    571:                if (AMSG_ISSET(p->bps)) {
                    572:                        if (p->bps < ((p->bits + 7) / 8) || p->bps > 4) {
                    573:                                return 0;
                    574:                        }
                    575:                } else
                    576:                        p->bps = APARAMS_BPS(p->bits);
                    577:                f->rpar.bits = f->wpar.bits = p->bits;
                    578:                f->rpar.bps = f->wpar.bps = p->bps;
                    579:        }
                    580:        if (AMSG_ISSET(p->sig))
                    581:                f->rpar.sig = f->wpar.sig = p->sig ? 1 : 0;
                    582:        if (AMSG_ISSET(p->le))
                    583:                f->rpar.le = f->wpar.le = p->le ? 1 : 0;
                    584:        if (AMSG_ISSET(p->msb))
                    585:                f->rpar.msb = f->wpar.msb = p->msb ? 1 : 0;
                    586:        if (AMSG_ISSET(p->rchan) && (f->mode & AMSG_REC)) {
                    587:                if (p->rchan < 1)
                    588:                        p->rchan = 1;
1.6       ratchov   589:                if (p->rchan > NCHAN_MAX)
                    590:                        p->rchan = NCHAN_MAX;
1.19      ratchov   591:                f->wpar.cmin = f->opt->wpar.cmin;
                    592:                f->wpar.cmax = f->opt->wpar.cmin + p->rchan - 1;
                    593:                if (f->wpar.cmax > f->opt->wpar.cmax)
                    594:                        f->wpar.cmax = f->opt->wpar.cmax;
1.1       ratchov   595:        }
                    596:        if (AMSG_ISSET(p->pchan) && (f->mode & AMSG_PLAY)) {
                    597:                if (p->pchan < 1)
                    598:                        p->pchan = 1;
1.6       ratchov   599:                if (p->pchan > NCHAN_MAX)
                    600:                        p->pchan = NCHAN_MAX;
1.19      ratchov   601:                f->rpar.cmin = f->opt->rpar.cmin;
                    602:                f->rpar.cmax = f->opt->rpar.cmin + p->pchan - 1;
                    603:                if (f->rpar.cmax > f->opt->rpar.cmax)
                    604:                        f->rpar.cmax = f->opt->rpar.cmax;
1.1       ratchov   605:        }
                    606:        if (AMSG_ISSET(p->rate)) {
                    607:                if (p->rate < RATE_MIN)
                    608:                        p->rate = RATE_MIN;
                    609:                if (p->rate > RATE_MAX)
                    610:                        p->rate = RATE_MAX;
1.9       ratchov   611:                f->round = dev_roundof(p->rate);
1.1       ratchov   612:                f->rpar.rate = f->wpar.rate = p->rate;
1.10      ratchov   613:                if (!AMSG_ISSET(p->appbufsz)) {
                    614:                        p->appbufsz = dev_bufsz / dev_round * f->round;
                    615:                }
1.1       ratchov   616:        }
                    617:        if (AMSG_ISSET(p->xrun)) {
                    618:                if (p->xrun != AMSG_IGNORE &&
                    619:                    p->xrun != AMSG_SYNC &&
                    620:                    p->xrun != AMSG_ERROR) {
                    621:                        return 0;
                    622:                }
                    623:                f->xrun = p->xrun;
                    624:        }
                    625:        if (AMSG_ISSET(p->bufsz)) {
1.10      ratchov   626:                /*
                    627:                 * XXX: bufsz will become read-only, but for now
                    628:                 *      allow old library to properly work
                    629:                 */
                    630:                min = (dev_bufsz / dev_round) * f->round;
                    631:                if (p->bufsz < min)
                    632:                        p->bufsz = min;
                    633:                p->appbufsz = p->bufsz - min;
                    634:        }
                    635:        if (AMSG_ISSET(p->appbufsz)) {
1.9       ratchov   636:                rate = (f->mode & AMSG_PLAY) ? f->rpar.rate : f->wpar.rate;
1.10      ratchov   637:                min = 1;
                    638:                max = 1 + rate / dev_round;
1.9       ratchov   639:                min *= f->round;
                    640:                max *= f->round;
1.10      ratchov   641:                p->appbufsz += f->round - 1;
                    642:                p->appbufsz -= p->appbufsz % f->round;
                    643:                if (p->appbufsz < min)
                    644:                        p->appbufsz = min;
                    645:                if (p->appbufsz > max)
                    646:                        p->appbufsz = max;
                    647:                f->bufsz = p->appbufsz;
1.1       ratchov   648:        }
                    649:        return 1;
                    650: }
                    651:
1.19      ratchov   652: /*
                    653:  * allocate buffers, so client can start filling write-end.
                    654:  */
                    655: void
                    656: sock_midiattach(struct sock *f, unsigned mode)
                    657: {
                    658:        struct abuf *rbuf = NULL, *wbuf = NULL;
                    659:
                    660:        if (mode & AMSG_MIDIOUT) {
1.22      ratchov   661:                rbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
1.19      ratchov   662:                aproc_setout(f->pipe.file.rproc, rbuf);
                    663:        }
                    664:        if (mode & AMSG_MIDIIN) {
1.22      ratchov   665:                wbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
1.19      ratchov   666:                aproc_setin(f->pipe.file.wproc, wbuf);
                    667:        }
1.23      ratchov   668:        dev_midiattach(rbuf, wbuf);
1.19      ratchov   669: }
                    670:
1.17      ratchov   671: int
                    672: sock_hello(struct sock *f)
                    673: {
                    674:        struct amsg_hello *p = &f->rmsg.u.hello;
                    675:
1.29      ratchov   676:        /* XXX : set file name to p->who */
                    677:        /* XXX : dev_midi can no longer be NULL, right ? */
1.19      ratchov   678:
1.23      ratchov   679:        if (dev_midi && (p->proto & (AMSG_MIDIIN | AMSG_MIDIOUT))) {
1.19      ratchov   680:                if (p->proto & ~(AMSG_MIDIIN | AMSG_MIDIOUT)) {
                    681:                        return 0;
                    682:                }
                    683:                f->mode = p->proto;
                    684:                f->pstate = SOCK_MIDI;
                    685:                sock_midiattach(f, p->proto);
                    686:                return 1;
                    687:        }
                    688:        f->opt = opt_byname(p->opt);
                    689:        if (f->opt == NULL)
                    690:                return 0;
1.31    ! ratchov   691:        if (dev_sub)
1.19      ratchov   692:                f->wpar = f->opt->wpar;
1.31    ! ratchov   693:        if (dev_mix)
1.19      ratchov   694:                f->rpar = f->opt->rpar;
1.18      ratchov   695:        if ((p->proto & ~(AMSG_PLAY | AMSG_REC)) != 0 ||
                    696:            (p->proto &  (AMSG_PLAY | AMSG_REC)) == 0) {
1.17      ratchov   697:                return 0;
                    698:        }
1.18      ratchov   699:        f->mode = 0;
                    700:        if (p->proto & AMSG_PLAY) {
                    701:                if (!dev_mix) {
                    702:                        return 0;
                    703:                }
                    704:                f->mode |= AMSG_PLAY;
1.17      ratchov   705:        }
1.18      ratchov   706:        if (p->proto & AMSG_REC) {
                    707:                if (!dev_sub) {
                    708:                        return 0;
                    709:                }
                    710:                f->mode |= AMSG_REC;
1.17      ratchov   711:        }
1.24      ratchov   712:        if (dev_midi) {
1.25      ratchov   713:                f->slot = ctl_slotnew(dev_midi, p->who, sock_setvol, f);
1.24      ratchov   714:                if (f->slot < 0) {
                    715:                        return 0;
                    716:                }
                    717:        }
1.18      ratchov   718:        f->pstate = SOCK_INIT;
1.17      ratchov   719:        return 1;
                    720: }
                    721:
1.1       ratchov   722: /*
1.20      ratchov   723:  * Execute message in f->rmsg and change the state accordingly; return 1
1.1       ratchov   724:  * on success, and 0 on failure, in which case the socket is destroyed.
                    725:  */
                    726: int
                    727: sock_execmsg(struct sock *f)
                    728: {
                    729:        struct amsg *m = &f->rmsg;
                    730:
1.18      ratchov   731:        /*
1.19      ratchov   732:         * XXX: allow old clients to work without hello on the default socket
1.18      ratchov   733:         */
1.19      ratchov   734:        if (f->pstate == SOCK_HELLO && m->cmd != AMSG_HELLO && f->opt != NULL) {
1.18      ratchov   735:                f->pstate = SOCK_INIT;
                    736:        }
                    737:
1.1       ratchov   738:        switch (m->cmd) {
                    739:        case AMSG_DATA:
                    740:                if (f->pstate != SOCK_RUN && f->pstate != SOCK_START) {
1.8       ratchov   741:                        aproc_del(f->pipe.file.rproc);
                    742:                        return 0;
                    743:                }
                    744:                if (!(f->mode & AMSG_PLAY)) {
1.1       ratchov   745:                        aproc_del(f->pipe.file.rproc);
                    746:                        return 0;
                    747:                }
                    748:                f->rstate = SOCK_RDATA;
                    749:                f->rtodo = m->u.data.size;
                    750:                if (f->rtodo == 0) {
                    751:                        aproc_del(f->pipe.file.rproc);
                    752:                        return 0;
                    753:                }
                    754:                break;
                    755:        case AMSG_START:
                    756:                if (f->pstate != SOCK_INIT) {
                    757:                        aproc_del(f->pipe.file.rproc);
                    758:                        return 0;
                    759:                }
                    760:                sock_allocbuf(f);
                    761:                f->rstate = SOCK_RMSG;
                    762:                f->rtodo = sizeof(struct amsg);
                    763:                break;
                    764:        case AMSG_STOP:
                    765:                if (f->pstate != SOCK_RUN && f->pstate != SOCK_START) {
                    766:                        aproc_del(f->pipe.file.rproc);
                    767:                        return 0;
                    768:                }
                    769:                if (f->pstate == SOCK_START)
                    770:                        (void)sock_attach(f, 1);
                    771:                sock_freebuf(f);
                    772:                AMSG_INIT(m);
                    773:                m->cmd = AMSG_ACK;
                    774:                f->rstate = SOCK_RRET;
                    775:                f->rtodo = sizeof(struct amsg);
                    776:                break;
                    777:        case AMSG_SETPAR:
                    778:                if (f->pstate != SOCK_INIT) {
                    779:                        aproc_del(f->pipe.file.rproc);
                    780:                        return 0;
                    781:                }
                    782:                if (!sock_setpar(f)) {
                    783:                        aproc_del(f->pipe.file.rproc);
                    784:                        return 0;
                    785:                }
                    786:                f->rtodo = sizeof(struct amsg);
                    787:                f->rstate = SOCK_RMSG;
                    788:                break;
                    789:        case AMSG_GETPAR:
                    790:                if (f->pstate != SOCK_INIT) {
                    791:                        aproc_del(f->pipe.file.rproc);
                    792:                        return 0;
                    793:                }
                    794:                AMSG_INIT(m);
                    795:                m->cmd = AMSG_GETPAR;
1.18      ratchov   796:                m->u.par.legacy_mode = f->mode;
1.1       ratchov   797:                m->u.par.bits = f->rpar.bits;
                    798:                m->u.par.bps = f->rpar.bps;
                    799:                m->u.par.sig = f->rpar.sig;
                    800:                m->u.par.le = f->rpar.le;
                    801:                m->u.par.msb = f->rpar.msb;
                    802:                m->u.par.rate = f->rpar.rate;
                    803:                m->u.par.rchan = f->wpar.cmax - f->wpar.cmin + 1;
                    804:                m->u.par.pchan = f->rpar.cmax - f->rpar.cmin + 1;
1.10      ratchov   805:                m->u.par.appbufsz = f->bufsz;
1.12      ratchov   806:                m->u.par.bufsz =
1.10      ratchov   807:                    f->bufsz + (dev_bufsz / dev_round) * f->round;
1.1       ratchov   808:                m->u.par.round = f->round;
                    809:                f->rstate = SOCK_RRET;
                    810:                f->rtodo = sizeof(struct amsg);
                    811:                break;
                    812:        case AMSG_GETCAP:
                    813:                if (f->pstate != SOCK_INIT) {
                    814:                        aproc_del(f->pipe.file.rproc);
                    815:                        return 0;
                    816:                }
                    817:                AMSG_INIT(m);
                    818:                m->cmd = AMSG_GETCAP;
                    819:                m->u.cap.rate = dev_rate;
1.6       ratchov   820:                m->u.cap.pchan = dev_mix ?
1.19      ratchov   821:                    (f->opt->rpar.cmax - f->opt->rpar.cmin + 1) : 0;
1.6       ratchov   822:                m->u.cap.rchan = dev_sub ?
1.19      ratchov   823:                    (f->opt->wpar.cmax - f->opt->wpar.cmin + 1) : 0;
1.1       ratchov   824:                m->u.cap.bits = sizeof(short) * 8;
                    825:                m->u.cap.bps = sizeof(short);
                    826:                f->rstate = SOCK_RRET;
                    827:                f->rtodo = sizeof(struct amsg);
1.3       ratchov   828:                break;
                    829:        case AMSG_SETVOL:
                    830:                if (f->pstate != SOCK_RUN &&
                    831:                    f->pstate != SOCK_START && f->pstate != SOCK_INIT) {
                    832:                        aproc_del(f->pipe.file.rproc);
                    833:                        return 0;
                    834:                }
                    835:                if (m->u.vol.ctl > MIDI_MAXCTL) {
                    836:                        aproc_del(f->pipe.file.rproc);
                    837:                        return 0;
                    838:                }
1.25      ratchov   839:                sock_setvol(f, m->u.vol.ctl);
1.24      ratchov   840:                if (dev_midi && f->slot >= 0)
                    841:                        ctl_slotvol(dev_midi, f->slot, m->u.vol.ctl);
1.3       ratchov   842:                f->rtodo = sizeof(struct amsg);
                    843:                f->rstate = SOCK_RMSG;
1.17      ratchov   844:                break;
                    845:        case AMSG_HELLO:
1.18      ratchov   846:                if (f->pstate != SOCK_HELLO) {
1.17      ratchov   847:                        aproc_del(f->pipe.file.rproc);
                    848:                        return 0;
                    849:                }
                    850:                if (!sock_hello(f)) {
                    851:                        aproc_del(f->pipe.file.rproc);
                    852:                        return 0;
                    853:                }
                    854:                AMSG_INIT(m);
                    855:                m->cmd = AMSG_ACK;
                    856:                f->rstate = SOCK_RRET;
                    857:                f->rtodo = sizeof(struct amsg);
1.1       ratchov   858:                break;
1.28      ratchov   859:        case AMSG_BYE:
1.29      ratchov   860:                if (f->pstate != SOCK_INIT) {
                    861:                }
1.28      ratchov   862:                aproc_del(f->pipe.file.rproc);
                    863:                return 0;
1.1       ratchov   864:        default:
                    865:                aproc_del(f->pipe.file.rproc);
                    866:                return 0;
                    867:        }
                    868:        if (f->rstate == SOCK_RRET) {
                    869:                if (f->wstate != SOCK_WIDLE ||
                    870:                    !sock_wmsg(f, &f->rmsg, &f->rtodo))
                    871:                        return 0;
1.19      ratchov   872:                if (f->pstate == SOCK_MIDI && (f->mode & AMSG_MIDIOUT)) {
                    873:                        f->rstate = SOCK_RDATA;
                    874:                        f->rtodo = 0;
                    875:                } else {
                    876:                        f->rstate = SOCK_RMSG;
                    877:                        f->rtodo = sizeof(struct amsg);
                    878:                }
1.1       ratchov   879:        }
                    880:        return 1;
                    881: }
                    882:
                    883: /*
1.20      ratchov   884:  * Create a new data/pos message.
1.1       ratchov   885:  */
                    886: int
                    887: sock_buildmsg(struct sock *f)
                    888: {
                    889:        struct aproc *p;
                    890:        struct abuf *ibuf;
1.12      ratchov   891:
1.19      ratchov   892:        if (f->pstate == SOCK_MIDI) {
                    893:                f->wstate = SOCK_WDATA;
                    894:                f->wtodo = 0;
                    895:                return 1;
                    896:        }
                    897:
1.1       ratchov   898:        /*
1.20      ratchov   899:         * If pos changed, build a MOVE message.
1.1       ratchov   900:         */
1.14      ratchov   901:        if (f->tickpending && f->delta >= 0) {
1.1       ratchov   902:                AMSG_INIT(&f->wmsg);
                    903:                f->wmsg.cmd = AMSG_MOVE;
1.14      ratchov   904:                f->wmsg.u.ts.delta = f->delta;
1.1       ratchov   905:                f->wtodo = sizeof(struct amsg);
                    906:                f->wstate = SOCK_WMSG;
1.14      ratchov   907:                f->delta = 0;
                    908:                f->tickpending = 0;
1.25      ratchov   909:                return 1;
                    910:        }
                    911:
                    912:        /*
                    913:         * if volume changed build a SETVOL message
                    914:         */
1.27      ratchov   915:        if (f->pstate >= SOCK_START && f->vol != f->lastvol) {
1.25      ratchov   916:                AMSG_INIT(&f->wmsg);
                    917:                f->wmsg.cmd = AMSG_SETVOL;
                    918:                f->wmsg.u.vol.ctl = f->vol;
                    919:                f->wtodo = sizeof(struct amsg);
                    920:                f->wstate = SOCK_WMSG;
                    921:                f->lastvol = f->vol;
1.1       ratchov   922:                return 1;
                    923:        }
                    924:
                    925:        /*
1.20      ratchov   926:         * If data available, build a DATA message.
1.1       ratchov   927:         */
                    928:        p = f->pipe.file.wproc;
                    929:        ibuf = LIST_FIRST(&p->ibuflist);
                    930:        if (ibuf && ABUF_ROK(ibuf)) {
                    931:                AMSG_INIT(&f->wmsg);
                    932:                f->wmsg.cmd = AMSG_DATA;
                    933:                f->wmsg.u.data.size = ibuf->used - (ibuf->used % ibuf->bpf);
                    934:                if (f->wmsg.u.data.size > AMSG_DATAMAX)
                    935:                        f->wmsg.u.data.size =
                    936:                            AMSG_DATAMAX - (AMSG_DATAMAX % ibuf->bpf);
                    937:                f->wtodo = sizeof(struct amsg);
                    938:                f->wstate = SOCK_WMSG;
                    939:                return 1;
                    940:        }
                    941:        f->wstate = SOCK_WIDLE;
                    942:        return 0;
                    943: }
                    944:
                    945: /*
1.20      ratchov   946:  * Read from the socket file descriptor, fill input buffer and update
1.1       ratchov   947:  * the state. Return 1 if at least one message or 1 data byte was
                    948:  * processed, 0 if something blocked.
                    949:  */
                    950: int
                    951: sock_read(struct sock *f)
                    952: {
                    953:        switch (f->rstate) {
                    954:        case SOCK_RMSG:
                    955:                if (!sock_rmsg(f))
                    956:                        return 0;
                    957:                if (!sock_execmsg(f))
                    958:                        return 0;
                    959:                break;
                    960:        case SOCK_RDATA:
                    961:                if (!sock_rdata(f))
                    962:                        return 0;
1.19      ratchov   963:                if (f->pstate != SOCK_MIDI && f->rtodo == 0) {
1.1       ratchov   964:                        f->rstate = SOCK_RMSG;
                    965:                        f->rtodo = sizeof(struct amsg);
                    966:                }
                    967:                if (f->pstate == SOCK_START)
                    968:                        (void)sock_attach(f, 0);
                    969:                break;
                    970:        case SOCK_RRET:
                    971:                return 0;
                    972:        }
                    973:        return 1;
                    974: }
                    975:
                    976: /*
1.20      ratchov   977:  * Process messages to return.
1.1       ratchov   978:  */
                    979: int
                    980: sock_return(struct sock *f)
                    981: {
                    982:        struct aproc *rp;
                    983:
                    984:        while (f->rstate == SOCK_RRET) {
                    985:                if (!sock_wmsg(f, &f->rmsg, &f->rtodo))
                    986:                        return 0;
1.19      ratchov   987:                if (f->pstate == SOCK_MIDI && (f->mode & AMSG_MIDIOUT)) {
                    988:                        f->rstate = SOCK_RDATA;
                    989:                        f->rtodo = 0;
                    990:                } else {
                    991:                        f->rstate = SOCK_RMSG;
                    992:                        f->rtodo = sizeof(struct amsg);
                    993:                }
                    994:                if (f->pipe.file.state & FILE_RINUSE)
                    995:                        break;
                    996:                f->pipe.file.state |= FILE_RINUSE;
1.1       ratchov   997:                for (;;) {
                    998:                        /*
                    999:                         * in() may trigger rsock_done and destroy the
1.20      ratchov  1000:                         * wsock.
1.1       ratchov  1001:                         */
                   1002:                        rp = f->pipe.file.rproc;
                   1003:                        if (!rp || !rp->ops->in(rp, NULL))
                   1004:                                break;
                   1005:                }
1.19      ratchov  1006:                f->pipe.file.state &= ~FILE_RINUSE;
1.1       ratchov  1007:                if (f->pipe.file.wproc == NULL)
                   1008:                        return 0;
                   1009:        }
                   1010:        return 1;
                   1011: }
                   1012:
                   1013: /*
1.20      ratchov  1014:  * Write messages and data on the socket file descriptor. Return 1 if
1.1       ratchov  1015:  * at least one message or one data byte was processed, 0 if something
                   1016:  * blocked.
                   1017:  */
                   1018: int
                   1019: sock_write(struct sock *f)
                   1020: {
                   1021:        switch (f->wstate) {
                   1022:        case SOCK_WMSG:
                   1023:                if (!sock_wmsg(f, &f->wmsg, &f->wtodo))
                   1024:                        return 0;
                   1025:                if (f->wmsg.cmd != AMSG_DATA) {
                   1026:                        f->wstate = SOCK_WIDLE;
                   1027:                        f->wtodo = 0xdeadbeef;
                   1028:                        break;
                   1029:                }
                   1030:                f->wstate = SOCK_WDATA;
                   1031:                f->wtodo = f->wmsg.u.data.size;
                   1032:                /* PASSTHROUGH */
                   1033:        case SOCK_WDATA:
                   1034:                if (!sock_wdata(f))
                   1035:                        return 0;
1.19      ratchov  1036:                if (f->pstate == SOCK_MIDI || f->wtodo > 0)
1.1       ratchov  1037:                        break;
                   1038:                f->wstate = SOCK_WIDLE;
                   1039:                f->wtodo = 0xdeadbeef;
                   1040:                /* PASSTHROUGH */
                   1041:        case SOCK_WIDLE:
                   1042:                if (!sock_return(f))
                   1043:                        return 0;
                   1044:                if (!sock_buildmsg(f))
                   1045:                        return 0;
                   1046:                break;
                   1047:        }
                   1048:        return 1;
                   1049: }