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