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