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