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