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