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