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