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