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

Annotation of src/usr.bin/sndiod/sock.c, Revision 1.32

1.32    ! ratchov     1: /*     $OpenBSD: sock.c,v 1.31 2019/07/12 06:30:55 ratchov Exp $       */
1.1       ratchov     2: /*
                      3:  * Copyright (c) 2008-2012 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 <netinet/in.h>
                     19: #include <errno.h>
                     20: #include <poll.h>
                     21: #include <stdio.h>
                     22: #include <stdlib.h>
                     23: #include <string.h>
                     24: #include <unistd.h>
                     25:
                     26: #include "abuf.h"
                     27: #include "defs.h"
                     28: #include "dev.h"
                     29: #include "file.h"
                     30: #include "midi.h"
                     31: #include "opt.h"
                     32: #include "sock.h"
                     33: #include "utils.h"
                     34:
1.32    ! ratchov    35: #define SOCK_CTLDESC_SIZE      16      /* number of entries in s->ctldesc */
        !            36:
1.7       ratchov    37: void sock_log(struct sock *);
1.1       ratchov    38: void sock_close(struct sock *);
                     39: void sock_slot_fill(void *);
                     40: void sock_slot_flush(void *);
                     41: void sock_slot_eof(void *);
1.12      ratchov    42: void sock_slot_onmove(void *);
1.18      ratchov    43: void sock_slot_onvol(void *);
1.7       ratchov    44: void sock_midi_imsg(void *, unsigned char *, int);
                     45: void sock_midi_omsg(void *, unsigned char *, int);
                     46: void sock_midi_fill(void *, int);
                     47: struct sock *sock_new(int);
1.1       ratchov    48: void sock_exit(void *);
1.7       ratchov    49: int sock_fdwrite(struct sock *, void *, int);
                     50: int sock_fdread(struct sock *, void *, int);
                     51: int sock_rmsg(struct sock *);
                     52: int sock_wmsg(struct sock *);
                     53: int sock_rdata(struct sock *);
                     54: int sock_wdata(struct sock *);
                     55: int sock_setpar(struct sock *);
                     56: int sock_auth(struct sock *);
                     57: int sock_hello(struct sock *);
                     58: int sock_execmsg(struct sock *);
                     59: int sock_buildmsg(struct sock *);
                     60: int sock_read(struct sock *);
                     61: int sock_write(struct sock *);
                     62: int sock_pollfd(void *, struct pollfd *);
                     63: int sock_revents(void *, struct pollfd *);
                     64: void sock_in(void *);
                     65: void sock_out(void *);
                     66: void sock_hup(void *);
1.1       ratchov    67:
                     68: struct fileops sock_fileops = {
                     69:        "sock",
                     70:        sock_pollfd,
                     71:        sock_revents,
                     72:        sock_in,
                     73:        sock_out,
                     74:        sock_hup
                     75: };
                     76:
                     77: struct slotops sock_slotops = {
                     78:        sock_slot_onmove,
                     79:        sock_slot_onvol,
                     80:        sock_slot_fill,
                     81:        sock_slot_flush,
                     82:        sock_slot_eof,
                     83:        sock_exit
                     84: };
                     85:
                     86: struct midiops sock_midiops = {
                     87:        sock_midi_imsg,
                     88:        sock_midi_omsg,
                     89:        sock_midi_fill,
                     90:        sock_exit
                     91: };
                     92:
1.32    ! ratchov    93: struct ctlops sock_ctlops = {
        !            94:        sock_exit
        !            95: };
        !            96:
1.1       ratchov    97: struct sock *sock_list = NULL;
                     98: unsigned int sock_sesrefs = 0;         /* connections to the session */
                     99: uint8_t sock_sescookie[AMSG_COOKIELEN];        /* owner of the session */
                    100:
                    101: void
                    102: sock_log(struct sock *f)
                    103: {
                    104: #ifdef DEBUG
                    105:        static char *rstates[] = { "ridl", "rmsg", "rdat", "rret" };
                    106:        static char *wstates[] = { "widl", "wmsg", "wdat" };
                    107: #endif
                    108:        if (f->slot)
                    109:                slot_log(f->slot);
                    110:        else if (f->midi)
                    111:                midi_log(f->midi);
1.32    ! ratchov   112:        else if (f->ctlslot) {
        !           113:                log_puts("ctlslot");
        !           114:                log_putu(f->ctlslot - f->ctlslot->dev->ctlslot);
        !           115:        } else
1.1       ratchov   116:                log_puts("sock");
                    117: #ifdef DEBUG
                    118:        if (log_level >= 3) {
                    119:                log_puts(",");
                    120:                log_puts(rstates[f->rstate]);
                    121:                log_puts(",");
                    122:                log_puts(wstates[f->wstate]);
                    123:        }
                    124: #endif
                    125: }
                    126:
                    127: void
                    128: sock_close(struct sock *f)
                    129: {
                    130:        struct sock **pf;
                    131:
                    132:        for (pf = &sock_list; *pf != f; pf = &(*pf)->next) {
                    133: #ifdef DEBUG
                    134:                if (*pf == NULL) {
                    135:                        log_puts("sock_close: not on list\n");
                    136:                        panic();
                    137:                }
                    138: #endif
                    139:        }
                    140:        *pf = f->next;
                    141:
                    142: #ifdef DEBUG
                    143:        if (log_level >= 3) {
                    144:                sock_log(f);
                    145:                log_puts(": closing\n");
                    146:        }
                    147: #endif
                    148:        if (f->pstate > SOCK_AUTH)
                    149:                sock_sesrefs--;
                    150:        if (f->slot) {
                    151:                slot_del(f->slot);
                    152:                f->slot = NULL;
                    153:        }
                    154:        if (f->midi) {
                    155:                midi_del(f->midi);
                    156:                f->midi = NULL;
                    157:        }
1.3       ratchov   158:        if (f->port) {
                    159:                port_unref(f->port);
                    160:                f->port = NULL;
                    161:        }
1.32    ! ratchov   162:        if (f->ctlslot) {
        !           163:                ctlslot_del(f->ctlslot);
        !           164:                f->ctlslot = NULL;
        !           165:                xfree(f->ctldesc);
        !           166:        }
1.1       ratchov   167:        file_del(f->file);
                    168:        close(f->fd);
1.16      ratchov   169:        file_slowaccept = 0;
1.1       ratchov   170:        xfree(f);
                    171: }
                    172:
                    173: void
                    174: sock_slot_fill(void *arg)
                    175: {
                    176:        struct sock *f = arg;
                    177:        struct slot *s = f->slot;
                    178:
                    179:        f->fillpending += s->round;
                    180: #ifdef DEBUG
                    181:        if (log_level >= 4) {
                    182:                sock_log(f);
                    183:                log_puts(": fill, rmax -> ");
                    184:                log_puti(f->rmax);
                    185:                log_puts(", pending -> ");
                    186:                log_puti(f->fillpending);
                    187:                log_puts("\n");
                    188:        }
                    189: #endif
                    190: }
                    191:
                    192: void
                    193: sock_slot_flush(void *arg)
                    194: {
                    195:        struct sock *f = arg;
                    196:        struct slot *s = f->slot;
                    197:
                    198:        f->wmax += s->round * s->sub.bpf;
                    199: #ifdef DEBUG
                    200:        if (log_level >= 4) {
                    201:                sock_log(f);
                    202:                log_puts(": flush, wmax -> ");
                    203:                log_puti(f->wmax);
                    204:                log_puts("\n");
                    205:        }
                    206: #endif
                    207: }
                    208:
                    209: void
                    210: sock_slot_eof(void *arg)
                    211: {
                    212:        struct sock *f = arg;
                    213:
                    214: #ifdef DEBUG
                    215:        if (log_level >= 3) {
                    216:                sock_log(f);
                    217:                log_puts(": stopped\n");
                    218:        }
                    219: #endif
                    220:        f->stoppending = 1;
                    221: }
                    222:
                    223: void
1.12      ratchov   224: sock_slot_onmove(void *arg)
1.1       ratchov   225: {
                    226:        struct sock *f = (struct sock *)arg;
                    227:        struct slot *s = f->slot;
                    228:
                    229: #ifdef DEBUG
                    230:        if (log_level >= 4) {
                    231:                sock_log(f);
                    232:                log_puts(": onmove: delta -> ");
                    233:                log_puti(s->delta);
                    234:                log_puts("\n");
                    235:        }
                    236: #endif
                    237:        if (s->pstate != SOCK_START)
                    238:                return;
                    239:        f->tickpending++;
                    240: }
                    241:
                    242: void
