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