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