1.18      ratchov   243: sock_slot_onvol(void *arg)
1.1       ratchov   244: {
                    245:        struct sock *f = (struct sock *)arg;
                    246:        struct slot *s = f->slot;
                    247:
                    248: #ifdef DEBUG
                    249:        if (log_level >= 4) {
                    250:                sock_log(f);
                    251:                log_puts(": onvol: vol -> ");
                    252:                log_puti(s->vol);
                    253:                log_puts("\n");
                    254:        }
                    255: #endif
                    256:        if (s->pstate != SOCK_START)
                    257:                return;
                    258: }
                    259:
                    260: void
                    261: sock_midi_imsg(void *arg, unsigned char *msg, int size)
                    262: {
                    263:        struct sock *f = arg;
                    264:
                    265:        midi_send(f->midi, msg, size);
                    266: }
                    267:
                    268: void
                    269: sock_midi_omsg(void *arg, unsigned char *msg, int size)
                    270: {
                    271:        struct sock *f = arg;
                    272:
                    273:        midi_out(f->midi, msg, size);
                    274: }
                    275:
                    276: void
                    277: sock_midi_fill(void *arg, int count)
                    278: {
                    279:        struct sock *f = arg;
                    280:
                    281:        f->fillpending += count;
                    282: }
                    283:
                    284: struct sock *
                    285: sock_new(int fd)
                    286: {
                    287:        struct sock *f;
                    288:
                    289:        f = xmalloc(sizeof(struct sock));
                    290:        f->pstate = SOCK_AUTH;
                    291:        f->slot = NULL;
1.13      ratchov   292:        f->port = NULL;
1.1       ratchov   293:        f->midi = NULL;
1.32    ! ratchov   294:        f->ctlslot = NULL;
1.1       ratchov   295:        f->tickpending = 0;
                    296:        f->fillpending = 0;
                    297:        f->stoppending = 0;
                    298:        f->wstate = SOCK_WIDLE;
                    299:        f->wtodo = 0xdeadbeef;
                    300:        f->rstate = SOCK_RMSG;
                    301:        f->rtodo = sizeof(struct amsg);
                    302:        f->wmax = f->rmax = 0;
                    303:        f->lastvol = -1;
1.32    ! ratchov   304:        f->ctlops = 0;
        !           305:        f->ctlsyncpending = 0;
1.1       ratchov   306:        f->file = file_new(&sock_fileops, f, "sock", 1);
                    307:        f->fd = fd;
                    308:        if (f->file == NULL) {
                    309:                xfree(f);
                    310:                return NULL;
                    311:        }
                    312:        f->next = sock_list;
                    313:        sock_list = f;
                    314:        return f;
                    315: }
                    316:
                    317: void
                    318: sock_exit(void *arg)
                    319: {
                    320:        struct sock *f = (struct sock *)arg;
                    321:
                    322: #ifdef DEBUG
                    323:        if (log_level >= 3) {
                    324:                sock_log(f);
                    325:                log_puts(": exit\n");
                    326:        }
                    327: #endif
                    328:        sock_close(f);
                    329: }
                    330:
                    331: /*
1.19      ratchov   332:  * write on the socket fd and handle errors
1.1       ratchov   333:  */
                    334: int
                    335: sock_fdwrite(struct sock *f, void *data, int count)
                    336: {
                    337:        int n;
                    338:
                    339:        n = write(f->fd, data, count);
1.30      ratchov   340:        if (n == -1) {
1.1       ratchov   341: #ifdef DEBUG
                    342:                if (errno == EFAULT) {
                    343:                        log_puts("sock_fdwrite: fault\n");
                    344:                        panic();
                    345:                }
                    346: #endif
                    347:                if (errno != EAGAIN) {
                    348:                        if (log_level >= 1) {
                    349:                                sock_log(f);
                    350:                                log_puts(": write filed, errno = ");
                    351:                                log_puti(errno);
                    352:                                log_puts("\n");
                    353:                        }
                    354:                        sock_close(f);
                    355:                } else {
1.17      ratchov   356: #ifdef DEBUG
1.1       ratchov   357:                        if (log_level >= 4) {
                    358:                                sock_log(f);
                    359:                                log_puts(": write blocked\n");
                    360:                        }
                    361: #endif
                    362:                }
                    363:                return 0;
                    364:        }
                    365:        if (n == 0) {
                    366:                sock_close(f);
                    367:                return 0;
                    368:        }
                    369:        return n;
                    370: }
                    371:
                    372: /*
1.19      ratchov   373:  * read from the socket fd and handle errors
1.1       ratchov   374:  */
                    375: int
                    376: sock_fdread(struct sock *f, void *data, int count)
                    377: {
                    378:        int n;
                    379:
                    380:        n = read(f->fd, data, count);
1.30      ratchov   381:        if (n == -1) {
1.1       ratchov   382: #ifdef DEBUG
                    383:                if (errno == EFAULT) {
                    384:                        log_puts("sock_fdread: fault\n");
                    385:                        panic();
                    386:                }
                    387: #endif
                    388:                if (errno != EAGAIN) {
                    389:                        if (log_level >= 1) {
                    390:                                sock_log(f);
                    391:                                log_puts(": read failed, errno = ");
                    392:                                log_puti(errno);
                    393:                                log_puts("\n");
                    394:                        }
                    395:                        sock_close(f);
                    396:                } else {
1.17      ratchov   397: #ifdef DEBUG
1.1       ratchov   398:                        if (log_level >= 4) {
                    399:                                sock_log(f);
                    400:                                log_puts(": read blocked\n");
                    401:                        }
                    402: #endif
                    403:                }
                    404:                return 0;
                    405:        }
                    406:        if (n == 0) {
                    407:                sock_close(f);
                    408:                return 0;
                    409:        }
                    410:        return n;
                    411: }
                    412:
                    413: /*
                    414:  * read the next message into f->rmsg, return 1 on success
                    415:  */
                    416: int
                    417: sock_rmsg(struct sock *f)
                    418: {
                    419:        int n;
                    420:        char *data;
                    421:
                    422: #ifdef DEBUG
                    423:        if (f->rtodo == 0) {
                    424:                sock_log(f);
                    425:                log_puts(": sock_rmsg: nothing to read\n");
                    426:                panic();
                    427:        }
                    428: #endif
                    429:        data = (char *)&f->rmsg + sizeof(struct amsg) - f->rtodo;
                    430:        n = sock_fdread(f, data, f->rtodo);
                    431:        if (n == 0)
                    432:                return 0;
                    433:        if (n < f->rtodo) {
                    434:                f->rtodo -= n;
                    435:                return 0;
                    436:        }
                    437:        f->rtodo = 0;
                    438: #ifdef DEBUG
                    439:        if (log_level >= 4) {
                    440:                sock_log(f);
                    441:                log_puts(": read full message\n");
                    442:        }
                    443: #endif
                    444:        return 1;
                    445: }
                    446:
                    447: /*
                    448:  * write the message in f->rmsg, return 1 on success
                    449:  */
                    450: int
                    451: sock_wmsg(struct sock *f)
                    452: {
                    453:        int n;
                    454:        char *data;
                    455:
                    456: #ifdef DEBUG
                    457:        if (f->wtodo == 0) {
                    458:                sock_log(f);
                    459:                log_puts(": sock_wmsg: already written\n");
                    460:        }
                    461: #endif
                    462:        data = (char *)&f->wmsg + sizeof(struct amsg) - f->wtodo;
                    463:        n = sock_fdwrite(f, data, f->wtodo);
                    464:        if (n == 0)
                    465:                return 0;
                    466:        if (n < f->wtodo) {
                    467:                f->wtodo -= n;
                    468:                return 0;
                    469:        }
                    470:        f->wtodo = 0;
                    471: #ifdef DEBUG
                    472:        if (log_level >= 4) {
                    473:                sock_log(f);
                    474:                log_puts(": wrote full message\n");
                    475:        }
                    476: #endif
                    477:        return 1;
                    478: }
                    479:
                    480: /*
                    481:  * read data into the slot/midi ring buffer
                    482:  */
                    483: int
                    484: sock_rdata(struct sock *f)
                    485: {
1.2       ratchov   486:        unsigned char midibuf[MIDI_BUFSZ];
1.1       ratchov   487:        unsigned char *data;
                    488:        int n, count;
                    489:
                    490: #ifdef DEBUG
                    491:        if (f->rtodo == 0) {
                    492:                sock_log(f);
                    493:                log_puts(": data block already read\n");
                    494:                panic();
                    495:        }
                    496: #endif
                    497:        while (f->rtodo > 0) {
1.2       ratchov   498:                if (f->slot)
                    499:                        data = abuf_wgetblk(&f->slot->mix.buf, &count);
                    500:                else {
                    501:                        data = midibuf;
                    502:                        count = MIDI_BUFSZ;
                    503:                }
1.1       ratchov   504:                if (count > f->rtodo)
                    505:                        count = f->rtodo;
                    506:                n = sock_fdread(f, data, count);
                    507:                if (n == 0)
                    508:                        return 0;
                    509:                f->rtodo -= n;
1.2       ratchov   510:                if (f->slot)
                    511:                        abuf_wcommit(&f->slot->mix.buf, n);
                    512:                else
                    513:                        midi_in(f->midi, midibuf, n);
1.1       ratchov   514:        }
                    515: #ifdef DEBUG
                    516:        if (log_level >= 4) {
                    517:                sock_log(f);
                    518:                log_puts(": read complete block\n");
                    519:        }
                    520: #endif
                    521:        if (f->slot)
                    522:                slot_write(f->slot);
                    523:        return 1;
                    524: }
                    525:
                    526: /*
1.19      ratchov   527:  * write data to the slot/midi ring buffer
1.1       ratchov   528:  */
                    529: int
                    530: sock_wdata(struct sock *f)
                    531: {
                    532:        static unsigned char dummy[AMSG_DATAMAX];
                    533:        unsigned char *data = NULL;
                    534:        int n, count;
                    535:
                    536: #ifdef DEBUG
                    537:        if (f->wtodo == 0) {
                    538:                sock_log(f);
                    539:                log_puts(": attempted to write zero-sized data block\n");
                    540:                panic();
                    541:        }
                    542: #endif
                    543:        if (f->pstate == SOCK_STOP) {
                    544:                while (f->wtodo > 0) {
                    545:                        n = sock_fdwrite(f, dummy, f->wtodo);
                    546:                        if (n == 0)
                    547:                                return 0;
                    548:                        f->wtodo -= n;
                    549:                }
                    550: #ifdef DEBUG
                    551:                if (log_level >= 4) {
                    552:                        sock_log(f);
                    553:                        log_puts(": zero-filled remaining block\n");
                    554:                }
                    555: #endif
                    556:                return 1;
                    557:        }
                    558:        while (f->wtodo > 0) {
1.20      ratchov   559:                /*
                    560:                 * f->slot and f->midi are set by sock_hello(), so
                    561:                 * count is always properly initialized
                    562:                 */
1.15      ratchov   563:                if (f->slot)
                    564:                        data = abuf_rgetblk(&f->slot->sub.buf, &count);
                    565:                else if (f->midi)
                    566:                        data = abuf_rgetblk(&f->midi->obuf, &count);
1.32    ! ratchov   567:                else {
        !           568:                        data = (unsigned char *)f->ctldesc +
        !           569:                            (f->wsize - f->wtodo);
        !           570:                        count = f->wtodo;
        !           571:                }
1.1       ratchov   572:                if (count > f->wtodo)
                    573:                        count = f->wtodo;
                    574:                n = sock_fdwrite(f, data, count);
                    575:                if (n == 0)
                    576:                        return 0;
                    577:                f->wtodo -= n;
1.15      ratchov   578:                if (f->slot)
                    579:                        abuf_rdiscard(&f->slot->sub.buf, n);
                    580:                else if (f->midi)
                    581:                        abuf_rdiscard(&f->midi->obuf, n);
1.1       ratchov   582:        }
                    583:        if (f->slot)
                    584:                slot_read(f->slot);
                    585:        if (f->midi)
                    586:                midi_fill(f->midi);
                    587: #ifdef DEBUG
                    588:        if (log_level >= 4) {
                    589:                sock_log(f);
                    590:                log_puts(": wrote complete block\n");
                    591:        }
                    592: #endif
                    593:        return 1;
                    594: }
                    595:
                    596: int
                    597: sock_setpar(struct sock *f)
                    598: {
                    599:        struct slot *s = f->slot;
                    600:        struct dev *d = s->dev;
                    601:        struct amsg_par *p = &f->rmsg.u.par;
1.9       ratchov   602:        unsigned int min, max;
                    603:        uint32_t rate, appbufsz;
                    604:        uint16_t pchan, rchan;
1.1       ratchov   605:
                    606:        rchan = ntohs(p->rchan);
                    607:        pchan = ntohs(p->pchan);
                    608:        appbufsz = ntohl(p->appbufsz);
                    609:        rate = ntohl(p->rate);
                    610:
                    611:        if (AMSG_ISSET(p->bits)) {
                    612:                if (p->bits < BITS_MIN || p->bits > BITS_MAX) {
                    613: #ifdef DEBUG
                    614:                        if (log_level >= 1) {
                    615:                                sock_log(f);
                    616:                                log_puts(": ");
                    617:                                log_putu(p->bits);
                    618:                                log_puts(": bits out of bounds\n");
                    619:                        }
                    620: #endif
                    621:                        return 0;
                    622:                }
                    623:                if (AMSG_ISSET(p->bps)) {
                    624:                        if (p->bps < ((p->bits + 7) / 8) || p->bps > 4) {
                    625: #ifdef DEBUG
                    626:                                if (log_level >= 1) {
                    627:                                        sock_log(f);
                    628:                                        log_puts(": ");
                    629:                                        log_putu(p->bps);
                    630:                                        log_puts(": wrong bytes per sample\n");
                    631:                                }
                    632: #endif
                    633:                                return 0;
                    634:                        }
                    635:                } else
                    636:                        p->bps = APARAMS_BPS(p->bits);
                    637:                s->par.bits = p->bits;
                    638:                s->par.bps = p->bps;
                    639:        }
                    640:        if (AMSG_ISSET(p->sig))
                    641:                s->par.sig = p->sig ? 1 : 0;
                    642:        if (AMSG_ISSET(p->le))
                    643:                s->par.le = p->le ? 1 : 0;
                    644:        if (AMSG_ISSET(p->msb))
                    645:                s->par.msb = p->msb ? 1 : 0;
                    646:        if (AMSG_ISSET(rchan) && (s->mode & MODE_RECMASK)) {
                    647:                if (rchan < 1)
                    648:                        rchan = 1;
1.21      ratchov   649:                else if (rchan > NCHAN_MAX)
1.1       ratchov   650:                        rchan = NCHAN_MAX;
1.28      ratchov   651:                s->sub.nch = rchan;
1.1       ratchov   652: #ifdef DEBUG
                    653:                if (log_level >= 3) {
                    654:                        sock_log(f);
                    655:                        log_puts(": recording channels ");
1.26      ratchov   656:                        log_putu(s->opt->rmin);
1.6       ratchov   657:                        log_puts(":");
1.26      ratchov   658:                        log_putu(s->opt->rmax);
1.6       ratchov   659:                        log_puts(" -> ");
1.27      ratchov   660:                        log_putu(s->opt->rmin);
1.1       ratchov   661:                        log_puts(":");
1.28      ratchov   662:                        log_putu(s->opt->rmin + s->sub.nch - 1);
1.1       ratchov   663:                        log_puts("\n");
                    664:                }
                    665: #endif
                    666:        }
                    667:        if (AMSG_ISSET(pchan) && (s->mode & MODE_PLAY)) {
                    668:                if (pchan < 1)
                    669:                        pchan = 1;
1.21      ratchov   670:                else if (pchan > NCHAN_MAX)
1.1       ratchov   671:                        pchan = NCHAN_MAX;
1.28      ratchov   672:                s->mix.nch = pchan;
1.1       ratchov   673: #ifdef DEBUG
                    674:                if (log_level >= 3) {
                    675:                        sock_log(f);
                    676:                        log_puts(": playback channels ");
1.27      ratchov   677:                        log_putu(s->opt->pmin);
1.1       ratchov   678:                        log_puts(":");
1.28      ratchov   679:                        log_putu(s->opt->pmin + s->mix.nch - 1);
1.1       ratchov   680:                        log_puts(" -> ");
1.26      ratchov   681:                        log_putu(s->opt->pmin);
1.1       ratchov   682:                        log_puts(":");
1.26      ratchov   683:                        log_putu(s->opt->pmax);
1.1       ratchov   684:                        log_puts("\n");
                    685:                }
                    686: #endif
                    687:        }
                    688:        if (AMSG_ISSET(rate)) {
                    689:                if (rate < RATE_MIN)
                    690:                        rate = RATE_MIN;
1.21      ratchov   691:                else if (rate > RATE_MAX)
1.1       ratchov   692:                        rate = RATE_MAX;
                    693:                s->round = dev_roundof(d, rate);
                    694:                s->rate = rate;
                    695:                if (!AMSG_ISSET(appbufsz)) {
                    696:                        appbufsz = d->bufsz / d->round * s->round;
                    697: #ifdef DEBUG
                    698:                        if (log_level >= 3) {
                    699:                                sock_log(f);
                    700:                                log_puts(": ");
                    701:                                log_putu(appbufsz);
                    702:                                log_puts(" frame buffer\n");
                    703:                        }
                    704: #endif
                    705:                }
                    706: #ifdef DEBUG
                    707:                if (log_level >= 3) {
                    708:                        sock_log(f);
                    709:                        log_puts(": ");
                    710:                        log_putu(rate);
                    711:                        log_puts("Hz sample rate, ");
                    712:                        log_putu(s->round);
                    713:                        log_puts(" frame blocks\n");
                    714:                }
                    715: #endif
                    716:        }
                    717:        if (AMSG_ISSET(p->xrun)) {
                    718:                if (p->xrun != XRUN_IGNORE &&
                    719:                    p->xrun != XRUN_SYNC &&
                    720:                    p->xrun != XRUN_ERROR) {
                    721: #ifdef DEBUG
                    722:                        if (log_level >= 1) {
                    723:                                sock_log(f);
                    724:                                log_puts(": ");
                    725:                                log_putx(p->xrun);
                    726:                                log_puts(": bad xrun policy\n");
                    727:                        }
                    728: #endif
                    729:                        return 0;
                    730:                }
                    731:                s->xrun = p->xrun;
1.23      ratchov   732:                if (s->opt->mmc && s->xrun == XRUN_IGNORE)
1.1       ratchov   733:                        s->xrun = XRUN_SYNC;
                    734: #ifdef DEBUG
                    735:                if (log_level >= 3) {
                    736:                        sock_log(f);
                    737:                        log_puts(": 0x");
                    738:                        log_putx(s->xrun);
                    739:                        log_puts(" xrun policy\n");
                    740:                }
                    741: #endif
                    742:        }
                    743:        if (AMSG_ISSET(appbufsz)) {
                    744:                rate = s->rate;
                    745:                min = 1;
                    746:                max = 1 + rate / d->round;
                    747:                min *= s->round;
                    748:                max *= s->round;
1.8       ratchov   749:                appbufsz += s->round / 2;
1.1       ratchov   750:                appbufsz -= appbufsz % s->round;
                    751:                if (appbufsz < min)
                    752:                        appbufsz = min;
                    753:                if (appbufsz > max)
                    754:                        appbufsz = max;
                    755:                s->appbufsz = appbufsz;
                    756: #ifdef DEBUG
                    757:                if (log_level >= 3) {
                    758:                        sock_log(f);
                    759:                        log_puts(": ");
                    760:                        log_putu(s->appbufsz);
                    761:                        log_puts(" frame buffer\n");
                    762:                }
                    763: #endif
                    764:        }
                    765:        return 1;
                    766: }
                    767:
                    768: int
                    769: sock_auth(struct sock *f)
                    770: {
                    771:        struct amsg_auth *p = &f->rmsg.u.auth;
                    772:
                    773:        if (sock_sesrefs == 0) {
                    774:                /* start a new session */
                    775:                memcpy(sock_sescookie, p->cookie, AMSG_COOKIELEN);
                    776:        } else if (memcmp(sock_sescookie, p->cookie, AMSG_COOKIELEN) != 0) {
                    777:                /* another session is active, drop connection */
                    778:                return 0;
                    779:        }
                    780:        sock_sesrefs++;
                    781:        f->pstate = SOCK_HELLO;
                    782:        return 1;
                    783: }
                    784:
                    785: int
                    786: sock_hello(struct sock *f)
                    787: {
                    788:        struct amsg_hello *p = &f->rmsg.u.hello;
                    789:        struct port *c;
                    790:        struct dev *d;
1.23      ratchov   791:        struct opt *opt;
1.1       ratchov   792:        unsigned int mode;
1.31      ratchov   793:        unsigned int id;
1.1       ratchov   794:
                    795:        mode = ntohs(p->mode);
1.31      ratchov   796:        id = ntohl(p->id);
1.1       ratchov   797: #ifdef DEBUG
                    798:        if (log_level >= 3) {
                    799:                sock_log(f);
                    800:                log_puts(": hello from <");
                    801:                log_puts(p->who);
                    802:                log_puts(">, mode = ");
                    803:                log_putx(mode);
                    804:                log_puts(", ver ");
                    805:                log_putu(p->version);
                    806:                log_puts("\n");
                    807:        }
                    808: #endif
                    809:        if (p->version != AMSG_VERSION) {
                    810:                if (log_level >= 1) {
                    811:                        sock_log(f);
                    812:                        log_puts(": ");
                    813:                        log_putu(p->version);
                    814:                        log_puts(": unsupported protocol version\n");
                    815:                }
                    816:                return 0;
                    817:        }
                    818:        switch (mode) {
                    819:        case MODE_MIDIIN:
                    820:        case MODE_MIDIOUT:
                    821:        case MODE_MIDIOUT | MODE_MIDIIN:
                    822:        case MODE_REC:
                    823:        case MODE_PLAY:
                    824:        case MODE_PLAY | MODE_REC:
1.32    ! ratchov   825:        case MODE_CTLREAD:
        !           826:        case MODE_CTLWRITE:
        !           827:        case MODE_CTLREAD | MODE_CTLWRITE:
1.1       ratchov   828:                break;
                    829:        default:
                    830: #ifdef DEBUG
                    831:                if (log_level >= 1) {
                    832:                        sock_log(f);
                    833:                        log_puts(": ");
                    834:                        log_putx(mode);
                    835:                        log_puts(": unsupported mode\n");
                    836:                }
                    837: #endif
                    838:                return 0;
                    839:        }
                    840:        f->pstate = SOCK_INIT;
1.5       ratchov   841:        f->port = NULL;
1.1       ratchov   842:        if (mode & MODE_MIDIMASK) {
                    843:                f->slot = NULL;
                    844:                f->midi = midi_new(&sock_midiops, f, mode);
                    845:                if (f->midi == NULL)
                    846:                        return 0;
                    847:                /* XXX: add 'devtype' to libsndio */
                    848:                if (p->devnum < 16) {
                    849:                        d = dev_bynum(p->devnum);
                    850:                        if (d == NULL)
                    851:                                return 0;
                    852:                        midi_tag(f->midi, p->devnum);
                    853:                } else if (p->devnum < 32) {
                    854:                        midi_tag(f->midi, p->devnum);
                    855:                } else if (p->devnum < 48) {
                    856:                        c = port_bynum(p->devnum - 32);
1.3       ratchov   857:                        if (c == NULL || !port_ref(c))
1.1       ratchov   858:                                return 0;
1.3       ratchov   859:                        f->port = c;
1.2       ratchov   860:                        midi_link(f->midi, c->midi);
1.1       ratchov   861:                } else
                    862:                        return 0;
                    863:                return 1;
                    864:        }
1.32    ! ratchov   865:        if (mode & MODE_CTLMASK) {
        !           866:                d = dev_bynum(p->devnum);
        !           867:                if (d == NULL) {
        !           868:                        if (log_level >= 2) {
        !           869:                                sock_log(f);
        !           870:                                log_puts(": ");
        !           871:                                log_putu(p->devnum);
        !           872:                                log_puts(": no such device\n");
        !           873:                        }
        !           874:                        return 0;
        !           875:                }
        !           876:                f->ctlslot = ctlslot_new(d, &sock_ctlops, f);
        !           877:                if (f->ctlslot == NULL) {
        !           878:                        if (log_level >= 2) {
        !           879:                                sock_log(f);
        !           880:                                log_puts(": couldn't get slot\n");
        !           881:                        }
        !           882:                        return 0;
        !           883:                }
        !           884:                f->ctldesc = xmalloc(SOCK_CTLDESC_SIZE *
        !           885:                    sizeof(struct amsg_ctl_desc));
        !           886:                f->ctlops = 0;
        !           887:                f->ctlsyncpending = 0;
        !           888:                return 1;
        !           889:        }
1.22      ratchov   890:        d = dev_bynum(p->devnum);
                    891:        if (d == NULL)
                    892:                return 0;
1.23      ratchov   893:        opt = opt_byname(d, p->opt);
                    894:        if (opt == NULL)
1.1       ratchov   895:                return 0;
1.31      ratchov   896:        f->slot = slot_new(d, opt, id, p->who, &sock_slotops, f, mode);
1.29      ratchov   897:        if (f->slot == NULL)
1.1       ratchov   898:                return 0;
                    899:        f->midi = NULL;
                    900:        return 1;
                    901: }
                    902:
                    903: /*
                    904:  * execute the message in f->rmsg, return 1 on success
                    905:  */
                    906: int
                    907: sock_execmsg(struct sock *f)
                    908: {
1.32    ! ratchov   909:        struct ctl *c;
1.1       ratchov   910:        struct slot *s = f->slot;
                    911:        struct amsg *m = &f->rmsg;
                    912:        unsigned char *data;
                    913:        int size, ctl;
                    914:
                    915:        switch (ntohl(m->cmd)) {
                    916:        case AMSG_DATA:
                    917: #ifdef DEBUG
                    918:                if (log_level >= 4) {
                    919:                        sock_log(f);
                    920:                        log_puts(": DATA message\n");
                    921:                }
                    922: #endif
                    923:                if (s != NULL && f->pstate != SOCK_START) {
                    924: #ifdef DEBUG
                    925:                        if (log_level >= 1) {
                    926:                                sock_log(f);
                    927:                                log_puts(": DATA, wrong state\n");
                    928:                        }
                    929: #endif
                    930:                        sock_close(f);
                    931:                        return 0;
                    932:                }
                    933:                if ((f->slot && !(f->slot->mode & MODE_PLAY)) ||
                    934:                    (f->midi && !(f->midi->mode & MODE_MIDIOUT))) {
                    935: #ifdef DEBUG
                    936:                        if (log_level >= 1) {
                    937:                                sock_log(f);
                    938:                                log_puts(": DATA, input-only mode\n");
                    939:                        }
                    940: #endif
                    941:                        sock_close(f);
                    942:                        return 0;
                    943:                }
                    944:                size = ntohl(m->u.data.size);
                    945:                if (size <= 0) {
                    946: #ifdef DEBUG
                    947:                        if (log_level >= 1) {
                    948:                                sock_log(f);
                    949:                                log_puts(": zero size payload\n");
                    950:                        }
                    951: #endif
                    952:                        sock_close(f);
                    953:                        return 0;
                    954:                }
                    955:                if (s != NULL && size % s->mix.bpf != 0) {
                    956: #ifdef DEBUG
                    957:                        if (log_level >= 1) {
                    958:                                sock_log(f);
                    959:                                log_puts(": not aligned to frame\n");
                    960:                        }
                    961: #endif
                    962:                        sock_close(f);
                    963:                        return 0;
                    964:                }
                    965:                if (s != NULL && size > f->ralign) {
                    966: #ifdef DEBUG
                    967:                        if (log_level >= 1) {
                    968:                                sock_log(f);
                    969:                                log_puts(": size = ");
                    970:                                log_puti(size);
                    971:                                log_puts(": ralign = ");
                    972:                                log_puti(f->ralign);
                    973:                                log_puts(": not aligned to block\n");
                    974:                        }
                    975: #endif
                    976:                        sock_close(f);
                    977:                        return 0;
                    978:                }
                    979:                f->rstate = SOCK_RDATA;
                    980:                f->rsize = f->rtodo = size;
                    981:                if (s != NULL) {
                    982:                        f->ralign -= size;
                    983:                        if (f->ralign == 0)
                    984:                                f->ralign = s->round * s->mix.bpf;
                    985:                }
                    986:                if (f->rtodo > f->rmax) {
                    987: #ifdef DEBUG
                    988:                        if (log_level >= 1) {
                    989:                                sock_log(f);
                    990:                                log_puts(": unexpected data, size = ");
                    991:                                log_putu(size);
                    992:                                log_puts(", rmax = ");
                    993:                                log_putu(f->rmax);
                    994:                                log_puts("\n");
                    995:                        }
                    996: #endif
                    997:                        sock_close(f);
                    998:                        return 0;
                    999:                }
                   1000:                f->rmax -= f->rtodo;
                   1001:                if (f->rtodo == 0) {
                   1002: #ifdef DEBUG
                   1003:                        if (log_level >= 1) {
                   1004:                                sock_log(f);
                   1005:                                log_puts(": zero-length data chunk\n");
                   1006:                        }
                   1007: #endif
                   1008:                        sock_close(f);
                   1009:                        return 0;
                   1010:                }
                   1011:                break;
                   1012:        case AMSG_START:
                   1013: #ifdef DEBUG
                   1014:                if (log_level >= 3) {
                   1015:                        sock_log(f);
                   1016:                        log_puts(": START message\n");
                   1017:                }
                   1018: #endif
1.15      ratchov  1019:                if (f->pstate != SOCK_INIT || s == NULL) {
1.1       ratchov  1020: #ifdef DEBUG
                   1021:                        if (log_level >= 1) {
                   1022:                                sock_log(f);
                   1023:                                log_puts(": START, wrong state\n");
                   1024:                        }
                   1025: #endif
                   1026:                        sock_close(f);
                   1027:                        return 0;
                   1028:                }
                   1029:                f->tickpending = 0;
                   1030:                f->stoppending = 0;
                   1031:                slot_start(s);
                   1032:                if (s->mode & MODE_PLAY) {
                   1033:                        f->fillpending = s->appbufsz;
                   1034:                        f->ralign = s->round * s->mix.bpf;
                   1035:                        f->rmax = 0;
                   1036:                }
                   1037:                if (s->mode & MODE_RECMASK) {
                   1038:                        f->walign = s->round * s->sub.bpf;
                   1039:                        f->wmax = 0;
                   1040:                }
                   1041:                f->pstate = SOCK_START;
                   1042:                f->rstate = SOCK_RMSG;
                   1043:                f->rtodo = sizeof(struct amsg);
                   1044:                if (log_level >= 2) {
                   1045:                        slot_log(f->slot);
                   1046:                        log_puts(": ");
                   1047:                        log_putu(s->rate);
                   1048:                        log_puts("Hz, ");
                   1049:                        aparams_log(&s->par);
                   1050:                        if (s->mode & MODE_PLAY) {
                   1051:                                log_puts(", play ");
1.27      ratchov  1052:                                log_puti(s->opt->pmin);
1.1       ratchov  1053:                                log_puts(":");
1.28      ratchov  1054:                                log_puti(s->opt->pmin + s->mix.nch - 1);
1.1       ratchov  1055:                        }
                   1056:                        if (s->mode & MODE_RECMASK) {
                   1057:                                log_puts(", rec ");
1.27      ratchov  1058:                                log_puti(s->opt->rmin);
1.1       ratchov  1059:                                log_puts(":");
1.28      ratchov  1060:                                log_puti(s->opt->rmin + s->sub.nch - 1);
1.1       ratchov  1061:                        }
                   1062:                        log_puts(", ");
                   1063:                        log_putu(s->appbufsz / s->round);
                   1064:                        log_puts(" blocks of ");
                   1065:                        log_putu(s->round);
                   1066:                        log_puts(" frames\n");
                   1067:                }
                   1068:                break;
                   1069:        case AMSG_STOP:
                   1070: #ifdef DEBUG
                   1071:                if (log_level >= 3) {
                   1072:                        sock_log(f);
                   1073:                        log_puts(": STOP message\n");
                   1074:                }
                   1075: #endif
                   1076:                if (f->pstate != SOCK_START) {
                   1077: #ifdef DEBUG
                   1078:                        if (log_level >= 1) {
                   1079:                                sock_log(f);
                   1080:                                log_puts(": STOP, wrong state\n");
                   1081:                        }
                   1082: #endif
                   1083:                        sock_close(f);
                   1084:                        return 0;
                   1085:                }
                   1086:                f->rmax = 0;
                   1087:                if (!(s->mode & MODE_PLAY))
                   1088:                        f->stoppending = 1;
                   1089:                f->pstate = SOCK_STOP;
                   1090:                f->rstate = SOCK_RMSG;
                   1091:                f->rtodo = sizeof(struct amsg);
                   1092:                if (s->mode & MODE_PLAY) {
                   1093:                        if (f->ralign < s->round * s->mix.bpf) {
                   1094:                                data = abuf_wgetblk(&s->mix.buf, &size);
                   1095: #ifdef DEBUG
                   1096:                                if (size < f->ralign) {
                   1097:                                        sock_log(f);
                   1098:                                        log_puts(": unaligned stop, size = ");
                   1099:                                        log_putu(size);
                   1100:                                        log_puts(", ralign = ");
                   1101:                                        log_putu(f->ralign);
                   1102:                                        log_puts("\n");
                   1103:                                        panic();
                   1104:                                }
                   1105: #endif
                   1106:                                memset(data, 0, f->ralign);
                   1107:                                abuf_wcommit(&s->mix.buf, f->ralign);
                   1108:                                f->ralign = s->round * s->mix.bpf;
                   1109:                        }
                   1110:                }
1.17      ratchov  1111:                slot_stop(s);
1.1       ratchov  1112:                break;
                   1113:        case AMSG_SETPAR:
                   1114: #ifdef DEBUG
                   1115:                if (log_level >= 3) {
                   1116:                        sock_log(f);
                   1117:                        log_puts(": SETPAR message\n");
                   1118:                }
                   1119: #endif
1.15      ratchov  1120:                if (f->pstate != SOCK_INIT || s == NULL) {
1.1       ratchov  1121: #ifdef DEBUG
                   1122:                        if (log_level >= 1) {
                   1123:                                sock_log(f);
                   1124:                                log_puts(": SETPAR, wrong state\n");
                   1125:                        }
                   1126: #endif
                   1127:                        sock_close(f);
                   1128:                        return 0;
                   1129:                }
                   1130:                if (!sock_setpar(f)) {
                   1131:                        sock_close(f);
                   1132:                        return 0;
                   1133:                }
                   1134:                f->rtodo = sizeof(struct amsg);
                   1135:                f->rstate = SOCK_RMSG;
                   1136:                break;
                   1137:        case AMSG_GETPAR:
                   1138: #ifdef DEBUG
                   1139:                if (log_level >= 3) {
                   1140:                        sock_log(f);
                   1141:                        log_puts(": GETPAR message\n");
                   1142:                }
                   1143: #endif
1.15      ratchov  1144:                if (f->pstate != SOCK_INIT || s == NULL) {
1.1       ratchov  1145: #ifdef DEBUG
                   1146:                        if (log_level >= 1) {
                   1147:                                sock_log(f);
                   1148:                                log_puts(": GETPAR, wrong state\n");
                   1149:                        }
                   1150: #endif
                   1151:                        sock_close(f);
                   1152:                        return 0;
                   1153:                }
                   1154:                AMSG_INIT(m);
                   1155:                m->cmd = htonl(AMSG_GETPAR);
                   1156:                m->u.par.legacy_mode = s->mode;
1.14      ratchov  1157:                m->u.par.xrun = s->xrun;
1.1       ratchov  1158:                m->u.par.bits = s->par.bits;
                   1159:                m->u.par.bps = s->par.bps;
                   1160:                m->u.par.sig = s->par.sig;
                   1161:                m->u.par.le = s->par.le;
                   1162:                m->u.par.msb = s->par.msb;
1.28      ratchov  1163:                if (s->mode & MODE_PLAY)
                   1164:                        m->u.par.pchan = htons(s->mix.nch);
                   1165:                if (s->mode & MODE_RECMASK)
                   1166:                        m->u.par.rchan = htons(s->sub.nch);
1.1       ratchov  1167:                m->u.par.rate = htonl(s->rate);
                   1168:                m->u.par.appbufsz = htonl(s->appbufsz);
                   1169:                m->u.par.bufsz = htonl(SLOT_BUFSZ(s));
                   1170:                m->u.par.round = htonl(s->round);
                   1171:                f->rstate = SOCK_RRET;
                   1172:                f->rtodo = sizeof(struct amsg);
                   1173:                break;
                   1174:        case AMSG_SETVOL:
                   1175: #ifdef DEBUG
                   1176:                if (log_level >= 3) {
                   1177:                        sock_log(f);
                   1178:                        log_puts(": SETVOL message\n");
                   1179:                }
                   1180: #endif
1.15      ratchov  1181:                if (f->pstate < SOCK_INIT || s == NULL) {
1.1       ratchov  1182: #ifdef DEBUG
                   1183:                        if (log_level >= 1) {
                   1184:                                sock_log(f);
                   1185:                                log_puts(": SETVOL, wrong state\n");
                   1186:                        }
                   1187: #endif
                   1188:                        sock_close(f);
                   1189:                        return 0;
                   1190:                }
                   1191:                ctl = ntohl(m->u.vol.ctl);
                   1192:                if (ctl > MIDI_MAXCTL) {
                   1193: #ifdef DEBUG
                   1194:                        if (log_level >= 1) {
                   1195:                                sock_log(f);
                   1196:                                log_puts(": SETVOL, volume out of range\n");
                   1197:                        }
                   1198: #endif
                   1199:                        sock_close(f);
                   1200:                        return 0;
                   1201:                }
                   1202:                f->rtodo = sizeof(struct amsg);
                   1203:                f->rstate = SOCK_RMSG;
                   1204:                f->lastvol = ctl; /* dont trigger feedback message */
1.15      ratchov  1205:                slot_setvol(s, ctl);
1.1       ratchov  1206:                dev_midi_vol(s->dev, s);
1.32    ! ratchov  1207:                dev_onval(s->dev,
        !          1208:                    CTLADDR_SLOT_LEVEL(f->slot - s->dev->slot), ctl);
        !          1209:                break;
        !          1210:        case AMSG_CTLSUB:
        !          1211: #ifdef DEBUG
        !          1212:                if (log_level >= 3) {
        !          1213:                        sock_log(f);
        !          1214:                        log_puts(": CTLSUB message, desc = ");
        !          1215:                        log_putx(m->u.ctlsub.desc);
        !          1216:                        log_puts(", val = ");
        !          1217:                        log_putx(m->u.ctlsub.val);
        !          1218:                        log_puts("\n");
        !          1219:                }
        !          1220: #endif
        !          1221:                if (f->pstate != SOCK_INIT || f->ctlslot == NULL) {
        !          1222: #ifdef DEBUG
        !          1223:                        if (log_level >= 1) {
        !          1224:                                sock_log(f);
        !          1225:                                log_puts(": CTLSUB, wrong state\n");
        !          1226:                        }
        !          1227: #endif
        !          1228:                        sock_close(f);
        !          1229:                        return 0;
        !          1230:                }
        !          1231:                if (m->u.ctlsub.desc) {
        !          1232:                        if (!(f->ctlops & SOCK_CTLDESC)) {
        !          1233:                                ctl = f->ctlslot->mask;
        !          1234:                                c = f->ctlslot->dev->ctl_list;
        !          1235:                                while (c != NULL) {
        !          1236:                                        c->desc_mask |= ctl;
        !          1237:                                        c = c->next;
        !          1238:                                }
        !          1239:                        }
        !          1240:                        f->ctlops |= SOCK_CTLDESC;
        !          1241:                        f->ctlsyncpending = 1;
        !          1242:                } else
        !          1243:                        f->ctlops &= ~SOCK_CTLDESC;
        !          1244:                if (m->u.ctlsub.val) {
        !          1245:                        f->ctlops |= SOCK_CTLVAL;
        !          1246:                } else
        !          1247:                        f->ctlops &= ~SOCK_CTLVAL;
        !          1248:                f->rstate = SOCK_RMSG;
        !          1249:                f->rtodo = sizeof(struct amsg);
        !          1250:                break;
        !          1251:        case AMSG_CTLSET:
        !          1252: #ifdef DEBUG
        !          1253:                if (log_level >= 3) {
        !          1254:                        sock_log(f);
        !          1255:                        log_puts(": CTLSET message\n");
        !          1256:                }
        !          1257: #endif
        !          1258:                if (f->pstate < SOCK_INIT || f->ctlslot == NULL) {
        !          1259: #ifdef DEBUG
        !          1260:                        if (log_level >= 1) {
        !          1261:                                sock_log(f);
        !          1262:                                log_puts(": CTLSET, wrong state\n");
        !          1263:                        }
        !          1264: #endif
        !          1265:                        sock_close(f);
        !          1266:                        return 0;
        !          1267:                }
        !          1268:                if (!dev_setctl(f->ctlslot->dev,
        !          1269:                        ntohs(m->u.ctlset.addr),
        !          1270:                        ntohs(m->u.ctlset.val))) {
        !          1271: #ifdef DEBUG
        !          1272:                        if (log_level >= 1) {
        !          1273:                                sock_log(f);
        !          1274:                                log_puts(": CTLSET, wrong addr/val\n");
        !          1275:                        }
        !          1276: #endif
        !          1277:                        sock_close(f);
        !          1278:                        return 0;
        !          1279:                }
        !          1280:                f->rtodo = sizeof(struct amsg);
        !          1281:                f->rstate = SOCK_RMSG;
1.1       ratchov  1282:                break;
                   1283:        case AMSG_AUTH:
                   1284: #ifdef DEBUG
                   1285:                if (log_level >= 3) {
                   1286:                        sock_log(f);
                   1287:                        log_puts(": AUTH message\n");
                   1288:                }
                   1289: #endif
                   1290:                if (f->pstate != SOCK_AUTH) {
                   1291: #ifdef DEBUG
                   1292:                        if (log_level >= 1) {
                   1293:                                sock_log(f);
                   1294:                                log_puts(": AUTH, wrong state\n");
                   1295:                        }
                   1296: #endif
                   1297:                        sock_close(f);
                   1298:                        return 0;
                   1299:                }
                   1300:                if (!sock_auth(f)) {
                   1301:                        sock_close(f);
                   1302:                        return 0;
                   1303:                }
                   1304:                f->rstate = SOCK_RMSG;
                   1305:                f->rtodo = sizeof(struct amsg);
                   1306:                break;
                   1307:        case AMSG_HELLO:
                   1308: #ifdef DEBUG
                   1309:                if (log_level >= 3) {
                   1310:                        sock_log(f);
                   1311:                        log_puts(": HELLO message\n");
                   1312:                }
                   1313: #endif
                   1314:                if (f->pstate != SOCK_HELLO) {
                   1315: #ifdef DEBUG
                   1316:                        if (log_level >= 1) {
                   1317:                                sock_log(f);
                   1318:                                log_puts(": HELLO, wrong state\n");
                   1319:                        }
                   1320: #endif
                   1321:                        sock_close(f);
                   1322:                        return 0;
                   1323:                }
                   1324:                if (!sock_hello(f)) {
                   1325:                        sock_close(f);
                   1326:                        return 0;
                   1327:                }
                   1328:                AMSG_INIT(m);
                   1329:                m->cmd = htonl(AMSG_ACK);
                   1330:                f->rstate = SOCK_RRET;
                   1331:                f->rtodo = sizeof(struct amsg);
                   1332:                break;
                   1333:        case AMSG_BYE:
                   1334: #ifdef DEBUG
                   1335:                if (log_level >= 3) {
                   1336:                        sock_log(f);
                   1337:                        log_puts(": BYE message\n");
                   1338:                }
                   1339: #endif
                   1340:                if (s != NULL && f->pstate != SOCK_INIT) {
                   1341: #ifdef DEBUG
                   1342:                        if (log_level >= 1) {
                   1343:                                sock_log(f);
                   1344:                                log_puts(": BYE, wrong state\n");
                   1345:                        }
                   1346: #endif
                   1347:                }
                   1348:                sock_close(f);
                   1349:                return 0;
                   1350:        default:
                   1351: #ifdef DEBUG
                   1352:                if (log_level >= 1) {
                   1353:                        sock_log(f);
                   1354:                        log_puts(": unknown command in message\n");
                   1355:                }
                   1356: #endif
                   1357:                sock_close(f);
                   1358:                return 0;
                   1359:        }
                   1360:        return 1;
                   1361: }
                   1362:
                   1363: /*
                   1364:  * build a message in f->wmsg, return 1 on success and 0 if
                   1365:  * there's nothing to do. Assume f->wstate is SOCK_WIDLE
                   1366:  */
                   1367: int
                   1368: sock_buildmsg(struct sock *f)
                   1369: {
1.32    ! ratchov  1370:        unsigned int size, mask;
        !          1371:        struct amsg_ctl_desc *desc;
        !          1372:        struct ctl *c, **pc;
1.1       ratchov  1373:
                   1374:        /*
                   1375:         * If pos changed (or initial tick), build a MOVE message.
                   1376:         */
                   1377:        if (f->tickpending) {
                   1378: #ifdef DEBUG
                   1379:                if (log_level >= 4) {
                   1380:                        sock_log(f);
                   1381:                        log_puts(": building MOVE message, delta = ");
                   1382:                        log_puti(f->slot->delta);
                   1383:                        log_puts("\n");
                   1384:                }
                   1385: #endif
                   1386:                AMSG_INIT(&f->wmsg);
                   1387:                f->wmsg.cmd = htonl(AMSG_MOVE);
                   1388:                f->wmsg.u.ts.delta = htonl(f->slot->delta);
                   1389:                f->wtodo = sizeof(struct amsg);
                   1390:                f->wstate = SOCK_WMSG;
                   1391:                f->tickpending = 0;
                   1392:                /*
                   1393:                 * XXX: use tickpending as accumulator rather than
                   1394:                 * slot->delta
                   1395:                 */
                   1396:                f->slot->delta = 0;
                   1397:                return 1;
                   1398:        }
                   1399:
                   1400:        if (f->fillpending > 0) {
                   1401:                AMSG_INIT(&f->wmsg);
1.17      ratchov  1402:                f->wmsg.cmd = htonl(AMSG_FLOWCTL);
1.1       ratchov  1403:                f->wmsg.u.ts.delta = htonl(f->fillpending);
                   1404:                size = f->fillpending;
                   1405:                if (f->slot)
                   1406:                        size *= f->slot->mix.bpf;
                   1407:                f->rmax += size;
                   1408: #ifdef DEBUG
                   1409:                if (log_level >= 4) {
                   1410:                        sock_log(f);
                   1411:                        log_puts(": building FLOWCTL message, count = ");
                   1412:                        log_puti(f->fillpending);
                   1413:                        log_puts(", rmax -> ");
                   1414:                        log_puti(f->rmax);
                   1415:                        log_puts("\n");
                   1416:                }
                   1417: #endif
                   1418:                f->wtodo = sizeof(struct amsg);
                   1419:                f->wstate = SOCK_WMSG;
                   1420:                f->fillpending = 0;
                   1421:                return 1;
                   1422:        }
                   1423:
                   1424:        /*
                   1425:         * if volume changed build a SETVOL message
                   1426:         */
                   1427:        if (f->pstate >= SOCK_START && f->slot->vol != f->lastvol) {
                   1428: #ifdef DEBUG
                   1429:                if (log_level >= 3) {
                   1430:                        sock_log(f);
                   1431:                        log_puts(": building SETVOL message, vol = ");
                   1432:                        log_puti(f->slot->vol);
                   1433:                        log_puts("\n");
                   1434:                }
                   1435: #endif
                   1436:                AMSG_INIT(&f->wmsg);
                   1437:                f->wmsg.cmd = htonl(AMSG_SETVOL);
                   1438:                f->wmsg.u.vol.ctl = htonl(f->slot->vol);
                   1439:                f->wtodo = sizeof(struct amsg);
                   1440:                f->wstate = SOCK_WMSG;
                   1441:                f->lastvol = f->slot->vol;
                   1442:                return 1;
                   1443:        }
                   1444:
                   1445:        if (f->midi != NULL && f->midi->obuf.used > 0) {
1.17      ratchov  1446:                size = f->midi->obuf.used;
1.1       ratchov  1447:                if (size > AMSG_DATAMAX)
                   1448:                        size = AMSG_DATAMAX;
                   1449:                AMSG_INIT(&f->wmsg);
                   1450:                f->wmsg.cmd = htonl(AMSG_DATA);
                   1451:                f->wmsg.u.data.size = htonl(size);
                   1452:                f->wtodo = sizeof(struct amsg);
                   1453:                f->wstate = SOCK_WMSG;
                   1454:                return 1;
                   1455:        }
                   1456:
                   1457:        /*
                   1458:         * If data available, build a DATA message.
                   1459:         */
1.10      ratchov  1460:        if (f->slot != NULL && f->wmax > 0 && f->slot->sub.buf.used > 0) {
1.1       ratchov  1461:                size = f->slot->sub.buf.used;
                   1462:                if (size > AMSG_DATAMAX)
                   1463:                        size = AMSG_DATAMAX;
                   1464:                if (size > f->walign)
                   1465:                        size = f->walign;
                   1466:                if (size > f->wmax)
                   1467:                        size = f->wmax;
                   1468:                size -= size % f->slot->sub.bpf;
                   1469: #ifdef DEBUG
                   1470:                if (size == 0) {
                   1471:                        sock_log(f);
                   1472:                        log_puts(": sock_buildmsg size == 0\n");
                   1473:                        panic();
                   1474:                }
                   1475: #endif
                   1476:                f->walign -= size;
                   1477:                f->wmax -= size;
                   1478:                if (f->walign == 0)
                   1479:                        f->walign = f->slot->round * f->slot->sub.bpf;
                   1480: #ifdef DEBUG
                   1481:                if (log_level >= 4) {
                   1482:                        sock_log(f);
                   1483:                        log_puts(": building audio DATA message, size = ");
                   1484:                        log_puti(size);
                   1485:                        log_puts("\n");
                   1486:                }
                   1487: #endif
                   1488:                AMSG_INIT(&f->wmsg);
                   1489:                f->wmsg.cmd = htonl(AMSG_DATA);
                   1490:                f->wmsg.u.data.size = htonl(size);
                   1491:                f->wtodo = sizeof(struct amsg);
                   1492:                f->wstate = SOCK_WMSG;
                   1493:                return 1;
                   1494:        }
                   1495:
                   1496:        if (f->stoppending) {
                   1497: #ifdef DEBUG
                   1498:                if (log_level >= 3) {
                   1499:                        sock_log(f);
                   1500:                        log_puts(": building STOP message\n");
                   1501:                }
                   1502: #endif
                   1503:                f->stoppending = 0;
                   1504:                f->pstate = SOCK_INIT;
                   1505:                AMSG_INIT(&f->wmsg);
                   1506:                f->wmsg.cmd = htonl(AMSG_STOP);
                   1507:                f->wtodo = sizeof(struct amsg);
                   1508:                f->wstate = SOCK_WMSG;
1.32    ! ratchov  1509:                return 1;
        !          1510:        }
        !          1511:
        !          1512:        /*
        !          1513:         * XXX: add a flag indicating if there are changes
        !          1514:         * in controls not seen by this client, rather
        !          1515:         * than walking through the full list of control
        !          1516:         * searching for the {desc,val}_mask bits
        !          1517:         */
        !          1518:        if (f->ctlslot && (f->ctlops & SOCK_CTLDESC)) {
        !          1519:                desc = f->ctldesc;
        !          1520:                mask = f->ctlslot->mask;
        !          1521:                size = 0;
        !          1522:                pc = &f->ctlslot->dev->ctl_list;
        !          1523:                while ((c = *pc) != NULL) {
        !          1524:                        if ((c->desc_mask & mask) == 0 ||
        !          1525:                            (c->refs_mask & mask) == 0) {
        !          1526:                                pc = &c->next;
        !          1527:                                continue;
        !          1528:                        }
        !          1529:                        if (size == SOCK_CTLDESC_SIZE *
        !          1530:                                sizeof(struct amsg_ctl_desc))
        !          1531:                                break;
        !          1532:                        c->desc_mask &= ~mask;
        !          1533:                        c->val_mask &= ~mask;
        !          1534:                        strlcpy(desc->group, c->group,
        !          1535:                            AMSG_CTL_NAMEMAX);
        !          1536:                        strlcpy(desc->node0.name, c->node0.name,
        !          1537:                            AMSG_CTL_NAMEMAX);
        !          1538:                        desc->node0.unit = ntohs(c->node0.unit);
        !          1539:                        strlcpy(desc->node1.name, c->node1.name,
        !          1540:                            AMSG_CTL_NAMEMAX);
        !          1541:                        desc->node1.unit = ntohs(c->node1.unit);
        !          1542:                        desc->type = c->type;
        !          1543:                        strlcpy(desc->func, c->func, AMSG_CTL_NAMEMAX);
        !          1544:                        desc->addr = htons(c->addr);
        !          1545:                        desc->maxval = htons(c->maxval);
        !          1546:                        desc->curval = htons(c->curval);
        !          1547:                        size += sizeof(struct amsg_ctl_desc);
        !          1548:                        desc++;
        !          1549:
        !          1550:                        /* if this is a deleted entry unref it */
        !          1551:                        if (c->type == CTL_NONE) {
        !          1552:                                c->refs_mask &= ~mask;
        !          1553:                                if (c->refs_mask == 0) {
        !          1554:                                        *pc = c->next;
        !          1555:                                        xfree(c);
        !          1556:                                        continue;
        !          1557:                                }
        !          1558:                        }
        !          1559:
        !          1560:                        pc = &c->next;
        !          1561:                }
        !          1562:                if (size > 0) {
        !          1563:                        AMSG_INIT(&f->wmsg);
        !          1564:                        f->wmsg.cmd = htonl(AMSG_DATA);
        !          1565:                        f->wmsg.u.data.size = htonl(size);
        !          1566:                        f->wtodo = sizeof(struct amsg);
        !          1567:                        f->wstate = SOCK_WMSG;
        !          1568: #ifdef DEBUG
        !          1569:                        if (log_level >= 3) {
        !          1570:                                sock_log(f);
        !          1571:                                log_puts(": building control DATA message\n");
        !          1572:                        }
        !          1573: #endif
        !          1574:                        return 1;
        !          1575:                }
        !          1576:        }
        !          1577:        if (f->ctlslot && (f->ctlops & SOCK_CTLVAL)) {
        !          1578:                mask = f->ctlslot->mask;
        !          1579:                for (c = f->ctlslot->dev->ctl_list; c != NULL; c = c->next) {
        !          1580:                        if ((c->val_mask & mask) == 0)
        !          1581:                                continue;
        !          1582:                        c->val_mask &= ~mask;
        !          1583:                        AMSG_INIT(&f->wmsg);
        !          1584:                        f->wmsg.cmd = htonl(AMSG_CTLSET);
        !          1585:                        f->wmsg.u.ctlset.addr = htons(c->addr);
        !          1586:                        f->wmsg.u.ctlset.val = htons(c->curval);
        !          1587:                        f->wtodo = sizeof(struct amsg);
        !          1588:                        f->wstate = SOCK_WMSG;
        !          1589: #ifdef DEBUG
        !          1590:                        if (log_level >= 3) {
        !          1591:                                sock_log(f);
        !          1592:                                log_puts(": building CTLSET message\n");
        !          1593:                        }
        !          1594: #endif
        !          1595:                        return 1;
        !          1596:                }
        !          1597:        }
        !          1598:        if (f->ctlslot && f->ctlsyncpending) {
        !          1599:                f->ctlsyncpending = 0;
        !          1600:                f->wmsg.cmd = htonl(AMSG_CTLSYNC);
        !          1601:                f->wtodo = sizeof(struct amsg);
        !          1602:                f->wstate = SOCK_WMSG;
        !          1603: #ifdef DEBUG
        !          1604:                if (log_level >= 3) {
        !          1605:                        sock_log(f);
        !          1606:                        log_puts(": building CTLSYNC message\n");
        !          1607:                }
        !          1608: #endif
1.1       ratchov  1609:                return 1;
                   1610:        }
                   1611: #ifdef DEBUG
                   1612:        if (log_level >= 4) {
                   1613:                sock_log(f);
                   1614:                log_puts(": no messages to build anymore, idling...\n");
                   1615:        }
                   1616: #endif
                   1617:        f->wstate = SOCK_WIDLE;
                   1618:        return 0;
                   1619: }
                   1620:
                   1621: /*
                   1622:  * iteration of the socket reader loop, return 1 on success
                   1623:  */
                   1624: int
                   1625: sock_read(struct sock *f)
                   1626: {
                   1627: #ifdef DEBUG
                   1628:        if (log_level >= 4) {
                   1629:                sock_log(f);
                   1630:                log_puts(": reading ");
                   1631:                log_putu(f->rtodo);
                   1632:                log_puts(" todo\n");
                   1633:        }
                   1634: #endif
                   1635:        switch (f->rstate) {
                   1636:        case SOCK_RIDLE:
                   1637:                return 0;
                   1638:        case SOCK_RMSG:
                   1639:                if (!sock_rmsg(f))
                   1640:                        return 0;
                   1641:                if (!sock_execmsg(f))
                   1642:                        return 0;
                   1643:                break;
                   1644:        case SOCK_RDATA:
                   1645:                if (!sock_rdata(f))
                   1646:                        return 0;
                   1647:                f->rstate = SOCK_RMSG;
                   1648:                f->rtodo = sizeof(struct amsg);
                   1649:                break;
                   1650:        case SOCK_RRET:
                   1651:                if (f->wstate != SOCK_WIDLE) {
                   1652: #ifdef DEBUG
                   1653:                        if (log_level >= 4) {
                   1654:                                sock_log(f);
                   1655:                                log_puts(": can't reply, write-end blocked\n");
                   1656:                        }
                   1657: #endif
                   1658:                        return 0;
                   1659:                }
                   1660:                f->wmsg = f->rmsg;
                   1661:                f->wstate = SOCK_WMSG;
                   1662:                f->wtodo = sizeof(struct amsg);
                   1663:                f->rstate = SOCK_RMSG;
                   1664:                f->rtodo = sizeof(struct amsg);
                   1665: #ifdef DEBUG
                   1666:                if (log_level >= 4) {
                   1667:                        sock_log(f);
                   1668:                        log_puts(": copied RRET message\n");
                   1669:                }
                   1670: #endif
                   1671:        }
                   1672:        return 1;
                   1673: }
                   1674:
                   1675: /*
                   1676:  * iteration of the socket writer loop, return 1 on success
                   1677:  */
                   1678: int
                   1679: sock_write(struct sock *f)
                   1680: {
                   1681: #ifdef DEBUG
                   1682:        if (log_level >= 4) {
                   1683:                sock_log(f);
                   1684:                log_puts(": writing");
                   1685:                if (f->wstate != SOCK_WIDLE) {
                   1686:                        log_puts(" todo = ");
                   1687:                        log_putu(f->wtodo);
                   1688:                }
                   1689:                log_puts("\n");
                   1690:        }
                   1691: #endif
                   1692:        switch (f->wstate) {
                   1693:        case SOCK_WMSG:
                   1694:                if (!sock_wmsg(f))
                   1695:                        return 0;
1.20      ratchov  1696:                /*
                   1697:                 * f->wmsg is either build by sock_buildmsg() or
                   1698:                 * copied from f->rmsg (in the SOCK_RRET state), so
                   1699:                 * it's safe.
                   1700:                 */
1.1       ratchov  1701:                if (ntohl(f->wmsg.cmd) != AMSG_DATA) {
                   1702:                        f->wstate = SOCK_WIDLE;
                   1703:                        f->wtodo = 0xdeadbeef;
                   1704:                        break;
                   1705:                }
                   1706:                f->wstate = SOCK_WDATA;
                   1707:                f->wsize = f->wtodo = ntohl(f->wmsg.u.data.size);
                   1708:                /* PASSTHROUGH */
                   1709:        case SOCK_WDATA:
                   1710:                if (!sock_wdata(f))
                   1711:                        return 0;
                   1712:                if (f->wtodo > 0)
                   1713:                        break;
                   1714:                f->wstate = SOCK_WIDLE;
                   1715:                f->wtodo = 0xdeadbeef;
                   1716:                if (f->pstate == SOCK_STOP) {
                   1717:                        f->pstate = SOCK_INIT;
                   1718:                        f->wmax = 0;
                   1719: #ifdef DEBUG
                   1720:                        if (log_level >= 4) {
                   1721:                                sock_log(f);
                   1722:                                log_puts(": drained, moved to INIT state\n");
                   1723:                        }
                   1724: #endif
                   1725:                }
                   1726:                /* PASSTHROUGH */
                   1727:        case SOCK_WIDLE:
                   1728:                if (f->rstate == SOCK_RRET) {
                   1729:                        f->wmsg = f->rmsg;
                   1730:                        f->wstate = SOCK_WMSG;
                   1731:                        f->wtodo = sizeof(struct amsg);
                   1732:                        f->rstate = SOCK_RMSG;
                   1733:                        f->rtodo = sizeof(struct amsg);
                   1734: #ifdef DEBUG
                   1735:                        if (log_level >= 4) {
                   1736:                                sock_log(f);
                   1737:                                log_puts(": copied RRET message\n");
                   1738:                        }
                   1739: #endif
                   1740:                } else {
                   1741:                        if (!sock_buildmsg(f))
                   1742:                                return 0;
                   1743:                }
                   1744:                break;
                   1745: #ifdef DEBUG
                   1746:        default:
                   1747:                sock_log(f);
                   1748:                log_puts(": bad writing end state\n");
                   1749:                panic();
                   1750: #endif
                   1751:        }
                   1752:        return 1;
                   1753: }
                   1754:
                   1755: int
                   1756: sock_pollfd(void *arg, struct pollfd *pfd)
                   1757: {
                   1758:        struct sock *f = arg;
                   1759:        int events = 0;
                   1760:
                   1761:        /*
                   1762:         * feedback counters, clock ticks and alike may have changed,
                   1763:         * prepare a message to trigger writes
                   1764:         *
                   1765:         * XXX: doing this at the beginning of the cycle is not optimal,
                   1766:         * because state is changed at the end of the read cycle, and
                   1767:         * thus counters, ret message and alike are generated then.
                   1768:         */
                   1769:        if (f->wstate == SOCK_WIDLE && f->rstate != SOCK_RRET)
                   1770:                sock_buildmsg(f);
                   1771:
                   1772:        if (f->rstate == SOCK_RMSG ||
                   1773:            f->rstate == SOCK_RDATA)
                   1774:                events |= POLLIN;
                   1775:        if (f->rstate == SOCK_RRET ||
                   1776:            f->wstate == SOCK_WMSG ||
                   1777:            f->wstate == SOCK_WDATA)
                   1778:                events |= POLLOUT;
                   1779:        pfd->fd = f->fd;
                   1780:        pfd->events = events;
                   1781:        return 1;
                   1782: }
                   1783:
                   1784: int
                   1785: sock_revents(void *arg, struct pollfd *pfd)
                   1786: {
                   1787:        return pfd->revents;
                   1788: }
                   1789:
                   1790: void
                   1791: sock_in(void *arg)
                   1792: {
                   1793:        struct sock *f = arg;
                   1794:
                   1795:        while (sock_read(f))
                   1796:                ;
                   1797: }
                   1798:
                   1799: void
                   1800: sock_out(void *arg)
                   1801: {
                   1802:        struct sock *f = arg;
                   1803:
                   1804:        while (sock_write(f))
                   1805:                ;
                   1806: }
                   1807:
                   1808: void
                   1809: sock_hup(void *arg)
                   1810: {
                   1811:        struct sock *f = arg;
                   1812:
                   1813:        sock_close(f);
                   1814: }