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