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