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