Annotation of src/usr.bin/sndiod/sock.c, Revision 1.36
1.36 ! ratchov 1: /* $OpenBSD: sock.c,v 1.35 2020/04/26 14:13:22 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");
117: log_putu(f->ctlslot - f->ctlslot->dev->ctlslot);
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;
619: struct dev *d = s->dev;
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;
883: if (!dev_ref(d))
1.1 ratchov 884: return 0;
885: midi_tag(f->midi, p->devnum);
886: } else if (p->devnum < 32) {
887: midi_tag(f->midi, p->devnum);
888: } else if (p->devnum < 48) {
889: c = port_bynum(p->devnum - 32);
1.3 ratchov 890: if (c == NULL || !port_ref(c))
1.1 ratchov 891: return 0;
1.3 ratchov 892: f->port = c;
1.2 ratchov 893: midi_link(f->midi, c->midi);
1.1 ratchov 894: } else
895: return 0;
896: return 1;
897: }
1.32 ratchov 898: if (mode & MODE_CTLMASK) {
899: d = dev_bynum(p->devnum);
900: if (d == NULL) {
901: if (log_level >= 2) {
902: sock_log(f);
903: log_puts(": ");
904: log_putu(p->devnum);
905: log_puts(": no such device\n");
906: }
907: return 0;
908: }
909: f->ctlslot = ctlslot_new(d, &sock_ctlops, f);
910: if (f->ctlslot == NULL) {
911: if (log_level >= 2) {
912: sock_log(f);
913: log_puts(": couldn't get slot\n");
914: }
915: return 0;
916: }
917: f->ctldesc = xmalloc(SOCK_CTLDESC_SIZE *
918: sizeof(struct amsg_ctl_desc));
919: f->ctlops = 0;
920: f->ctlsyncpending = 0;
921: return 1;
922: }
1.22 ratchov 923: d = dev_bynum(p->devnum);
924: if (d == NULL)
925: return 0;
1.23 ratchov 926: opt = opt_byname(d, p->opt);
927: if (opt == NULL)
1.1 ratchov 928: return 0;
1.31 ratchov 929: f->slot = slot_new(d, opt, id, p->who, &sock_slotops, f, mode);
1.29 ratchov 930: if (f->slot == NULL)
1.1 ratchov 931: return 0;
932: f->midi = NULL;
933: return 1;
934: }
935:
936: /*
937: * execute the message in f->rmsg, return 1 on success
938: */
939: int
940: sock_execmsg(struct sock *f)
941: {
1.32 ratchov 942: struct ctl *c;
1.1 ratchov 943: struct slot *s = f->slot;
944: struct amsg *m = &f->rmsg;
945: unsigned char *data;
946: int size, ctl;
947:
948: switch (ntohl(m->cmd)) {
949: case AMSG_DATA:
950: #ifdef DEBUG
951: if (log_level >= 4) {
952: sock_log(f);
953: log_puts(": DATA message\n");
954: }
955: #endif
956: if (s != NULL && f->pstate != SOCK_START) {
957: #ifdef DEBUG
958: if (log_level >= 1) {
959: sock_log(f);
960: log_puts(": DATA, wrong state\n");
961: }
962: #endif
963: sock_close(f);
964: return 0;
965: }
966: if ((f->slot && !(f->slot->mode & MODE_PLAY)) ||
967: (f->midi && !(f->midi->mode & MODE_MIDIOUT))) {
968: #ifdef DEBUG
969: if (log_level >= 1) {
970: sock_log(f);
971: log_puts(": DATA, input-only mode\n");
972: }
973: #endif
974: sock_close(f);
975: return 0;
976: }
977: size = ntohl(m->u.data.size);
978: if (size <= 0) {
979: #ifdef DEBUG
980: if (log_level >= 1) {
981: sock_log(f);
982: log_puts(": zero size payload\n");
983: }
984: #endif
985: sock_close(f);
986: return 0;
987: }
988: if (s != NULL && size % s->mix.bpf != 0) {
989: #ifdef DEBUG
990: if (log_level >= 1) {
991: sock_log(f);
992: log_puts(": not aligned to frame\n");
993: }
994: #endif
995: sock_close(f);
996: return 0;
997: }
998: if (s != NULL && size > f->ralign) {
999: #ifdef DEBUG
1000: if (log_level >= 1) {
1001: sock_log(f);
1002: log_puts(": size = ");
1003: log_puti(size);
1004: log_puts(": ralign = ");
1005: log_puti(f->ralign);
1006: log_puts(": not aligned to block\n");
1007: }
1008: #endif
1009: sock_close(f);
1010: return 0;
1011: }
1012: f->rstate = SOCK_RDATA;
1013: f->rsize = f->rtodo = size;
1014: if (s != NULL) {
1015: f->ralign -= size;
1016: if (f->ralign == 0)
1017: f->ralign = s->round * s->mix.bpf;
1018: }
1019: if (f->rtodo > f->rmax) {
1020: #ifdef DEBUG
1021: if (log_level >= 1) {
1022: sock_log(f);
1023: log_puts(": unexpected data, size = ");
1024: log_putu(size);
1025: log_puts(", rmax = ");
1026: log_putu(f->rmax);
1027: log_puts("\n");
1028: }
1029: #endif
1030: sock_close(f);
1031: return 0;
1032: }
1033: f->rmax -= f->rtodo;
1034: if (f->rtodo == 0) {
1035: #ifdef DEBUG
1036: if (log_level >= 1) {
1037: sock_log(f);
1038: log_puts(": zero-length data chunk\n");
1039: }
1040: #endif
1041: sock_close(f);
1042: return 0;
1043: }
1044: break;
1045: case AMSG_START:
1046: #ifdef DEBUG
1047: if (log_level >= 3) {
1048: sock_log(f);
1049: log_puts(": START message\n");
1050: }
1051: #endif
1.15 ratchov 1052: if (f->pstate != SOCK_INIT || s == NULL) {
1.1 ratchov 1053: #ifdef DEBUG
1054: if (log_level >= 1) {
1055: sock_log(f);
1056: log_puts(": START, wrong state\n");
1057: }
1058: #endif
1059: sock_close(f);
1060: return 0;
1061: }
1062: f->tickpending = 0;
1063: f->stoppending = 0;
1064: slot_start(s);
1065: if (s->mode & MODE_PLAY) {
1066: f->fillpending = s->appbufsz;
1067: f->ralign = s->round * s->mix.bpf;
1068: f->rmax = 0;
1069: }
1070: if (s->mode & MODE_RECMASK) {
1071: f->walign = s->round * s->sub.bpf;
1072: f->wmax = 0;
1073: }
1074: f->pstate = SOCK_START;
1075: f->rstate = SOCK_RMSG;
1076: f->rtodo = sizeof(struct amsg);
1077: if (log_level >= 2) {
1078: slot_log(f->slot);
1079: log_puts(": ");
1080: log_putu(s->rate);
1081: log_puts("Hz, ");
1082: aparams_log(&s->par);
1083: if (s->mode & MODE_PLAY) {
1084: log_puts(", play ");
1.27 ratchov 1085: log_puti(s->opt->pmin);
1.1 ratchov 1086: log_puts(":");
1.28 ratchov 1087: log_puti(s->opt->pmin + s->mix.nch - 1);
1.1 ratchov 1088: }
1089: if (s->mode & MODE_RECMASK) {
1090: log_puts(", rec ");
1.27 ratchov 1091: log_puti(s->opt->rmin);
1.1 ratchov 1092: log_puts(":");
1.28 ratchov 1093: log_puti(s->opt->rmin + s->sub.nch - 1);
1.1 ratchov 1094: }
1095: log_puts(", ");
1096: log_putu(s->appbufsz / s->round);
1097: log_puts(" blocks of ");
1098: log_putu(s->round);
1099: log_puts(" frames\n");
1100: }
1101: break;
1102: case AMSG_STOP:
1103: #ifdef DEBUG
1104: if (log_level >= 3) {
1105: sock_log(f);
1106: log_puts(": STOP message\n");
1107: }
1108: #endif
1109: if (f->pstate != SOCK_START) {
1110: #ifdef DEBUG
1111: if (log_level >= 1) {
1112: sock_log(f);
1113: log_puts(": STOP, wrong state\n");
1114: }
1115: #endif
1116: sock_close(f);
1117: return 0;
1118: }
1119: f->rmax = 0;
1120: if (!(s->mode & MODE_PLAY))
1121: f->stoppending = 1;
1122: f->pstate = SOCK_STOP;
1123: f->rstate = SOCK_RMSG;
1124: f->rtodo = sizeof(struct amsg);
1125: if (s->mode & MODE_PLAY) {
1126: if (f->ralign < s->round * s->mix.bpf) {
1127: data = abuf_wgetblk(&s->mix.buf, &size);
1128: #ifdef DEBUG
1129: if (size < f->ralign) {
1130: sock_log(f);
1131: log_puts(": unaligned stop, size = ");
1132: log_putu(size);
1133: log_puts(", ralign = ");
1134: log_putu(f->ralign);
1135: log_puts("\n");
1136: panic();
1137: }
1138: #endif
1139: memset(data, 0, f->ralign);
1140: abuf_wcommit(&s->mix.buf, f->ralign);
1141: f->ralign = s->round * s->mix.bpf;
1142: }
1143: }
1.36 ! ratchov 1144: slot_stop(s, 1);
1.1 ratchov 1145: break;
1146: case AMSG_SETPAR:
1147: #ifdef DEBUG
1148: if (log_level >= 3) {
1149: sock_log(f);
1150: log_puts(": SETPAR message\n");
1151: }
1152: #endif
1.15 ratchov 1153: if (f->pstate != SOCK_INIT || s == NULL) {
1.1 ratchov 1154: #ifdef DEBUG
1155: if (log_level >= 1) {
1156: sock_log(f);
1157: log_puts(": SETPAR, wrong state\n");
1158: }
1159: #endif
1160: sock_close(f);
1161: return 0;
1162: }
1163: if (!sock_setpar(f)) {
1164: sock_close(f);
1165: return 0;
1166: }
1167: f->rtodo = sizeof(struct amsg);
1168: f->rstate = SOCK_RMSG;
1169: break;
1170: case AMSG_GETPAR:
1171: #ifdef DEBUG
1172: if (log_level >= 3) {
1173: sock_log(f);
1174: log_puts(": GETPAR message\n");
1175: }
1176: #endif
1.15 ratchov 1177: if (f->pstate != SOCK_INIT || s == NULL) {
1.1 ratchov 1178: #ifdef DEBUG
1179: if (log_level >= 1) {
1180: sock_log(f);
1181: log_puts(": GETPAR, wrong state\n");
1182: }
1183: #endif
1184: sock_close(f);
1185: return 0;
1186: }
1187: AMSG_INIT(m);
1188: m->cmd = htonl(AMSG_GETPAR);
1189: m->u.par.legacy_mode = s->mode;
1.14 ratchov 1190: m->u.par.xrun = s->xrun;
1.1 ratchov 1191: m->u.par.bits = s->par.bits;
1192: m->u.par.bps = s->par.bps;
1193: m->u.par.sig = s->par.sig;
1194: m->u.par.le = s->par.le;
1195: m->u.par.msb = s->par.msb;
1.28 ratchov 1196: if (s->mode & MODE_PLAY)
1197: m->u.par.pchan = htons(s->mix.nch);
1198: if (s->mode & MODE_RECMASK)
1199: m->u.par.rchan = htons(s->sub.nch);
1.1 ratchov 1200: m->u.par.rate = htonl(s->rate);
1201: m->u.par.appbufsz = htonl(s->appbufsz);
1202: m->u.par.bufsz = htonl(SLOT_BUFSZ(s));
1203: m->u.par.round = htonl(s->round);
1204: f->rstate = SOCK_RRET;
1205: f->rtodo = sizeof(struct amsg);
1206: break;
1207: case AMSG_SETVOL:
1208: #ifdef DEBUG
1209: if (log_level >= 3) {
1210: sock_log(f);
1211: log_puts(": SETVOL message\n");
1212: }
1213: #endif
1.15 ratchov 1214: if (f->pstate < SOCK_INIT || s == NULL) {
1.1 ratchov 1215: #ifdef DEBUG
1216: if (log_level >= 1) {
1217: sock_log(f);
1218: log_puts(": SETVOL, wrong state\n");
1219: }
1220: #endif
1221: sock_close(f);
1222: return 0;
1223: }
1224: ctl = ntohl(m->u.vol.ctl);
1225: if (ctl > MIDI_MAXCTL) {
1226: #ifdef DEBUG
1227: if (log_level >= 1) {
1228: sock_log(f);
1229: log_puts(": SETVOL, volume out of range\n");
1230: }
1231: #endif
1232: sock_close(f);
1233: return 0;
1234: }
1235: f->rtodo = sizeof(struct amsg);
1236: f->rstate = SOCK_RMSG;
1237: f->lastvol = ctl; /* dont trigger feedback message */
1.15 ratchov 1238: slot_setvol(s, ctl);
1.1 ratchov 1239: dev_midi_vol(s->dev, s);
1.32 ratchov 1240: dev_onval(s->dev,
1241: CTLADDR_SLOT_LEVEL(f->slot - s->dev->slot), ctl);
1242: break;
1243: case AMSG_CTLSUB:
1244: #ifdef DEBUG
1245: if (log_level >= 3) {
1246: sock_log(f);
1247: log_puts(": CTLSUB message, desc = ");
1248: log_putx(m->u.ctlsub.desc);
1249: log_puts(", val = ");
1250: log_putx(m->u.ctlsub.val);
1251: log_puts("\n");
1252: }
1253: #endif
1254: if (f->pstate != SOCK_INIT || f->ctlslot == NULL) {
1255: #ifdef DEBUG
1256: if (log_level >= 1) {
1257: sock_log(f);
1258: log_puts(": CTLSUB, wrong state\n");
1259: }
1260: #endif
1261: sock_close(f);
1262: return 0;
1263: }
1264: if (m->u.ctlsub.desc) {
1265: if (!(f->ctlops & SOCK_CTLDESC)) {
1266: ctl = f->ctlslot->mask;
1267: c = f->ctlslot->dev->ctl_list;
1268: while (c != NULL) {
1269: c->desc_mask |= ctl;
1270: c = c->next;
1271: }
1.33 ratchov 1272: f->ctlops |= SOCK_CTLDESC;
1273: f->ctlsyncpending = 1;
1.32 ratchov 1274: }
1275: } else
1276: f->ctlops &= ~SOCK_CTLDESC;
1277: if (m->u.ctlsub.val) {
1278: f->ctlops |= SOCK_CTLVAL;
1279: } else
1280: f->ctlops &= ~SOCK_CTLVAL;
1281: f->rstate = SOCK_RMSG;
1282: f->rtodo = sizeof(struct amsg);
1283: break;
1284: case AMSG_CTLSET:
1285: #ifdef DEBUG
1286: if (log_level >= 3) {
1287: sock_log(f);
1288: log_puts(": CTLSET message\n");
1289: }
1290: #endif
1291: if (f->pstate < SOCK_INIT || f->ctlslot == NULL) {
1292: #ifdef DEBUG
1293: if (log_level >= 1) {
1294: sock_log(f);
1295: log_puts(": CTLSET, wrong state\n");
1296: }
1297: #endif
1298: sock_close(f);
1299: return 0;
1300: }
1301: if (!dev_setctl(f->ctlslot->dev,
1302: ntohs(m->u.ctlset.addr),
1303: ntohs(m->u.ctlset.val))) {
1304: #ifdef DEBUG
1305: if (log_level >= 1) {
1306: sock_log(f);
1307: log_puts(": CTLSET, wrong addr/val\n");
1308: }
1309: #endif
1310: sock_close(f);
1311: return 0;
1312: }
1313: f->rtodo = sizeof(struct amsg);
1314: f->rstate = SOCK_RMSG;
1.1 ratchov 1315: break;
1316: case AMSG_AUTH:
1317: #ifdef DEBUG
1318: if (log_level >= 3) {
1319: sock_log(f);
1320: log_puts(": AUTH message\n");
1321: }
1322: #endif
1323: if (f->pstate != SOCK_AUTH) {
1324: #ifdef DEBUG
1325: if (log_level >= 1) {
1326: sock_log(f);
1327: log_puts(": AUTH, wrong state\n");
1328: }
1329: #endif
1330: sock_close(f);
1331: return 0;
1332: }
1333: if (!sock_auth(f)) {
1334: sock_close(f);
1335: return 0;
1336: }
1337: f->rstate = SOCK_RMSG;
1338: f->rtodo = sizeof(struct amsg);
1339: break;
1340: case AMSG_HELLO:
1341: #ifdef DEBUG
1342: if (log_level >= 3) {
1343: sock_log(f);
1344: log_puts(": HELLO message\n");
1345: }
1346: #endif
1347: if (f->pstate != SOCK_HELLO) {
1348: #ifdef DEBUG
1349: if (log_level >= 1) {
1350: sock_log(f);
1351: log_puts(": HELLO, wrong state\n");
1352: }
1353: #endif
1354: sock_close(f);
1355: return 0;
1356: }
1357: if (!sock_hello(f)) {
1358: sock_close(f);
1359: return 0;
1360: }
1361: AMSG_INIT(m);
1362: m->cmd = htonl(AMSG_ACK);
1363: f->rstate = SOCK_RRET;
1364: f->rtodo = sizeof(struct amsg);
1365: break;
1366: case AMSG_BYE:
1367: #ifdef DEBUG
1368: if (log_level >= 3) {
1369: sock_log(f);
1370: log_puts(": BYE message\n");
1371: }
1372: #endif
1373: if (s != NULL && f->pstate != SOCK_INIT) {
1374: #ifdef DEBUG
1375: if (log_level >= 1) {
1376: sock_log(f);
1377: log_puts(": BYE, wrong state\n");
1378: }
1379: #endif
1380: }
1381: sock_close(f);
1382: return 0;
1383: default:
1384: #ifdef DEBUG
1385: if (log_level >= 1) {
1386: sock_log(f);
1387: log_puts(": unknown command in message\n");
1388: }
1389: #endif
1390: sock_close(f);
1391: return 0;
1392: }
1393: return 1;
1394: }
1395:
1396: /*
1397: * build a message in f->wmsg, return 1 on success and 0 if
1398: * there's nothing to do. Assume f->wstate is SOCK_WIDLE
1399: */
1400: int
1401: sock_buildmsg(struct sock *f)
1402: {
1.32 ratchov 1403: unsigned int size, mask;
1404: struct amsg_ctl_desc *desc;
1405: struct ctl *c, **pc;
1.1 ratchov 1406:
1407: /*
1408: * If pos changed (or initial tick), build a MOVE message.
1409: */
1410: if (f->tickpending) {
1411: #ifdef DEBUG
1412: if (log_level >= 4) {
1413: sock_log(f);
1414: log_puts(": building MOVE message, delta = ");
1415: log_puti(f->slot->delta);
1416: log_puts("\n");
1417: }
1418: #endif
1419: AMSG_INIT(&f->wmsg);
1420: f->wmsg.cmd = htonl(AMSG_MOVE);
1421: f->wmsg.u.ts.delta = htonl(f->slot->delta);
1422: f->wtodo = sizeof(struct amsg);
1423: f->wstate = SOCK_WMSG;
1424: f->tickpending = 0;
1425: /*
1426: * XXX: use tickpending as accumulator rather than
1427: * slot->delta
1428: */
1429: f->slot->delta = 0;
1430: return 1;
1431: }
1432:
1433: if (f->fillpending > 0) {
1434: AMSG_INIT(&f->wmsg);
1.17 ratchov 1435: f->wmsg.cmd = htonl(AMSG_FLOWCTL);
1.1 ratchov 1436: f->wmsg.u.ts.delta = htonl(f->fillpending);
1437: size = f->fillpending;
1438: if (f->slot)
1439: size *= f->slot->mix.bpf;
1440: f->rmax += size;
1441: #ifdef DEBUG
1442: if (log_level >= 4) {
1443: sock_log(f);
1444: log_puts(": building FLOWCTL message, count = ");
1445: log_puti(f->fillpending);
1446: log_puts(", rmax -> ");
1447: log_puti(f->rmax);
1448: log_puts("\n");
1449: }
1450: #endif
1451: f->wtodo = sizeof(struct amsg);
1452: f->wstate = SOCK_WMSG;
1453: f->fillpending = 0;
1454: return 1;
1455: }
1456:
1457: /*
1458: * if volume changed build a SETVOL message
1459: */
1460: if (f->pstate >= SOCK_START && f->slot->vol != f->lastvol) {
1461: #ifdef DEBUG
1462: if (log_level >= 3) {
1463: sock_log(f);
1464: log_puts(": building SETVOL message, vol = ");
1465: log_puti(f->slot->vol);
1466: log_puts("\n");
1467: }
1468: #endif
1469: AMSG_INIT(&f->wmsg);
1470: f->wmsg.cmd = htonl(AMSG_SETVOL);
1471: f->wmsg.u.vol.ctl = htonl(f->slot->vol);
1472: f->wtodo = sizeof(struct amsg);
1473: f->wstate = SOCK_WMSG;
1474: f->lastvol = f->slot->vol;
1475: return 1;
1476: }
1477:
1478: if (f->midi != NULL && f->midi->obuf.used > 0) {
1.17 ratchov 1479: size = f->midi->obuf.used;
1.1 ratchov 1480: if (size > AMSG_DATAMAX)
1481: size = AMSG_DATAMAX;
1482: AMSG_INIT(&f->wmsg);
1483: f->wmsg.cmd = htonl(AMSG_DATA);
1484: f->wmsg.u.data.size = htonl(size);
1485: f->wtodo = sizeof(struct amsg);
1486: f->wstate = SOCK_WMSG;
1487: return 1;
1488: }
1489:
1490: /*
1491: * If data available, build a DATA message.
1492: */
1.10 ratchov 1493: if (f->slot != NULL && f->wmax > 0 && f->slot->sub.buf.used > 0) {
1.1 ratchov 1494: size = f->slot->sub.buf.used;
1495: if (size > AMSG_DATAMAX)
1496: size = AMSG_DATAMAX;
1497: if (size > f->walign)
1498: size = f->walign;
1499: if (size > f->wmax)
1500: size = f->wmax;
1501: size -= size % f->slot->sub.bpf;
1502: #ifdef DEBUG
1503: if (size == 0) {
1504: sock_log(f);
1505: log_puts(": sock_buildmsg size == 0\n");
1506: panic();
1507: }
1508: #endif
1509: f->walign -= size;
1510: f->wmax -= size;
1511: if (f->walign == 0)
1512: f->walign = f->slot->round * f->slot->sub.bpf;
1513: #ifdef DEBUG
1514: if (log_level >= 4) {
1515: sock_log(f);
1516: log_puts(": building audio DATA message, size = ");
1517: log_puti(size);
1518: log_puts("\n");
1519: }
1520: #endif
1521: AMSG_INIT(&f->wmsg);
1522: f->wmsg.cmd = htonl(AMSG_DATA);
1523: f->wmsg.u.data.size = htonl(size);
1524: f->wtodo = sizeof(struct amsg);
1525: f->wstate = SOCK_WMSG;
1526: return 1;
1527: }
1528:
1529: if (f->stoppending) {
1530: #ifdef DEBUG
1531: if (log_level >= 3) {
1532: sock_log(f);
1533: log_puts(": building STOP message\n");
1534: }
1535: #endif
1536: f->stoppending = 0;
1537: f->pstate = SOCK_INIT;
1538: AMSG_INIT(&f->wmsg);
1539: f->wmsg.cmd = htonl(AMSG_STOP);
1540: f->wtodo = sizeof(struct amsg);
1541: f->wstate = SOCK_WMSG;
1.32 ratchov 1542: return 1;
1543: }
1544:
1545: /*
1546: * XXX: add a flag indicating if there are changes
1547: * in controls not seen by this client, rather
1548: * than walking through the full list of control
1549: * searching for the {desc,val}_mask bits
1550: */
1551: if (f->ctlslot && (f->ctlops & SOCK_CTLDESC)) {
1552: desc = f->ctldesc;
1553: mask = f->ctlslot->mask;
1554: size = 0;
1555: pc = &f->ctlslot->dev->ctl_list;
1556: while ((c = *pc) != NULL) {
1557: if ((c->desc_mask & mask) == 0 ||
1558: (c->refs_mask & mask) == 0) {
1559: pc = &c->next;
1560: continue;
1561: }
1562: if (size == SOCK_CTLDESC_SIZE *
1563: sizeof(struct amsg_ctl_desc))
1564: break;
1565: c->desc_mask &= ~mask;
1566: c->val_mask &= ~mask;
1567: strlcpy(desc->group, c->group,
1568: AMSG_CTL_NAMEMAX);
1569: strlcpy(desc->node0.name, c->node0.name,
1570: AMSG_CTL_NAMEMAX);
1571: desc->node0.unit = ntohs(c->node0.unit);
1572: strlcpy(desc->node1.name, c->node1.name,
1573: AMSG_CTL_NAMEMAX);
1574: desc->node1.unit = ntohs(c->node1.unit);
1575: desc->type = c->type;
1576: strlcpy(desc->func, c->func, AMSG_CTL_NAMEMAX);
1577: desc->addr = htons(c->addr);
1578: desc->maxval = htons(c->maxval);
1579: desc->curval = htons(c->curval);
1580: size += sizeof(struct amsg_ctl_desc);
1581: desc++;
1582:
1583: /* if this is a deleted entry unref it */
1584: if (c->type == CTL_NONE) {
1585: c->refs_mask &= ~mask;
1586: if (c->refs_mask == 0) {
1587: *pc = c->next;
1588: xfree(c);
1589: continue;
1590: }
1591: }
1592:
1593: pc = &c->next;
1594: }
1595: if (size > 0) {
1596: AMSG_INIT(&f->wmsg);
1597: f->wmsg.cmd = htonl(AMSG_DATA);
1598: f->wmsg.u.data.size = htonl(size);
1599: f->wtodo = sizeof(struct amsg);
1600: f->wstate = SOCK_WMSG;
1601: #ifdef DEBUG
1602: if (log_level >= 3) {
1603: sock_log(f);
1604: log_puts(": building control DATA message\n");
1605: }
1606: #endif
1607: return 1;
1608: }
1609: }
1610: if (f->ctlslot && (f->ctlops & SOCK_CTLVAL)) {
1611: mask = f->ctlslot->mask;
1612: for (c = f->ctlslot->dev->ctl_list; c != NULL; c = c->next) {
1613: if ((c->val_mask & mask) == 0)
1614: continue;
1615: c->val_mask &= ~mask;
1616: AMSG_INIT(&f->wmsg);
1617: f->wmsg.cmd = htonl(AMSG_CTLSET);
1618: f->wmsg.u.ctlset.addr = htons(c->addr);
1619: f->wmsg.u.ctlset.val = htons(c->curval);
1620: f->wtodo = sizeof(struct amsg);
1621: f->wstate = SOCK_WMSG;
1622: #ifdef DEBUG
1623: if (log_level >= 3) {
1624: sock_log(f);
1625: log_puts(": building CTLSET message\n");
1626: }
1627: #endif
1628: return 1;
1629: }
1630: }
1631: if (f->ctlslot && f->ctlsyncpending) {
1632: f->ctlsyncpending = 0;
1633: f->wmsg.cmd = htonl(AMSG_CTLSYNC);
1634: f->wtodo = sizeof(struct amsg);
1635: f->wstate = SOCK_WMSG;
1636: #ifdef DEBUG
1637: if (log_level >= 3) {
1638: sock_log(f);
1639: log_puts(": building CTLSYNC message\n");
1640: }
1641: #endif
1.1 ratchov 1642: return 1;
1643: }
1644: #ifdef DEBUG
1645: if (log_level >= 4) {
1646: sock_log(f);
1647: log_puts(": no messages to build anymore, idling...\n");
1648: }
1649: #endif
1650: f->wstate = SOCK_WIDLE;
1651: return 0;
1652: }
1653:
1654: /*
1655: * iteration of the socket reader loop, return 1 on success
1656: */
1657: int
1658: sock_read(struct sock *f)
1659: {
1660: #ifdef DEBUG
1661: if (log_level >= 4) {
1662: sock_log(f);
1663: log_puts(": reading ");
1664: log_putu(f->rtodo);
1665: log_puts(" todo\n");
1666: }
1667: #endif
1668: switch (f->rstate) {
1669: case SOCK_RIDLE:
1670: return 0;
1671: case SOCK_RMSG:
1672: if (!sock_rmsg(f))
1673: return 0;
1674: if (!sock_execmsg(f))
1675: return 0;
1676: break;
1677: case SOCK_RDATA:
1678: if (!sock_rdata(f))
1679: return 0;
1680: f->rstate = SOCK_RMSG;
1681: f->rtodo = sizeof(struct amsg);
1682: break;
1683: case SOCK_RRET:
1684: if (f->wstate != SOCK_WIDLE) {
1685: #ifdef DEBUG
1686: if (log_level >= 4) {
1687: sock_log(f);
1688: log_puts(": can't reply, write-end blocked\n");
1689: }
1690: #endif
1691: return 0;
1692: }
1693: f->wmsg = f->rmsg;
1694: f->wstate = SOCK_WMSG;
1695: f->wtodo = sizeof(struct amsg);
1696: f->rstate = SOCK_RMSG;
1697: f->rtodo = sizeof(struct amsg);
1698: #ifdef DEBUG
1699: if (log_level >= 4) {
1700: sock_log(f);
1701: log_puts(": copied RRET message\n");
1702: }
1703: #endif
1704: }
1705: return 1;
1706: }
1707:
1708: /*
1709: * iteration of the socket writer loop, return 1 on success
1710: */
1711: int
1712: sock_write(struct sock *f)
1713: {
1714: #ifdef DEBUG
1715: if (log_level >= 4) {
1716: sock_log(f);
1717: log_puts(": writing");
1718: if (f->wstate != SOCK_WIDLE) {
1719: log_puts(" todo = ");
1720: log_putu(f->wtodo);
1721: }
1722: log_puts("\n");
1723: }
1724: #endif
1725: switch (f->wstate) {
1726: case SOCK_WMSG:
1727: if (!sock_wmsg(f))
1728: return 0;
1.20 ratchov 1729: /*
1730: * f->wmsg is either build by sock_buildmsg() or
1731: * copied from f->rmsg (in the SOCK_RRET state), so
1732: * it's safe.
1733: */
1.1 ratchov 1734: if (ntohl(f->wmsg.cmd) != AMSG_DATA) {
1735: f->wstate = SOCK_WIDLE;
1736: f->wtodo = 0xdeadbeef;
1737: break;
1738: }
1739: f->wstate = SOCK_WDATA;
1740: f->wsize = f->wtodo = ntohl(f->wmsg.u.data.size);
1741: /* PASSTHROUGH */
1742: case SOCK_WDATA:
1743: if (!sock_wdata(f))
1744: return 0;
1745: if (f->wtodo > 0)
1746: break;
1747: f->wstate = SOCK_WIDLE;
1748: f->wtodo = 0xdeadbeef;
1749: if (f->pstate == SOCK_STOP) {
1750: f->pstate = SOCK_INIT;
1751: f->wmax = 0;
1752: #ifdef DEBUG
1753: if (log_level >= 4) {
1754: sock_log(f);
1755: log_puts(": drained, moved to INIT state\n");
1756: }
1757: #endif
1758: }
1759: /* PASSTHROUGH */
1760: case SOCK_WIDLE:
1761: if (f->rstate == SOCK_RRET) {
1762: f->wmsg = f->rmsg;
1763: f->wstate = SOCK_WMSG;
1764: f->wtodo = sizeof(struct amsg);
1765: f->rstate = SOCK_RMSG;
1766: f->rtodo = sizeof(struct amsg);
1767: #ifdef DEBUG
1768: if (log_level >= 4) {
1769: sock_log(f);
1770: log_puts(": copied RRET message\n");
1771: }
1772: #endif
1773: } else {
1774: if (!sock_buildmsg(f))
1775: return 0;
1776: }
1777: break;
1778: #ifdef DEBUG
1779: default:
1780: sock_log(f);
1781: log_puts(": bad writing end state\n");
1782: panic();
1783: #endif
1784: }
1785: return 1;
1786: }
1787:
1788: int
1789: sock_pollfd(void *arg, struct pollfd *pfd)
1790: {
1791: struct sock *f = arg;
1792: int events = 0;
1793:
1794: /*
1795: * feedback counters, clock ticks and alike may have changed,
1796: * prepare a message to trigger writes
1797: *
1798: * XXX: doing this at the beginning of the cycle is not optimal,
1799: * because state is changed at the end of the read cycle, and
1800: * thus counters, ret message and alike are generated then.
1801: */
1802: if (f->wstate == SOCK_WIDLE && f->rstate != SOCK_RRET)
1803: sock_buildmsg(f);
1804:
1805: if (f->rstate == SOCK_RMSG ||
1806: f->rstate == SOCK_RDATA)
1807: events |= POLLIN;
1808: if (f->rstate == SOCK_RRET ||
1809: f->wstate == SOCK_WMSG ||
1810: f->wstate == SOCK_WDATA)
1811: events |= POLLOUT;
1812: pfd->fd = f->fd;
1813: pfd->events = events;
1814: return 1;
1815: }
1816:
1817: int
1818: sock_revents(void *arg, struct pollfd *pfd)
1819: {
1820: return pfd->revents;
1821: }
1822:
1823: void
1824: sock_in(void *arg)
1825: {
1826: struct sock *f = arg;
1827:
1828: while (sock_read(f))
1829: ;
1830: }
1831:
1832: void
1833: sock_out(void *arg)
1834: {
1835: struct sock *f = arg;
1836:
1837: while (sock_write(f))
1838: ;
1839: }
1840:
1841: void
1842: sock_hup(void *arg)
1843: {
1844: struct sock *f = arg;
1845:
1846: sock_close(f);
1847: }