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