xref: /openbsd/usr.bin/sndiod/sock.c (revision cecf84d4)
1 /*	$OpenBSD: sock.c,v 1.15 2015/02/16 06:35:17 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 	int n, count;
518 
519 #ifdef DEBUG
520 	if (f->wtodo == 0) {
521 		sock_log(f);
522 		log_puts(": attempted to write zero-sized data block\n");
523 		panic();
524 	}
525 #endif
526 	if (f->pstate == SOCK_STOP) {
527 		while (f->wtodo > 0) {
528 			n = sock_fdwrite(f, dummy, f->wtodo);
529 			if (n == 0)
530 				return 0;
531 			f->wtodo -= n;
532 		}
533 #ifdef DEBUG
534 		if (log_level >= 4) {
535 			sock_log(f);
536 			log_puts(": zero-filled remaining block\n");
537 		}
538 #endif
539 		return 1;
540 	}
541 	while (f->wtodo > 0) {
542 		if (f->slot)
543 			data = abuf_rgetblk(&f->slot->sub.buf, &count);
544 		else if (f->midi)
545 			data = abuf_rgetblk(&f->midi->obuf, &count);
546 		if (count > f->wtodo)
547 			count = f->wtodo;
548 		n = sock_fdwrite(f, data, count);
549 		if (n == 0)
550 			return 0;
551 		f->wtodo -= n;
552 		if (f->slot)
553 			abuf_rdiscard(&f->slot->sub.buf, n);
554 		else if (f->midi)
555 			abuf_rdiscard(&f->midi->obuf, n);
556 	}
557 	if (f->slot)
558 		slot_read(f->slot);
559 	if (f->midi)
560 		midi_fill(f->midi);
561 #ifdef DEBUG
562 	if (log_level >= 4) {
563 		sock_log(f);
564 		log_puts(": wrote complete block\n");
565 	}
566 #endif
567 	return 1;
568 }
569 
570 int
571 sock_setpar(struct sock *f)
572 {
573 	struct slot *s = f->slot;
574 	struct dev *d = s->dev;
575 	struct amsg_par *p = &f->rmsg.u.par;
576 	unsigned int min, max;
577 	uint32_t rate, appbufsz;
578 	uint16_t pchan, rchan;
579 
580 	rchan = ntohs(p->rchan);
581 	pchan = ntohs(p->pchan);
582 	appbufsz = ntohl(p->appbufsz);
583 	rate = ntohl(p->rate);
584 
585 	if (AMSG_ISSET(p->bits)) {
586 		if (p->bits < BITS_MIN || p->bits > BITS_MAX) {
587 #ifdef DEBUG
588 			if (log_level >= 1) {
589 				sock_log(f);
590 				log_puts(": ");
591 				log_putu(p->bits);
592 				log_puts(": bits out of bounds\n");
593 			}
594 #endif
595 			return 0;
596 		}
597 		if (AMSG_ISSET(p->bps)) {
598 			if (p->bps < ((p->bits + 7) / 8) || p->bps > 4) {
599 #ifdef DEBUG
600 				if (log_level >= 1) {
601 					sock_log(f);
602 					log_puts(": ");
603 					log_putu(p->bps);
604 					log_puts(": wrong bytes per sample\n");
605 				}
606 #endif
607 				return 0;
608 			}
609 		} else
610 			p->bps = APARAMS_BPS(p->bits);
611 		s->par.bits = p->bits;
612 		s->par.bps = p->bps;
613 	}
614 	if (AMSG_ISSET(p->sig))
615 		s->par.sig = p->sig ? 1 : 0;
616 	if (AMSG_ISSET(p->le))
617 		s->par.le = p->le ? 1 : 0;
618 	if (AMSG_ISSET(p->msb))
619 		s->par.msb = p->msb ? 1 : 0;
620 	if (AMSG_ISSET(rchan) && (s->mode & MODE_RECMASK)) {
621 		if (rchan < 1)
622 			rchan = 1;
623 		if (rchan > NCHAN_MAX)
624 			rchan = NCHAN_MAX;
625 		s->sub.slot_cmin = f->opt->rmin;
626 		s->sub.slot_cmax = f->opt->rmin + rchan - 1;
627 		s->sub.dev_cmin = f->opt->rmin;
628 		s->sub.dev_cmax = f->opt->rmax;
629 #ifdef DEBUG
630 		if (log_level >= 3) {
631 			sock_log(f);
632 			log_puts(": recording channels ");
633 			log_putu(s->sub.dev_cmin);
634 			log_puts(":");
635 			log_putu(s->sub.dev_cmax);
636 			log_puts(" -> ");
637 			log_putu(s->sub.slot_cmin);
638 			log_puts(":");
639 			log_putu(s->sub.slot_cmax);
640 			log_puts("\n");
641 		}
642 #endif
643 	}
644 	if (AMSG_ISSET(pchan) && (s->mode & MODE_PLAY)) {
645 		if (pchan < 1)
646 			pchan = 1;
647 		if (pchan > NCHAN_MAX)
648 			pchan = NCHAN_MAX;
649 		s->mix.slot_cmin = f->opt->pmin;
650 		s->mix.slot_cmax = f->opt->pmin + pchan - 1;
651 		s->mix.dev_cmin = f->opt->pmin;
652 		s->mix.dev_cmax = f->opt->pmax;
653 #ifdef DEBUG
654 		if (log_level >= 3) {
655 			sock_log(f);
656 			log_puts(": playback channels ");
657 			log_putu(s->mix.slot_cmin);
658 			log_puts(":");
659 			log_putu(s->mix.slot_cmax);
660 			log_puts(" -> ");
661 			log_putu(s->mix.dev_cmin);
662 			log_puts(":");
663 			log_putu(s->mix.dev_cmax);
664 			log_puts("\n");
665 		}
666 #endif
667 	}
668 	if (AMSG_ISSET(rate)) {
669 		if (rate < RATE_MIN)
670 			rate = RATE_MIN;
671 		if (rate > RATE_MAX)
672 			rate = RATE_MAX;
673 		s->round = dev_roundof(d, rate);
674 		s->rate = rate;
675 		if (!AMSG_ISSET(appbufsz)) {
676 			appbufsz = d->bufsz / d->round * s->round;
677 #ifdef DEBUG
678 			if (log_level >= 3) {
679 				sock_log(f);
680 				log_puts(": ");
681 				log_putu(appbufsz);
682 				log_puts(" frame buffer\n");
683 			}
684 #endif
685 		}
686 #ifdef DEBUG
687 		if (log_level >= 3) {
688 			sock_log(f);
689 			log_puts(": ");
690 			log_putu(rate);
691 			log_puts("Hz sample rate, ");
692 			log_putu(s->round);
693 			log_puts(" frame blocks\n");
694 		}
695 #endif
696 	}
697 	if (AMSG_ISSET(p->xrun)) {
698 		if (p->xrun != XRUN_IGNORE &&
699 		    p->xrun != XRUN_SYNC &&
700 		    p->xrun != XRUN_ERROR) {
701 #ifdef DEBUG
702 			if (log_level >= 1) {
703 				sock_log(f);
704 				log_puts(": ");
705 				log_putx(p->xrun);
706 				log_puts(": bad xrun policy\n");
707 			}
708 #endif
709 			return 0;
710 		}
711 		s->xrun = p->xrun;
712 		if (f->opt->mmc && s->xrun == XRUN_IGNORE)
713 			s->xrun = XRUN_SYNC;
714 #ifdef DEBUG
715 		if (log_level >= 3) {
716 			sock_log(f);
717 			log_puts(": 0x");
718 			log_putx(s->xrun);
719 			log_puts(" xrun policy\n");
720 		}
721 #endif
722 	}
723 	if (AMSG_ISSET(appbufsz)) {
724 		rate = s->rate;
725 		min = 1;
726 		max = 1 + rate / d->round;
727 		min *= s->round;
728 		max *= s->round;
729 		appbufsz += s->round / 2;
730 		appbufsz -= appbufsz % s->round;
731 		if (appbufsz < min)
732 			appbufsz = min;
733 		if (appbufsz > max)
734 			appbufsz = max;
735 		s->appbufsz = appbufsz;
736 #ifdef DEBUG
737 		if (log_level >= 3) {
738 			sock_log(f);
739 			log_puts(": ");
740 			log_putu(s->appbufsz);
741 			log_puts(" frame buffer\n");
742 		}
743 #endif
744 	}
745 	return 1;
746 }
747 
748 int
749 sock_auth(struct sock *f)
750 {
751 	struct amsg_auth *p = &f->rmsg.u.auth;
752 
753 	if (sock_sesrefs == 0) {
754 		/* start a new session */
755 		memcpy(sock_sescookie, p->cookie, AMSG_COOKIELEN);
756 	} else if (memcmp(sock_sescookie, p->cookie, AMSG_COOKIELEN) != 0) {
757 		/* another session is active, drop connection */
758 		return 0;
759 	}
760 	sock_sesrefs++;
761 	f->pstate = SOCK_HELLO;
762 	return 1;
763 }
764 
765 int
766 sock_hello(struct sock *f)
767 {
768 	struct amsg_hello *p = &f->rmsg.u.hello;
769 	struct slot *s;
770 	struct port *c;
771 	struct dev *d;
772 	unsigned int mode;
773 
774 	mode = ntohs(p->mode);
775 #ifdef DEBUG
776 	if (log_level >= 3) {
777 		sock_log(f);
778 		log_puts(": hello from <");
779 		log_puts(p->who);
780 		log_puts(">, mode = ");
781 		log_putx(mode);
782 		log_puts(", ver ");
783 		log_putu(p->version);
784 		log_puts("\n");
785 	}
786 #endif
787 	if (p->version != AMSG_VERSION) {
788 		if (log_level >= 1) {
789 			sock_log(f);
790 			log_puts(": ");
791 			log_putu(p->version);
792 			log_puts(": unsupported protocol version\n");
793 		}
794 		return 0;
795 	}
796 	switch (mode) {
797 	case MODE_MIDIIN:
798 	case MODE_MIDIOUT:
799 	case MODE_MIDIOUT | MODE_MIDIIN:
800 	case MODE_REC:
801 	case MODE_PLAY:
802 	case MODE_PLAY | MODE_REC:
803 		break;
804 	default:
805 #ifdef DEBUG
806 		if (log_level >= 1) {
807 			sock_log(f);
808 			log_puts(": ");
809 			log_putx(mode);
810 			log_puts(": unsupported mode\n");
811 		}
812 #endif
813 		return 0;
814 	}
815 	f->pstate = SOCK_INIT;
816 	f->port = NULL;
817 	if (mode & MODE_MIDIMASK) {
818 		f->slot = NULL;
819 		f->midi = midi_new(&sock_midiops, f, mode);
820 		if (f->midi == NULL)
821 			return 0;
822 		/* XXX: add 'devtype' to libsndio */
823 		if (p->devnum < 16) {
824 			d = dev_bynum(p->devnum);
825 			if (d == NULL)
826 				return 0;
827 			midi_tag(f->midi, p->devnum);
828 		} else if (p->devnum < 32) {
829 			midi_tag(f->midi, p->devnum);
830 		} else if (p->devnum < 48) {
831 			c = port_bynum(p->devnum - 32);
832 			if (c == NULL || !port_ref(c))
833 				return 0;
834 			f->port = c;
835 			midi_link(f->midi, c->midi);
836 		} else
837 			return 0;
838 		return 1;
839 	}
840 	f->opt = opt_byname(p->opt, p->devnum);
841 	if (f->opt == NULL)
842 		return 0;
843 #ifdef DEBUG
844 	if (log_level >= 3) {
845 		sock_log(f);
846 		log_puts(": using ");
847 		dev_log(f->opt->dev);
848 		log_puts(".");
849 		log_puts(f->opt->name);
850 		log_puts(", mode = ");
851 		log_putx(mode);
852 		log_puts("\n");
853 	}
854 #endif
855 	if ((mode & MODE_REC) && (f->opt->mode & MODE_MON)) {
856 		mode |= MODE_MON;
857 		mode &= ~MODE_REC;
858 	}
859 	if ((mode & f->opt->mode) != mode) {
860 		if (log_level >= 1) {
861 			sock_log(f);
862 			log_puts(": requested mode not allowed\n");
863 		}
864 		return 0;
865 	}
866 	s = slot_new(f->opt->dev, p->who, &sock_slotops, f, mode);
867 	if (s == NULL)
868 		return 0;
869 	f->midi = NULL;
870 	if (s->mode & MODE_PLAY) {
871 		s->mix.slot_cmin = s->mix.dev_cmin = f->opt->pmin;
872 		s->mix.slot_cmax = s->mix.dev_cmax = f->opt->pmax;
873 	}
874 	if (s->mode & MODE_RECMASK) {
875 		s->sub.slot_cmin = s->sub.dev_cmin = f->opt->rmin;
876 		s->sub.slot_cmax = s->sub.dev_cmax = f->opt->rmax;
877 	}
878 	if (f->opt->mmc) {
879 		s->xrun = XRUN_SYNC;
880 		s->tstate = MMC_STOP;
881 	} else {
882 		s->xrun = XRUN_IGNORE;
883 		s->tstate = MMC_OFF;
884 	}
885 	s->mix.maxweight = f->opt->maxweight;
886 	s->dup = f->opt->dup;
887 	f->slot = s;
888 	return 1;
889 }
890 
891 /*
892  * execute the message in f->rmsg, return 1 on success
893  */
894 int
895 sock_execmsg(struct sock *f)
896 {
897 	struct slot *s = f->slot;
898 	struct amsg *m = &f->rmsg;
899 	unsigned char *data;
900 	int size, ctl;
901 
902 	switch (ntohl(m->cmd)) {
903 	case AMSG_DATA:
904 #ifdef DEBUG
905 		if (log_level >= 4) {
906 			sock_log(f);
907 			log_puts(": DATA message\n");
908 		}
909 #endif
910 		if (s != NULL && f->pstate != SOCK_START) {
911 #ifdef DEBUG
912 			if (log_level >= 1) {
913 				sock_log(f);
914 				log_puts(": DATA, wrong state\n");
915 			}
916 #endif
917 			sock_close(f);
918 			return 0;
919 		}
920 		if ((f->slot && !(f->slot->mode & MODE_PLAY)) ||
921 		    (f->midi && !(f->midi->mode & MODE_MIDIOUT))) {
922 #ifdef DEBUG
923 			if (log_level >= 1) {
924 				sock_log(f);
925 				log_puts(": DATA, input-only mode\n");
926 			}
927 #endif
928 			sock_close(f);
929 			return 0;
930 		}
931 		size = ntohl(m->u.data.size);
932 		if (size <= 0) {
933 #ifdef DEBUG
934 			if (log_level >= 1) {
935 				sock_log(f);
936 				log_puts(": zero size payload\n");
937 			}
938 #endif
939 			sock_close(f);
940 			return 0;
941 		}
942 		if (s != NULL && size % s->mix.bpf != 0) {
943 #ifdef DEBUG
944 			if (log_level >= 1) {
945 				sock_log(f);
946 				log_puts(": not aligned to frame\n");
947 			}
948 #endif
949 			sock_close(f);
950 			return 0;
951 		}
952 		if (s != NULL && size > f->ralign) {
953 #ifdef DEBUG
954 			if (log_level >= 1) {
955 				sock_log(f);
956 				log_puts(": size = ");
957 				log_puti(size);
958 				log_puts(": ralign = ");
959 				log_puti(f->ralign);
960 				log_puts(": not aligned to block\n");
961 			}
962 #endif
963 			sock_close(f);
964 			return 0;
965 		}
966 		f->rstate = SOCK_RDATA;
967 		f->rsize = f->rtodo = size;
968 		if (s != NULL) {
969 			f->ralign -= size;
970 			if (f->ralign == 0)
971 				f->ralign = s->round * s->mix.bpf;
972 		}
973 		if (f->rtodo > f->rmax) {
974 #ifdef DEBUG
975 			if (log_level >= 1) {
976 				sock_log(f);
977 				log_puts(": unexpected data, size = ");
978 				log_putu(size);
979 				log_puts(", rmax = ");
980 				log_putu(f->rmax);
981 				log_puts("\n");
982 			}
983 #endif
984 			sock_close(f);
985 			return 0;
986 		}
987 		f->rmax -= f->rtodo;
988 		if (f->rtodo == 0) {
989 #ifdef DEBUG
990 			if (log_level >= 1) {
991 				sock_log(f);
992 				log_puts(": zero-length data chunk\n");
993 			}
994 #endif
995 			sock_close(f);
996 			return 0;
997 		}
998 		break;
999 	case AMSG_START:
1000 #ifdef DEBUG
1001 		if (log_level >= 3) {
1002 			sock_log(f);
1003 			log_puts(": START message\n");
1004 		}
1005 #endif
1006 		if (f->pstate != SOCK_INIT || s == NULL) {
1007 #ifdef DEBUG
1008 			if (log_level >= 1) {
1009 				sock_log(f);
1010 				log_puts(": START, wrong state\n");
1011 			}
1012 #endif
1013 			sock_close(f);
1014 			return 0;
1015 		}
1016 		f->tickpending = 0;
1017 		f->stoppending = 0;
1018 		slot_start(s);
1019 		if (s->mode & MODE_PLAY) {
1020 			f->fillpending = s->appbufsz;
1021 			f->ralign = s->round * s->mix.bpf;
1022 			f->rmax = 0;
1023 		}
1024 		if (s->mode & MODE_RECMASK) {
1025 			f->walign = s->round * s->sub.bpf;
1026 			f->wmax = 0;
1027 		}
1028 		f->pstate = SOCK_START;
1029 		f->rstate = SOCK_RMSG;
1030 		f->rtodo = sizeof(struct amsg);
1031 		if (log_level >= 2) {
1032 			slot_log(f->slot);
1033 			log_puts(": ");
1034 			log_putu(s->rate);
1035 			log_puts("Hz, ");
1036 			aparams_log(&s->par);
1037 			if (s->mode & MODE_PLAY) {
1038 				log_puts(", play ");
1039 				log_puti(s->mix.slot_cmin);
1040 				log_puts(":");
1041 				log_puti(s->mix.slot_cmax);
1042 			}
1043 			if (s->mode & MODE_RECMASK) {
1044 				log_puts(", rec ");
1045 				log_puti(s->sub.slot_cmin);
1046 				log_puts(":");
1047 				log_puti(s->sub.slot_cmax);
1048 			}
1049 			log_puts(", ");
1050 			log_putu(s->appbufsz / s->round);
1051 			log_puts(" blocks of ");
1052 			log_putu(s->round);
1053 			log_puts(" frames\n");
1054 		}
1055 		break;
1056 	case AMSG_STOP:
1057 #ifdef DEBUG
1058 		if (log_level >= 3) {
1059 			sock_log(f);
1060 			log_puts(": STOP message\n");
1061 		}
1062 #endif
1063 		if (f->pstate != SOCK_START) {
1064 #ifdef DEBUG
1065 			if (log_level >= 1) {
1066 				sock_log(f);
1067 				log_puts(": STOP, wrong state\n");
1068 			}
1069 #endif
1070 			sock_close(f);
1071 			return 0;
1072 		}
1073 		f->rmax = 0;
1074 		if (!(s->mode & MODE_PLAY))
1075 			f->stoppending = 1;
1076 		f->pstate = SOCK_STOP;
1077 		f->rstate = SOCK_RMSG;
1078 		f->rtodo = sizeof(struct amsg);
1079 		if (s->mode & MODE_PLAY) {
1080 			if (f->ralign < s->round * s->mix.bpf) {
1081 				data = abuf_wgetblk(&s->mix.buf, &size);
1082 #ifdef DEBUG
1083 				if (size < f->ralign) {
1084 					sock_log(f);
1085 					log_puts(": unaligned stop, size = ");
1086 					log_putu(size);
1087 					log_puts(", ralign = ");
1088 					log_putu(f->ralign);
1089 					log_puts("\n");
1090 					panic();
1091 				}
1092 #endif
1093 				memset(data, 0, f->ralign);
1094 				abuf_wcommit(&s->mix.buf, f->ralign);
1095 				f->ralign = s->round * s->mix.bpf;
1096 			}
1097 		}
1098 		slot_stop(s);
1099 		break;
1100 	case AMSG_SETPAR:
1101 #ifdef DEBUG
1102 		if (log_level >= 3) {
1103 			sock_log(f);
1104 			log_puts(": SETPAR message\n");
1105 		}
1106 #endif
1107 		if (f->pstate != SOCK_INIT || s == NULL) {
1108 #ifdef DEBUG
1109 			if (log_level >= 1) {
1110 				sock_log(f);
1111 				log_puts(": SETPAR, wrong state\n");
1112 			}
1113 #endif
1114 			sock_close(f);
1115 			return 0;
1116 		}
1117 		if (!sock_setpar(f)) {
1118 			sock_close(f);
1119 			return 0;
1120 		}
1121 		f->rtodo = sizeof(struct amsg);
1122 		f->rstate = SOCK_RMSG;
1123 		break;
1124 	case AMSG_GETPAR:
1125 #ifdef DEBUG
1126 		if (log_level >= 3) {
1127 			sock_log(f);
1128 			log_puts(": GETPAR message\n");
1129 		}
1130 #endif
1131 		if (f->pstate != SOCK_INIT || s == NULL) {
1132 #ifdef DEBUG
1133 			if (log_level >= 1) {
1134 				sock_log(f);
1135 				log_puts(": GETPAR, wrong state\n");
1136 			}
1137 #endif
1138 			sock_close(f);
1139 			return 0;
1140 		}
1141 		AMSG_INIT(m);
1142 		m->cmd = htonl(AMSG_GETPAR);
1143 		m->u.par.legacy_mode = s->mode;
1144 		m->u.par.xrun = s->xrun;
1145 		m->u.par.bits = s->par.bits;
1146 		m->u.par.bps = s->par.bps;
1147 		m->u.par.sig = s->par.sig;
1148 		m->u.par.le = s->par.le;
1149 		m->u.par.msb = s->par.msb;
1150 		if (s->mode & MODE_PLAY) {
1151 			m->u.par.pchan = htons(s->mix.slot_cmax -
1152 			    s->mix.slot_cmin + 1);
1153 		}
1154 		if (s->mode & MODE_RECMASK) {
1155 			m->u.par.rchan = htons(s->sub.slot_cmax -
1156 			    s->sub.slot_cmin + 1);
1157 		}
1158 		m->u.par.rate = htonl(s->rate);
1159 		m->u.par.appbufsz = htonl(s->appbufsz);
1160 		m->u.par.bufsz = htonl(SLOT_BUFSZ(s));
1161 		m->u.par.round = htonl(s->round);
1162 		f->rstate = SOCK_RRET;
1163 		f->rtodo = sizeof(struct amsg);
1164 		break;
1165 	case AMSG_SETVOL:
1166 #ifdef DEBUG
1167 		if (log_level >= 3) {
1168 			sock_log(f);
1169 			log_puts(": SETVOL message\n");
1170 		}
1171 #endif
1172 		if (f->pstate < SOCK_INIT || s == NULL) {
1173 #ifdef DEBUG
1174 			if (log_level >= 1) {
1175 				sock_log(f);
1176 				log_puts(": SETVOL, wrong state\n");
1177 			}
1178 #endif
1179 			sock_close(f);
1180 			return 0;
1181 		}
1182 		ctl = ntohl(m->u.vol.ctl);
1183 		if (ctl > MIDI_MAXCTL) {
1184 #ifdef DEBUG
1185 			if (log_level >= 1) {
1186 				sock_log(f);
1187 				log_puts(": SETVOL, volume out of range\n");
1188 			}
1189 #endif
1190 			sock_close(f);
1191 			return 0;
1192 		}
1193 		f->rtodo = sizeof(struct amsg);
1194 		f->rstate = SOCK_RMSG;
1195 		f->lastvol = ctl; /* dont trigger feedback message */
1196 		slot_setvol(s, ctl);
1197 		dev_midi_vol(s->dev, s);
1198 		break;
1199 	case AMSG_AUTH:
1200 #ifdef DEBUG
1201 		if (log_level >= 3) {
1202 			sock_log(f);
1203 			log_puts(": AUTH message\n");
1204 		}
1205 #endif
1206 		if (f->pstate != SOCK_AUTH) {
1207 #ifdef DEBUG
1208 			if (log_level >= 1) {
1209 				sock_log(f);
1210 				log_puts(": AUTH, wrong state\n");
1211 			}
1212 #endif
1213 			sock_close(f);
1214 			return 0;
1215 		}
1216 		if (!sock_auth(f)) {
1217 			sock_close(f);
1218 			return 0;
1219 		}
1220 		f->rstate = SOCK_RMSG;
1221 		f->rtodo = sizeof(struct amsg);
1222 		break;
1223 	case AMSG_HELLO:
1224 #ifdef DEBUG
1225 		if (log_level >= 3) {
1226 			sock_log(f);
1227 			log_puts(": HELLO message\n");
1228 		}
1229 #endif
1230 		if (f->pstate != SOCK_HELLO) {
1231 #ifdef DEBUG
1232 			if (log_level >= 1) {
1233 				sock_log(f);
1234 				log_puts(": HELLO, wrong state\n");
1235 			}
1236 #endif
1237 			sock_close(f);
1238 			return 0;
1239 		}
1240 		if (!sock_hello(f)) {
1241 			sock_close(f);
1242 			return 0;
1243 		}
1244 		AMSG_INIT(m);
1245 		m->cmd = htonl(AMSG_ACK);
1246 		f->rstate = SOCK_RRET;
1247 		f->rtodo = sizeof(struct amsg);
1248 		break;
1249 	case AMSG_BYE:
1250 #ifdef DEBUG
1251 		if (log_level >= 3) {
1252 			sock_log(f);
1253 			log_puts(": BYE message\n");
1254 		}
1255 #endif
1256 		if (s != NULL && f->pstate != SOCK_INIT) {
1257 #ifdef DEBUG
1258 			if (log_level >= 1) {
1259 				sock_log(f);
1260 				log_puts(": BYE, wrong state\n");
1261 			}
1262 #endif
1263 		}
1264 		sock_close(f);
1265 		return 0;
1266 	default:
1267 #ifdef DEBUG
1268 		if (log_level >= 1) {
1269 			sock_log(f);
1270 			log_puts(": unknown command in message\n");
1271 		}
1272 #endif
1273 		sock_close(f);
1274 		return 0;
1275 	}
1276 	return 1;
1277 }
1278 
1279 /*
1280  * build a message in f->wmsg, return 1 on success and 0 if
1281  * there's nothing to do. Assume f->wstate is SOCK_WIDLE
1282  */
1283 int
1284 sock_buildmsg(struct sock *f)
1285 {
1286 	unsigned int size;
1287 
1288 	/*
1289 	 * If pos changed (or initial tick), build a MOVE message.
1290 	 */
1291 	if (f->tickpending) {
1292 #ifdef DEBUG
1293 		if (log_level >= 4) {
1294 			sock_log(f);
1295 			log_puts(": building MOVE message, delta = ");
1296 			log_puti(f->slot->delta);
1297 			log_puts("\n");
1298 		}
1299 #endif
1300 		AMSG_INIT(&f->wmsg);
1301 		f->wmsg.cmd = htonl(AMSG_MOVE);
1302 		f->wmsg.u.ts.delta = htonl(f->slot->delta);
1303 		f->wtodo = sizeof(struct amsg);
1304 		f->wstate = SOCK_WMSG;
1305 		f->tickpending = 0;
1306 		/*
1307 		 * XXX: use tickpending as accumulator rather than
1308 		 * slot->delta
1309 		 */
1310 		f->slot->delta = 0;
1311 		return 1;
1312 	}
1313 
1314 	if (f->fillpending > 0) {
1315 		AMSG_INIT(&f->wmsg);
1316 		f->wmsg.cmd = htonl(AMSG_FLOWCTL);
1317 		f->wmsg.u.ts.delta = htonl(f->fillpending);
1318 		size = f->fillpending;
1319 		if (f->slot)
1320 			size *= f->slot->mix.bpf;
1321 		f->rmax += size;
1322 #ifdef DEBUG
1323 		if (log_level >= 4) {
1324 			sock_log(f);
1325 			log_puts(": building FLOWCTL message, count = ");
1326 			log_puti(f->fillpending);
1327 			log_puts(", rmax -> ");
1328 			log_puti(f->rmax);
1329 			log_puts("\n");
1330 		}
1331 #endif
1332 		f->wtodo = sizeof(struct amsg);
1333 		f->wstate = SOCK_WMSG;
1334 		f->fillpending = 0;
1335 		return 1;
1336 	}
1337 
1338 	/*
1339 	 * if volume changed build a SETVOL message
1340 	 */
1341 	if (f->pstate >= SOCK_START && f->slot->vol != f->lastvol) {
1342 #ifdef DEBUG
1343 		if (log_level >= 3) {
1344 			sock_log(f);
1345 			log_puts(": building SETVOL message, vol = ");
1346 			log_puti(f->slot->vol);
1347 			log_puts("\n");
1348 		}
1349 #endif
1350 		AMSG_INIT(&f->wmsg);
1351 		f->wmsg.cmd = htonl(AMSG_SETVOL);
1352 		f->wmsg.u.vol.ctl = htonl(f->slot->vol);
1353 		f->wtodo = sizeof(struct amsg);
1354 		f->wstate = SOCK_WMSG;
1355 		f->lastvol = f->slot->vol;
1356 		return 1;
1357 	}
1358 
1359 	if (f->midi != NULL && f->midi->obuf.used > 0) {
1360 		size = f->midi->obuf.used;
1361 		if (size > AMSG_DATAMAX)
1362 			size = AMSG_DATAMAX;
1363 		AMSG_INIT(&f->wmsg);
1364 		f->wmsg.cmd = htonl(AMSG_DATA);
1365 		f->wmsg.u.data.size = htonl(size);
1366 		f->wtodo = sizeof(struct amsg);
1367 		f->wstate = SOCK_WMSG;
1368 		return 1;
1369 	}
1370 
1371 	/*
1372 	 * If data available, build a DATA message.
1373 	 */
1374 	if (f->slot != NULL && f->wmax > 0 && f->slot->sub.buf.used > 0) {
1375 		size = f->slot->sub.buf.used;
1376 		if (size > AMSG_DATAMAX)
1377 			size = AMSG_DATAMAX;
1378 		if (size > f->walign)
1379 			size = f->walign;
1380 		if (size > f->wmax)
1381 			size = f->wmax;
1382 		size -= size % f->slot->sub.bpf;
1383 #ifdef DEBUG
1384 		if (size == 0) {
1385 			sock_log(f);
1386 			log_puts(": sock_buildmsg size == 0\n");
1387 			panic();
1388 		}
1389 #endif
1390 		f->walign -= size;
1391 		f->wmax -= size;
1392 		if (f->walign == 0)
1393 			f->walign = f->slot->round * f->slot->sub.bpf;
1394 #ifdef DEBUG
1395 		if (log_level >= 4) {
1396 			sock_log(f);
1397 			log_puts(": building audio DATA message, size = ");
1398 			log_puti(size);
1399 			log_puts("\n");
1400 		}
1401 #endif
1402 		AMSG_INIT(&f->wmsg);
1403 		f->wmsg.cmd = htonl(AMSG_DATA);
1404 		f->wmsg.u.data.size = htonl(size);
1405 		f->wtodo = sizeof(struct amsg);
1406 		f->wstate = SOCK_WMSG;
1407 		return 1;
1408 	}
1409 
1410 	if (f->stoppending) {
1411 #ifdef DEBUG
1412 		if (log_level >= 3) {
1413 			sock_log(f);
1414 			log_puts(": building STOP message\n");
1415 		}
1416 #endif
1417 		f->stoppending = 0;
1418 		f->pstate = SOCK_INIT;
1419 		AMSG_INIT(&f->wmsg);
1420 		f->wmsg.cmd = htonl(AMSG_STOP);
1421 		f->wtodo = sizeof(struct amsg);
1422 		f->wstate = SOCK_WMSG;
1423 		return 1;
1424 	}
1425 #ifdef DEBUG
1426 	if (log_level >= 4) {
1427 		sock_log(f);
1428 		log_puts(": no messages to build anymore, idling...\n");
1429 	}
1430 #endif
1431 	f->wstate = SOCK_WIDLE;
1432 	return 0;
1433 }
1434 
1435 /*
1436  * iteration of the socket reader loop, return 1 on success
1437  */
1438 int
1439 sock_read(struct sock *f)
1440 {
1441 #ifdef DEBUG
1442 	if (log_level >= 4) {
1443 		sock_log(f);
1444 		log_puts(": reading ");
1445 		log_putu(f->rtodo);
1446 		log_puts(" todo\n");
1447 	}
1448 #endif
1449 	switch (f->rstate) {
1450 	case SOCK_RIDLE:
1451 		return 0;
1452 	case SOCK_RMSG:
1453 		if (!sock_rmsg(f))
1454 			return 0;
1455 		if (!sock_execmsg(f))
1456 			return 0;
1457 		break;
1458 	case SOCK_RDATA:
1459 		if (!sock_rdata(f))
1460 			return 0;
1461 		f->rstate = SOCK_RMSG;
1462 		f->rtodo = sizeof(struct amsg);
1463 		break;
1464 	case SOCK_RRET:
1465 		if (f->wstate != SOCK_WIDLE) {
1466 #ifdef DEBUG
1467 			if (log_level >= 4) {
1468 				sock_log(f);
1469 				log_puts(": can't reply, write-end blocked\n");
1470 			}
1471 #endif
1472 			return 0;
1473 		}
1474 		f->wmsg = f->rmsg;
1475 		f->wstate = SOCK_WMSG;
1476 		f->wtodo = sizeof(struct amsg);
1477 		f->rstate = SOCK_RMSG;
1478 		f->rtodo = sizeof(struct amsg);
1479 #ifdef DEBUG
1480 		if (log_level >= 4) {
1481 			sock_log(f);
1482 			log_puts(": copied RRET message\n");
1483 		}
1484 #endif
1485 	}
1486 	return 1;
1487 }
1488 
1489 /*
1490  * iteration of the socket writer loop, return 1 on success
1491  */
1492 int
1493 sock_write(struct sock *f)
1494 {
1495 #ifdef DEBUG
1496 	if (log_level >= 4) {
1497 		sock_log(f);
1498 		log_puts(": writing");
1499 		if (f->wstate != SOCK_WIDLE) {
1500 			log_puts(" todo = ");
1501 			log_putu(f->wtodo);
1502 		}
1503 		log_puts("\n");
1504 	}
1505 #endif
1506 	switch (f->wstate) {
1507 	case SOCK_WMSG:
1508 		if (!sock_wmsg(f))
1509 			return 0;
1510 		if (ntohl(f->wmsg.cmd) != AMSG_DATA) {
1511 			f->wstate = SOCK_WIDLE;
1512 			f->wtodo = 0xdeadbeef;
1513 			break;
1514 		}
1515 		f->wstate = SOCK_WDATA;
1516 		f->wsize = f->wtodo = ntohl(f->wmsg.u.data.size);
1517 		/* PASSTHROUGH */
1518 	case SOCK_WDATA:
1519 		if (!sock_wdata(f))
1520 			return 0;
1521 		if (f->wtodo > 0)
1522 			break;
1523 		f->wstate = SOCK_WIDLE;
1524 		f->wtodo = 0xdeadbeef;
1525 		if (f->pstate == SOCK_STOP) {
1526 			f->pstate = SOCK_INIT;
1527 			f->wmax = 0;
1528 #ifdef DEBUG
1529 			if (log_level >= 4) {
1530 				sock_log(f);
1531 				log_puts(": drained, moved to INIT state\n");
1532 			}
1533 #endif
1534 		}
1535 		/* PASSTHROUGH */
1536 	case SOCK_WIDLE:
1537 		if (f->rstate == SOCK_RRET) {
1538 			f->wmsg = f->rmsg;
1539 			f->wstate = SOCK_WMSG;
1540 			f->wtodo = sizeof(struct amsg);
1541 			f->rstate = SOCK_RMSG;
1542 			f->rtodo = sizeof(struct amsg);
1543 #ifdef DEBUG
1544 			if (log_level >= 4) {
1545 				sock_log(f);
1546 				log_puts(": copied RRET message\n");
1547 			}
1548 #endif
1549 		} else {
1550 			if (!sock_buildmsg(f))
1551 				return 0;
1552 		}
1553 		break;
1554 #ifdef DEBUG
1555 	default:
1556 		sock_log(f);
1557 		log_puts(": bad writing end state\n");
1558 		panic();
1559 #endif
1560 	}
1561 	return 1;
1562 }
1563 
1564 int
1565 sock_pollfd(void *arg, struct pollfd *pfd)
1566 {
1567 	struct sock *f = arg;
1568 	int events = 0;
1569 
1570 	/*
1571 	 * feedback counters, clock ticks and alike may have changed,
1572 	 * prepare a message to trigger writes
1573 	 *
1574 	 * XXX: doing this at the beginning of the cycle is not optimal,
1575 	 * because state is changed at the end of the read cycle, and
1576 	 * thus counters, ret message and alike are generated then.
1577 	 */
1578 	if (f->wstate == SOCK_WIDLE && f->rstate != SOCK_RRET)
1579 		sock_buildmsg(f);
1580 
1581 	if (f->rstate == SOCK_RMSG ||
1582 	    f->rstate == SOCK_RDATA)
1583 		events |= POLLIN;
1584 	if (f->rstate == SOCK_RRET ||
1585 	    f->wstate == SOCK_WMSG ||
1586 	    f->wstate == SOCK_WDATA)
1587 		events |= POLLOUT;
1588 	pfd->fd = f->fd;
1589 	pfd->events = events;
1590 	return 1;
1591 }
1592 
1593 int
1594 sock_revents(void *arg, struct pollfd *pfd)
1595 {
1596 	return pfd->revents;
1597 }
1598 
1599 void
1600 sock_in(void *arg)
1601 {
1602 	struct sock *f = arg;
1603 
1604 	while (sock_read(f))
1605 		;
1606 }
1607 
1608 void
1609 sock_out(void *arg)
1610 {
1611 	struct sock *f = arg;
1612 
1613 	while (sock_write(f))
1614 		;
1615 }
1616 
1617 void
1618 sock_hup(void *arg)
1619 {
1620 	struct sock *f = arg;
1621 
1622 	sock_close(f);
1623 }
1624