Annotation of src/usr.bin/sndiod/sock.c, Revision 1.31
1.31 ! ratchov 1: /* $OpenBSD: sock.c,v 1.30 2019/06/29 21:23:18 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);
1.30 ratchov 323: if (n == -1) {
1.1 ratchov 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);
1.30 ratchov 364: if (n == -1) {
1.1 ratchov 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;
1.31 ! ratchov 771: unsigned int id;
1.1 ratchov 772:
773: mode = ntohs(p->mode);
1.31 ! ratchov 774: id = ntohl(p->id);
1.1 ratchov 775: #ifdef DEBUG
776: if (log_level >= 3) {
777: sock_log(f);
778: log_puts(": hello from <");
779: log_puts(p->who);
780: log_puts(">, mode = ");
781: log_putx(mode);
782: log_puts(", ver ");
783: log_putu(p->version);
784: log_puts("\n");
785: }
786: #endif
787: if (p->version != AMSG_VERSION) {
788: if (log_level >= 1) {
789: sock_log(f);
790: log_puts(": ");
791: log_putu(p->version);
792: log_puts(": unsupported protocol version\n");
793: }
794: return 0;
795: }
796: switch (mode) {
797: case MODE_MIDIIN:
798: case MODE_MIDIOUT:
799: case MODE_MIDIOUT | MODE_MIDIIN:
800: case MODE_REC:
801: case MODE_PLAY:
802: case MODE_PLAY | MODE_REC:
803: break;
804: default:
805: #ifdef DEBUG
806: if (log_level >= 1) {
807: sock_log(f);
808: log_puts(": ");
809: log_putx(mode);
810: log_puts(": unsupported mode\n");
811: }
812: #endif
813: return 0;
814: }
815: f->pstate = SOCK_INIT;
1.5 ratchov 816: f->port = NULL;
1.1 ratchov 817: if (mode & MODE_MIDIMASK) {
818: f->slot = NULL;
819: f->midi = midi_new(&sock_midiops, f, mode);
820: if (f->midi == NULL)
821: return 0;
822: /* XXX: add 'devtype' to libsndio */
823: if (p->devnum < 16) {
824: d = dev_bynum(p->devnum);
825: if (d == NULL)
826: return 0;
827: midi_tag(f->midi, p->devnum);
828: } else if (p->devnum < 32) {
829: midi_tag(f->midi, p->devnum);
830: } else if (p->devnum < 48) {
831: c = port_bynum(p->devnum - 32);
1.3 ratchov 832: if (c == NULL || !port_ref(c))
1.1 ratchov 833: return 0;
1.3 ratchov 834: f->port = c;
1.2 ratchov 835: midi_link(f->midi, c->midi);
1.1 ratchov 836: } else
837: return 0;
838: return 1;
839: }
1.22 ratchov 840: d = dev_bynum(p->devnum);
841: if (d == NULL)
842: return 0;
1.23 ratchov 843: opt = opt_byname(d, p->opt);
844: if (opt == NULL)
1.1 ratchov 845: return 0;
1.31 ! ratchov 846: f->slot = slot_new(d, opt, id, p->who, &sock_slotops, f, mode);
1.29 ratchov 847: if (f->slot == NULL)
1.1 ratchov 848: return 0;
849: f->midi = NULL;
850: return 1;
851: }
852:
853: /*
854: * execute the message in f->rmsg, return 1 on success
855: */
856: int
857: sock_execmsg(struct sock *f)
858: {
859: struct slot *s = f->slot;
860: struct amsg *m = &f->rmsg;
861: unsigned char *data;
862: int size, ctl;
863:
864: switch (ntohl(m->cmd)) {
865: case AMSG_DATA:
866: #ifdef DEBUG
867: if (log_level >= 4) {
868: sock_log(f);
869: log_puts(": DATA message\n");
870: }
871: #endif
872: if (s != NULL && f->pstate != SOCK_START) {
873: #ifdef DEBUG
874: if (log_level >= 1) {
875: sock_log(f);
876: log_puts(": DATA, wrong state\n");
877: }
878: #endif
879: sock_close(f);
880: return 0;
881: }
882: if ((f->slot && !(f->slot->mode & MODE_PLAY)) ||
883: (f->midi && !(f->midi->mode & MODE_MIDIOUT))) {
884: #ifdef DEBUG
885: if (log_level >= 1) {
886: sock_log(f);
887: log_puts(": DATA, input-only mode\n");
888: }
889: #endif
890: sock_close(f);
891: return 0;
892: }
893: size = ntohl(m->u.data.size);
894: if (size <= 0) {
895: #ifdef DEBUG
896: if (log_level >= 1) {
897: sock_log(f);
898: log_puts(": zero size payload\n");
899: }
900: #endif
901: sock_close(f);
902: return 0;
903: }
904: if (s != NULL && size % s->mix.bpf != 0) {
905: #ifdef DEBUG
906: if (log_level >= 1) {
907: sock_log(f);
908: log_puts(": not aligned to frame\n");
909: }
910: #endif
911: sock_close(f);
912: return 0;
913: }
914: if (s != NULL && size > f->ralign) {
915: #ifdef DEBUG
916: if (log_level >= 1) {
917: sock_log(f);
918: log_puts(": size = ");
919: log_puti(size);
920: log_puts(": ralign = ");
921: log_puti(f->ralign);
922: log_puts(": not aligned to block\n");
923: }
924: #endif
925: sock_close(f);
926: return 0;
927: }
928: f->rstate = SOCK_RDATA;
929: f->rsize = f->rtodo = size;
930: if (s != NULL) {
931: f->ralign -= size;
932: if (f->ralign == 0)
933: f->ralign = s->round * s->mix.bpf;
934: }
935: if (f->rtodo > f->rmax) {
936: #ifdef DEBUG
937: if (log_level >= 1) {
938: sock_log(f);
939: log_puts(": unexpected data, size = ");
940: log_putu(size);
941: log_puts(", rmax = ");
942: log_putu(f->rmax);
943: log_puts("\n");
944: }
945: #endif
946: sock_close(f);
947: return 0;
948: }
949: f->rmax -= f->rtodo;
950: if (f->rtodo == 0) {
951: #ifdef DEBUG
952: if (log_level >= 1) {
953: sock_log(f);
954: log_puts(": zero-length data chunk\n");
955: }
956: #endif
957: sock_close(f);
958: return 0;
959: }
960: break;
961: case AMSG_START:
962: #ifdef DEBUG
963: if (log_level >= 3) {
964: sock_log(f);
965: log_puts(": START message\n");
966: }
967: #endif
1.15 ratchov 968: if (f->pstate != SOCK_INIT || s == NULL) {
1.1 ratchov 969: #ifdef DEBUG
970: if (log_level >= 1) {
971: sock_log(f);
972: log_puts(": START, wrong state\n");
973: }
974: #endif
975: sock_close(f);
976: return 0;
977: }
978: f->tickpending = 0;
979: f->stoppending = 0;
980: slot_start(s);
981: if (s->mode & MODE_PLAY) {
982: f->fillpending = s->appbufsz;
983: f->ralign = s->round * s->mix.bpf;
984: f->rmax = 0;
985: }
986: if (s->mode & MODE_RECMASK) {
987: f->walign = s->round * s->sub.bpf;
988: f->wmax = 0;
989: }
990: f->pstate = SOCK_START;
991: f->rstate = SOCK_RMSG;
992: f->rtodo = sizeof(struct amsg);
993: if (log_level >= 2) {
994: slot_log(f->slot);
995: log_puts(": ");
996: log_putu(s->rate);
997: log_puts("Hz, ");
998: aparams_log(&s->par);
999: if (s->mode & MODE_PLAY) {
1000: log_puts(", play ");
1.27 ratchov 1001: log_puti(s->opt->pmin);
1.1 ratchov 1002: log_puts(":");
1.28 ratchov 1003: log_puti(s->opt->pmin + s->mix.nch - 1);
1.1 ratchov 1004: }
1005: if (s->mode & MODE_RECMASK) {
1006: log_puts(", rec ");
1.27 ratchov 1007: log_puti(s->opt->rmin);
1.1 ratchov 1008: log_puts(":");
1.28 ratchov 1009: log_puti(s->opt->rmin + s->sub.nch - 1);
1.1 ratchov 1010: }
1011: log_puts(", ");
1012: log_putu(s->appbufsz / s->round);
1013: log_puts(" blocks of ");
1014: log_putu(s->round);
1015: log_puts(" frames\n");
1016: }
1017: break;
1018: case AMSG_STOP:
1019: #ifdef DEBUG
1020: if (log_level >= 3) {
1021: sock_log(f);
1022: log_puts(": STOP message\n");
1023: }
1024: #endif
1025: if (f->pstate != SOCK_START) {
1026: #ifdef DEBUG
1027: if (log_level >= 1) {
1028: sock_log(f);
1029: log_puts(": STOP, wrong state\n");
1030: }
1031: #endif
1032: sock_close(f);
1033: return 0;
1034: }
1035: f->rmax = 0;
1036: if (!(s->mode & MODE_PLAY))
1037: f->stoppending = 1;
1038: f->pstate = SOCK_STOP;
1039: f->rstate = SOCK_RMSG;
1040: f->rtodo = sizeof(struct amsg);
1041: if (s->mode & MODE_PLAY) {
1042: if (f->ralign < s->round * s->mix.bpf) {
1043: data = abuf_wgetblk(&s->mix.buf, &size);
1044: #ifdef DEBUG
1045: if (size < f->ralign) {
1046: sock_log(f);
1047: log_puts(": unaligned stop, size = ");
1048: log_putu(size);
1049: log_puts(", ralign = ");
1050: log_putu(f->ralign);
1051: log_puts("\n");
1052: panic();
1053: }
1054: #endif
1055: memset(data, 0, f->ralign);
1056: abuf_wcommit(&s->mix.buf, f->ralign);
1057: f->ralign = s->round * s->mix.bpf;
1058: }
1059: }
1.17 ratchov 1060: slot_stop(s);
1.1 ratchov 1061: break;
1062: case AMSG_SETPAR:
1063: #ifdef DEBUG
1064: if (log_level >= 3) {
1065: sock_log(f);
1066: log_puts(": SETPAR message\n");
1067: }
1068: #endif
1.15 ratchov 1069: if (f->pstate != SOCK_INIT || s == NULL) {
1.1 ratchov 1070: #ifdef DEBUG
1071: if (log_level >= 1) {
1072: sock_log(f);
1073: log_puts(": SETPAR, wrong state\n");
1074: }
1075: #endif
1076: sock_close(f);
1077: return 0;
1078: }
1079: if (!sock_setpar(f)) {
1080: sock_close(f);
1081: return 0;
1082: }
1083: f->rtodo = sizeof(struct amsg);
1084: f->rstate = SOCK_RMSG;
1085: break;
1086: case AMSG_GETPAR:
1087: #ifdef DEBUG
1088: if (log_level >= 3) {
1089: sock_log(f);
1090: log_puts(": GETPAR message\n");
1091: }
1092: #endif
1.15 ratchov 1093: if (f->pstate != SOCK_INIT || s == NULL) {
1.1 ratchov 1094: #ifdef DEBUG
1095: if (log_level >= 1) {
1096: sock_log(f);
1097: log_puts(": GETPAR, wrong state\n");
1098: }
1099: #endif
1100: sock_close(f);
1101: return 0;
1102: }
1103: AMSG_INIT(m);
1104: m->cmd = htonl(AMSG_GETPAR);
1105: m->u.par.legacy_mode = s->mode;
1.14 ratchov 1106: m->u.par.xrun = s->xrun;
1.1 ratchov 1107: m->u.par.bits = s->par.bits;
1108: m->u.par.bps = s->par.bps;
1109: m->u.par.sig = s->par.sig;
1110: m->u.par.le = s->par.le;
1111: m->u.par.msb = s->par.msb;
1.28 ratchov 1112: if (s->mode & MODE_PLAY)
1113: m->u.par.pchan = htons(s->mix.nch);
1114: if (s->mode & MODE_RECMASK)
1115: m->u.par.rchan = htons(s->sub.nch);
1.1 ratchov 1116: m->u.par.rate = htonl(s->rate);
1117: m->u.par.appbufsz = htonl(s->appbufsz);
1118: m->u.par.bufsz = htonl(SLOT_BUFSZ(s));
1119: m->u.par.round = htonl(s->round);
1120: f->rstate = SOCK_RRET;
1121: f->rtodo = sizeof(struct amsg);
1122: break;
1123: case AMSG_SETVOL:
1124: #ifdef DEBUG
1125: if (log_level >= 3) {
1126: sock_log(f);
1127: log_puts(": SETVOL message\n");
1128: }
1129: #endif
1.15 ratchov 1130: if (f->pstate < SOCK_INIT || s == NULL) {
1.1 ratchov 1131: #ifdef DEBUG
1132: if (log_level >= 1) {
1133: sock_log(f);
1134: log_puts(": SETVOL, wrong state\n");
1135: }
1136: #endif
1137: sock_close(f);
1138: return 0;
1139: }
1140: ctl = ntohl(m->u.vol.ctl);
1141: if (ctl > MIDI_MAXCTL) {
1142: #ifdef DEBUG
1143: if (log_level >= 1) {
1144: sock_log(f);
1145: log_puts(": SETVOL, volume out of range\n");
1146: }
1147: #endif
1148: sock_close(f);
1149: return 0;
1150: }
1151: f->rtodo = sizeof(struct amsg);
1152: f->rstate = SOCK_RMSG;
1153: f->lastvol = ctl; /* dont trigger feedback message */
1.15 ratchov 1154: slot_setvol(s, ctl);
1.1 ratchov 1155: dev_midi_vol(s->dev, s);
1156: break;
1157: case AMSG_AUTH:
1158: #ifdef DEBUG
1159: if (log_level >= 3) {
1160: sock_log(f);
1161: log_puts(": AUTH message\n");
1162: }
1163: #endif
1164: if (f->pstate != SOCK_AUTH) {
1165: #ifdef DEBUG
1166: if (log_level >= 1) {
1167: sock_log(f);
1168: log_puts(": AUTH, wrong state\n");
1169: }
1170: #endif
1171: sock_close(f);
1172: return 0;
1173: }
1174: if (!sock_auth(f)) {
1175: sock_close(f);
1176: return 0;
1177: }
1178: f->rstate = SOCK_RMSG;
1179: f->rtodo = sizeof(struct amsg);
1180: break;
1181: case AMSG_HELLO:
1182: #ifdef DEBUG
1183: if (log_level >= 3) {
1184: sock_log(f);
1185: log_puts(": HELLO message\n");
1186: }
1187: #endif
1188: if (f->pstate != SOCK_HELLO) {
1189: #ifdef DEBUG
1190: if (log_level >= 1) {
1191: sock_log(f);
1192: log_puts(": HELLO, wrong state\n");
1193: }
1194: #endif
1195: sock_close(f);
1196: return 0;
1197: }
1198: if (!sock_hello(f)) {
1199: sock_close(f);
1200: return 0;
1201: }
1202: AMSG_INIT(m);
1203: m->cmd = htonl(AMSG_ACK);
1204: f->rstate = SOCK_RRET;
1205: f->rtodo = sizeof(struct amsg);
1206: break;
1207: case AMSG_BYE:
1208: #ifdef DEBUG
1209: if (log_level >= 3) {
1210: sock_log(f);
1211: log_puts(": BYE message\n");
1212: }
1213: #endif
1214: if (s != NULL && f->pstate != SOCK_INIT) {
1215: #ifdef DEBUG
1216: if (log_level >= 1) {
1217: sock_log(f);
1218: log_puts(": BYE, wrong state\n");
1219: }
1220: #endif
1221: }
1222: sock_close(f);
1223: return 0;
1224: default:
1225: #ifdef DEBUG
1226: if (log_level >= 1) {
1227: sock_log(f);
1228: log_puts(": unknown command in message\n");
1229: }
1230: #endif
1231: sock_close(f);
1232: return 0;
1233: }
1234: return 1;
1235: }
1236:
1237: /*
1238: * build a message in f->wmsg, return 1 on success and 0 if
1239: * there's nothing to do. Assume f->wstate is SOCK_WIDLE
1240: */
1241: int
1242: sock_buildmsg(struct sock *f)
1243: {
1.17 ratchov 1244: unsigned int size;
1.1 ratchov 1245:
1246: /*
1247: * If pos changed (or initial tick), build a MOVE message.
1248: */
1249: if (f->tickpending) {
1250: #ifdef DEBUG
1251: if (log_level >= 4) {
1252: sock_log(f);
1253: log_puts(": building MOVE message, delta = ");
1254: log_puti(f->slot->delta);
1255: log_puts("\n");
1256: }
1257: #endif
1258: AMSG_INIT(&f->wmsg);
1259: f->wmsg.cmd = htonl(AMSG_MOVE);
1260: f->wmsg.u.ts.delta = htonl(f->slot->delta);
1261: f->wtodo = sizeof(struct amsg);
1262: f->wstate = SOCK_WMSG;
1263: f->tickpending = 0;
1264: /*
1265: * XXX: use tickpending as accumulator rather than
1266: * slot->delta
1267: */
1268: f->slot->delta = 0;
1269: return 1;
1270: }
1271:
1272: if (f->fillpending > 0) {
1273: AMSG_INIT(&f->wmsg);
1.17 ratchov 1274: f->wmsg.cmd = htonl(AMSG_FLOWCTL);
1.1 ratchov 1275: f->wmsg.u.ts.delta = htonl(f->fillpending);
1276: size = f->fillpending;
1277: if (f->slot)
1278: size *= f->slot->mix.bpf;
1279: f->rmax += size;
1280: #ifdef DEBUG
1281: if (log_level >= 4) {
1282: sock_log(f);
1283: log_puts(": building FLOWCTL message, count = ");
1284: log_puti(f->fillpending);
1285: log_puts(", rmax -> ");
1286: log_puti(f->rmax);
1287: log_puts("\n");
1288: }
1289: #endif
1290: f->wtodo = sizeof(struct amsg);
1291: f->wstate = SOCK_WMSG;
1292: f->fillpending = 0;
1293: return 1;
1294: }
1295:
1296: /*
1297: * if volume changed build a SETVOL message
1298: */
1299: if (f->pstate >= SOCK_START && f->slot->vol != f->lastvol) {
1300: #ifdef DEBUG
1301: if (log_level >= 3) {
1302: sock_log(f);
1303: log_puts(": building SETVOL message, vol = ");
1304: log_puti(f->slot->vol);
1305: log_puts("\n");
1306: }
1307: #endif
1308: AMSG_INIT(&f->wmsg);
1309: f->wmsg.cmd = htonl(AMSG_SETVOL);
1310: f->wmsg.u.vol.ctl = htonl(f->slot->vol);
1311: f->wtodo = sizeof(struct amsg);
1312: f->wstate = SOCK_WMSG;
1313: f->lastvol = f->slot->vol;
1314: return 1;
1315: }
1316:
1317: if (f->midi != NULL && f->midi->obuf.used > 0) {
1.17 ratchov 1318: size = f->midi->obuf.used;
1.1 ratchov 1319: if (size > AMSG_DATAMAX)
1320: size = AMSG_DATAMAX;
1321: AMSG_INIT(&f->wmsg);
1322: f->wmsg.cmd = htonl(AMSG_DATA);
1323: f->wmsg.u.data.size = htonl(size);
1324: f->wtodo = sizeof(struct amsg);
1325: f->wstate = SOCK_WMSG;
1326: return 1;
1327: }
1328:
1329: /*
1330: * If data available, build a DATA message.
1331: */
1.10 ratchov 1332: if (f->slot != NULL && f->wmax > 0 && f->slot->sub.buf.used > 0) {
1.1 ratchov 1333: size = f->slot->sub.buf.used;
1334: if (size > AMSG_DATAMAX)
1335: size = AMSG_DATAMAX;
1336: if (size > f->walign)
1337: size = f->walign;
1338: if (size > f->wmax)
1339: size = f->wmax;
1340: size -= size % f->slot->sub.bpf;
1341: #ifdef DEBUG
1342: if (size == 0) {
1343: sock_log(f);
1344: log_puts(": sock_buildmsg size == 0\n");
1345: panic();
1346: }
1347: #endif
1348: f->walign -= size;
1349: f->wmax -= size;
1350: if (f->walign == 0)
1351: f->walign = f->slot->round * f->slot->sub.bpf;
1352: #ifdef DEBUG
1353: if (log_level >= 4) {
1354: sock_log(f);
1355: log_puts(": building audio DATA message, size = ");
1356: log_puti(size);
1357: log_puts("\n");
1358: }
1359: #endif
1360: AMSG_INIT(&f->wmsg);
1361: f->wmsg.cmd = htonl(AMSG_DATA);
1362: f->wmsg.u.data.size = htonl(size);
1363: f->wtodo = sizeof(struct amsg);
1364: f->wstate = SOCK_WMSG;
1365: return 1;
1366: }
1367:
1368: if (f->stoppending) {
1369: #ifdef DEBUG
1370: if (log_level >= 3) {
1371: sock_log(f);
1372: log_puts(": building STOP message\n");
1373: }
1374: #endif
1375: f->stoppending = 0;
1376: f->pstate = SOCK_INIT;
1377: AMSG_INIT(&f->wmsg);
1378: f->wmsg.cmd = htonl(AMSG_STOP);
1379: f->wtodo = sizeof(struct amsg);
1380: f->wstate = SOCK_WMSG;
1381: return 1;
1382: }
1383: #ifdef DEBUG
1384: if (log_level >= 4) {
1385: sock_log(f);
1386: log_puts(": no messages to build anymore, idling...\n");
1387: }
1388: #endif
1389: f->wstate = SOCK_WIDLE;
1390: return 0;
1391: }
1392:
1393: /*
1394: * iteration of the socket reader loop, return 1 on success
1395: */
1396: int
1397: sock_read(struct sock *f)
1398: {
1399: #ifdef DEBUG
1400: if (log_level >= 4) {
1401: sock_log(f);
1402: log_puts(": reading ");
1403: log_putu(f->rtodo);
1404: log_puts(" todo\n");
1405: }
1406: #endif
1407: switch (f->rstate) {
1408: case SOCK_RIDLE:
1409: return 0;
1410: case SOCK_RMSG:
1411: if (!sock_rmsg(f))
1412: return 0;
1413: if (!sock_execmsg(f))
1414: return 0;
1415: break;
1416: case SOCK_RDATA:
1417: if (!sock_rdata(f))
1418: return 0;
1419: f->rstate = SOCK_RMSG;
1420: f->rtodo = sizeof(struct amsg);
1421: break;
1422: case SOCK_RRET:
1423: if (f->wstate != SOCK_WIDLE) {
1424: #ifdef DEBUG
1425: if (log_level >= 4) {
1426: sock_log(f);
1427: log_puts(": can't reply, write-end blocked\n");
1428: }
1429: #endif
1430: return 0;
1431: }
1432: f->wmsg = f->rmsg;
1433: f->wstate = SOCK_WMSG;
1434: f->wtodo = sizeof(struct amsg);
1435: f->rstate = SOCK_RMSG;
1436: f->rtodo = sizeof(struct amsg);
1437: #ifdef DEBUG
1438: if (log_level >= 4) {
1439: sock_log(f);
1440: log_puts(": copied RRET message\n");
1441: }
1442: #endif
1443: }
1444: return 1;
1445: }
1446:
1447: /*
1448: * iteration of the socket writer loop, return 1 on success
1449: */
1450: int
1451: sock_write(struct sock *f)
1452: {
1453: #ifdef DEBUG
1454: if (log_level >= 4) {
1455: sock_log(f);
1456: log_puts(": writing");
1457: if (f->wstate != SOCK_WIDLE) {
1458: log_puts(" todo = ");
1459: log_putu(f->wtodo);
1460: }
1461: log_puts("\n");
1462: }
1463: #endif
1464: switch (f->wstate) {
1465: case SOCK_WMSG:
1466: if (!sock_wmsg(f))
1467: return 0;
1.20 ratchov 1468: /*
1469: * f->wmsg is either build by sock_buildmsg() or
1470: * copied from f->rmsg (in the SOCK_RRET state), so
1471: * it's safe.
1472: */
1.1 ratchov 1473: if (ntohl(f->wmsg.cmd) != AMSG_DATA) {
1474: f->wstate = SOCK_WIDLE;
1475: f->wtodo = 0xdeadbeef;
1476: break;
1477: }
1478: f->wstate = SOCK_WDATA;
1479: f->wsize = f->wtodo = ntohl(f->wmsg.u.data.size);
1480: /* PASSTHROUGH */
1481: case SOCK_WDATA:
1482: if (!sock_wdata(f))
1483: return 0;
1484: if (f->wtodo > 0)
1485: break;
1486: f->wstate = SOCK_WIDLE;
1487: f->wtodo = 0xdeadbeef;
1488: if (f->pstate == SOCK_STOP) {
1489: f->pstate = SOCK_INIT;
1490: f->wmax = 0;
1491: #ifdef DEBUG
1492: if (log_level >= 4) {
1493: sock_log(f);
1494: log_puts(": drained, moved to INIT state\n");
1495: }
1496: #endif
1497: }
1498: /* PASSTHROUGH */
1499: case SOCK_WIDLE:
1500: if (f->rstate == SOCK_RRET) {
1501: f->wmsg = f->rmsg;
1502: f->wstate = SOCK_WMSG;
1503: f->wtodo = sizeof(struct amsg);
1504: f->rstate = SOCK_RMSG;
1505: f->rtodo = sizeof(struct amsg);
1506: #ifdef DEBUG
1507: if (log_level >= 4) {
1508: sock_log(f);
1509: log_puts(": copied RRET message\n");
1510: }
1511: #endif
1512: } else {
1513: if (!sock_buildmsg(f))
1514: return 0;
1515: }
1516: break;
1517: #ifdef DEBUG
1518: default:
1519: sock_log(f);
1520: log_puts(": bad writing end state\n");
1521: panic();
1522: #endif
1523: }
1524: return 1;
1525: }
1526:
1527: int
1528: sock_pollfd(void *arg, struct pollfd *pfd)
1529: {
1530: struct sock *f = arg;
1531: int events = 0;
1532:
1533: /*
1534: * feedback counters, clock ticks and alike may have changed,
1535: * prepare a message to trigger writes
1536: *
1537: * XXX: doing this at the beginning of the cycle is not optimal,
1538: * because state is changed at the end of the read cycle, and
1539: * thus counters, ret message and alike are generated then.
1540: */
1541: if (f->wstate == SOCK_WIDLE && f->rstate != SOCK_RRET)
1542: sock_buildmsg(f);
1543:
1544: if (f->rstate == SOCK_RMSG ||
1545: f->rstate == SOCK_RDATA)
1546: events |= POLLIN;
1547: if (f->rstate == SOCK_RRET ||
1548: f->wstate == SOCK_WMSG ||
1549: f->wstate == SOCK_WDATA)
1550: events |= POLLOUT;
1551: pfd->fd = f->fd;
1552: pfd->events = events;
1553: return 1;
1554: }
1555:
1556: int
1557: sock_revents(void *arg, struct pollfd *pfd)
1558: {
1559: return pfd->revents;
1560: }
1561:
1562: void
1563: sock_in(void *arg)
1564: {
1565: struct sock *f = arg;
1566:
1567: while (sock_read(f))
1568: ;
1569: }
1570:
1571: void
1572: sock_out(void *arg)
1573: {
1574: struct sock *f = arg;
1575:
1576: while (sock_write(f))
1577: ;
1578: }
1579:
1580: void
1581: sock_hup(void *arg)
1582: {
1583: struct sock *f = arg;
1584:
1585: sock_close(f);
1586: }