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

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

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