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