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 * 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 * 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 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 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 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 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 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 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 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 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 276 sock_midi_fill(void *arg, int count) 277 { 278 struct sock *f = arg; 279 280 f->fillpending += count; 281 } 282 283 void 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 1505 sock_revents(void *arg, struct pollfd *pfd) 1506 { 1507 return pfd->revents; 1508 } 1509 1510 void 1511 sock_in(void *arg) 1512 { 1513 struct sock *f = arg; 1514 1515 while (sock_read(f)) 1516 ; 1517 } 1518 1519 void 1520 sock_out(void *arg) 1521 { 1522 struct sock *f = arg; 1523 1524 while (sock_write(f)) 1525 ; 1526 } 1527 1528 void 1529 sock_hup(void *arg) 1530 { 1531 struct sock *f = arg; 1532 1533 sock_close(f); 1534 } 1535