Annotation of src/usr.bin/aucat/sock.c, Revision 1.27
1.27 ! ratchov 1: /* $OpenBSD: sock.c,v 1.26 2009/08/27 06:31:13 ratchov Exp $ */
1.1 ratchov 2: /*
3: * Copyright (c) 2008 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: /*
18: * TODO:
19: *
20: * change f->bufsz to contain only socket-side buffer,
21: * because it's less error prone
22: */
23:
24: #include <stdio.h>
25: #include <stdlib.h>
26: #include <string.h>
1.20 ratchov 27:
28: #include "abuf.h"
1.1 ratchov 29: #include "aproc.h"
1.20 ratchov 30: #include "conf.h"
1.1 ratchov 31: #include "dev.h"
1.19 ratchov 32: #include "midi.h"
33: #include "opt.h"
1.20 ratchov 34: #include "sock.h"
1.1 ratchov 35:
36: int sock_attach(struct sock *, int);
37: int sock_read(struct sock *);
38: int sock_write(struct sock *);
39: int sock_execmsg(struct sock *);
40: void sock_reset(struct sock *);
41:
42: struct fileops sock_ops = {
43: "sock",
44: sizeof(struct sock),
45: pipe_close,
46: pipe_read,
47: pipe_write,
48: NULL, /* start */
49: NULL, /* stop */
50: pipe_nfds,
51: pipe_pollfd,
52: pipe_revents
53: };
54:
55: void
56: rsock_done(struct aproc *p)
57: {
58: struct sock *f = (struct sock *)p->u.io.file;
59:
60: DPRINTFN(1, "rsock_done: %p\n", f);
1.11 ratchov 61: if (f == NULL)
62: return;
1.1 ratchov 63: sock_reset(f);
64: f->pipe.file.rproc = NULL;
65: if (f->pipe.file.wproc) {
1.24 ratchov 66: if (dev_midi && f->slot >= 0)
67: ctl_slotdel(dev_midi, f->slot);
1.1 ratchov 68: aproc_del(f->pipe.file.wproc);
69: file_del(&f->pipe.file);
70: }
1.11 ratchov 71: p->u.io.file = NULL;
1.1 ratchov 72: }
73:
74: int
75: rsock_in(struct aproc *p, struct abuf *ibuf_dummy)
76: {
77: struct sock *f = (struct sock *)p->u.io.file;
78: struct abuf *obuf;
79:
80: DPRINTFN(4, "rsock_in: %p\n", f);
81:
82: if (!sock_read(f))
83: return 0;
84: obuf = LIST_FIRST(&p->obuflist);
85: if (obuf) {
86: if (!abuf_flush(obuf))
87: return 0;
88: }
89: return 1;
90: }
91:
92: int
93: rsock_out(struct aproc *p, struct abuf *obuf)
94: {
95: struct sock *f = (struct sock *)p->u.io.file;
96:
1.19 ratchov 97: if (f->pipe.file.state & FILE_RINUSE)
1.1 ratchov 98: return 0;
99:
100: DPRINTFN(4, "rsock_out: %p\n", f);
101:
1.12 ratchov 102: /*
1.20 ratchov 103: * When calling sock_read(), we may receive a ``STOP'' command,
1.1 ratchov 104: * and detach ``obuf''. In this case, there's no more caller and
1.20 ratchov 105: * we'll stop processing further messages, resulting in a deadlock.
1.1 ratchov 106: * The solution is to iterate over sock_read() in order to
107: * consume all messages().
108: */
109: for (;;) {
110: if (!sock_read(f))
1.12 ratchov 111: return 0;
1.1 ratchov 112: }
113: return 1;
114: }
115:
116: void
117: rsock_eof(struct aproc *p, struct abuf *ibuf_dummy)
118: {
119: DPRINTFN(3, "rsock_eof: %p\n", p->u.io.file);
120: aproc_del(p);
121: }
122:
123: void
124: rsock_hup(struct aproc *p, struct abuf *ibuf)
125: {
126: DPRINTFN(3, "rsock_hup: %p\n", p->u.io.file);
127: aproc_del(p);
128: }
129:
130: void
131: rsock_opos(struct aproc *p, struct abuf *obuf, int delta)
132: {
133: struct sock *f = (struct sock *)p->u.io.file;
134:
1.15 ratchov 135: if (f->mode & AMSG_REC)
1.14 ratchov 136: return;
137:
138: f->delta += delta;
139: DPRINTFN(3, "rsock_opos: %p: delta = %d, f->delta = %d\n",
140: f, delta, f->delta);
1.1 ratchov 141:
142: /*
1.16 jakemsr 143: * Negative deltas are xrun notifications for internal uses
144: * only. Don't generate a packet for this, the client will be
1.1 ratchov 145: * notified later.
146: */
1.14 ratchov 147: if (delta < 0)
1.1 ratchov 148: return;
1.14 ratchov 149: f->tickpending++;
1.1 ratchov 150: for (;;) {
151: if (!sock_write(f))
152: break;
153: }
154: }
155:
156: struct aproc_ops rsock_ops = {
157: "rsock",
158: rsock_in,
159: rsock_out,
160: rsock_eof,
161: rsock_hup,
162: NULL, /* newin */
163: NULL, /* newout */
164: NULL, /* ipos */
165: rsock_opos,
166: rsock_done
167: };
168:
169: void
170: wsock_done(struct aproc *p)
171: {
172: struct sock *f = (struct sock *)p->u.io.file;
173:
174: DPRINTFN(1, "wsock_done: %p\n", f);
1.11 ratchov 175: if (f == NULL)
176: return;
1.1 ratchov 177: sock_reset(f);
178: f->pipe.file.wproc = NULL;
179: if (f->pipe.file.rproc) {
1.24 ratchov 180: if (dev_midi && f->slot >= 0)
181: ctl_slotdel(dev_midi, f->slot);
1.1 ratchov 182: aproc_del(f->pipe.file.rproc);
183: file_del(&f->pipe.file);
184: }
1.11 ratchov 185: p->u.io.file = NULL;
1.1 ratchov 186: }
187:
188: int
189: wsock_in(struct aproc *p, struct abuf *ibuf)
190: {
191: struct sock *f = (struct sock *)p->u.io.file;
192:
1.19 ratchov 193: if (f->pipe.file.state & FILE_WINUSE)
1.1 ratchov 194: return 0;
195:
196: DPRINTFN(4, "wsock_in: %p\n", f);
197: /*
1.20 ratchov 198: * See remark in rsock_out().
1.1 ratchov 199: */
200: for (;;) {
201: if (!sock_write(f))
202: return 0;
203: }
204: return 1;
205: }
206:
207: int
208: wsock_out(struct aproc *p, struct abuf *obuf_dummy)
209: {
210: struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
211: struct sock *f = (struct sock *)p->u.io.file;
212:
213: DPRINTFN(3, "wsock_out: %p\n", f);
214:
215: if (ibuf) {
216: DPRINTFN(3, "wsock_out: %p, filling ibuf\n", f);
217: if (!abuf_fill(ibuf))
218: return 0;
219: }
220: if (!sock_write(f))
221: return 0;
222: return 1;
223: }
224:
225: void
226: wsock_eof(struct aproc *p, struct abuf *obuf)
227: {
228: DPRINTFN(3, "wsock_eof: %p\n", p->u.io.file);
229: aproc_del(p);
230: }
231:
232: void
233: wsock_hup(struct aproc *p, struct abuf *obuf_dummy)
234: {
235: DPRINTFN(3, "wsock_hup: %p\n", p->u.io.file);
236: aproc_del(p);
237: }
238:
239: void
240: wsock_ipos(struct aproc *p, struct abuf *obuf, int delta)
241: {
242: struct sock *f = (struct sock *)p->u.io.file;
243:
1.14 ratchov 244: if (!(f->mode & AMSG_REC))
245: return;
1.1 ratchov 246:
1.14 ratchov 247: f->delta += delta;
248: DPRINTFN(3, "wsock_ipos: %p, delta = %d, f->delta = %d\n",
249: f, delta, f->delta);
1.1 ratchov 250: /*
1.16 jakemsr 251: * Negative deltas are xrun notifications for internal uses
252: * only. Don't generate a packet for this, the client will be
1.1 ratchov 253: * notified later.
254: */
1.14 ratchov 255: if (delta < 0)
1.1 ratchov 256: return;
1.14 ratchov 257: f->tickpending++;
1.1 ratchov 258: for (;;) {
259: if (!sock_write(f))
260: break;
261: }
262: }
263:
264: struct aproc_ops wsock_ops = {
265: "wsock",
266: wsock_in,
267: wsock_out,
268: wsock_eof,
269: wsock_hup,
270: NULL, /* newin */
271: NULL, /* newout */
272: wsock_ipos,
273: NULL, /* opos */
274: wsock_done
275: };
276:
277: /*
1.20 ratchov 278: * Initialise socket in the SOCK_HELLO state with default
279: * parameters.
1.1 ratchov 280: */
281: struct sock *
1.19 ratchov 282: sock_new(struct fileops *ops, int fd)
1.1 ratchov 283: {
284: struct aproc *rproc, *wproc;
285: struct sock *f;
286:
1.19 ratchov 287: f = (struct sock *)pipe_new(ops, fd, "sock");
1.13 ratchov 288: if (f == NULL)
289: return NULL;
1.18 ratchov 290: f->pstate = SOCK_HELLO;
1.1 ratchov 291: f->mode = 0;
1.19 ratchov 292: f->opt = opt_byname("default");
293: if (f->opt) {
294: if (dev_rec)
295: f->wpar = f->opt->wpar;
296: if (dev_play)
297: f->rpar = f->opt->rpar;
1.1 ratchov 298: }
299: f->xrun = AMSG_IGNORE;
1.10 ratchov 300: f->bufsz = dev_bufsz;
1.1 ratchov 301: f->round = dev_round;
1.14 ratchov 302: f->delta = 0;
303: f->tickpending = 0;
1.25 ratchov 304: f->vol = f->lastvol = MIDI_MAXCTL;
1.24 ratchov 305: f->slot = -1;
1.1 ratchov 306:
1.19 ratchov 307: wproc = aproc_new(&wsock_ops, f->pipe.file.name);
1.1 ratchov 308: wproc->u.io.file = &f->pipe.file;
309: f->pipe.file.wproc = wproc;
310: f->wstate = SOCK_WIDLE;
311: f->wtodo = 0xdeadbeef;
312:
1.19 ratchov 313: rproc = aproc_new(&rsock_ops, f->pipe.file.name);
1.1 ratchov 314: rproc->u.io.file = &f->pipe.file;
315: f->pipe.file.rproc = rproc;
316: f->rstate = SOCK_RMSG;
317: f->rtodo = sizeof(struct amsg);
318: return f;
319: }
320:
321: /*
1.20 ratchov 322: * Free buffers.
1.1 ratchov 323: */
324: void
325: sock_freebuf(struct sock *f)
326: {
327: struct abuf *rbuf, *wbuf;
1.12 ratchov 328:
1.1 ratchov 329: f->pstate = SOCK_INIT;
330: DPRINTF("sock_freebuf:\n");
331: rbuf = LIST_FIRST(&f->pipe.file.rproc->obuflist);
332: if (rbuf)
333: abuf_eof(rbuf);
334: wbuf = LIST_FIRST(&f->pipe.file.wproc->ibuflist);
335: if (wbuf)
336: abuf_hup(wbuf);
337: }
338:
339: /*
1.20 ratchov 340: * Allocate buffers, so client can start filling write-end.
1.1 ratchov 341: */
342: void
343: sock_allocbuf(struct sock *f)
344: {
345: struct abuf *rbuf = NULL, *wbuf = NULL;
346:
347: if (f->mode & AMSG_PLAY) {
1.10 ratchov 348: rbuf = abuf_new(f->bufsz, &f->rpar);
1.1 ratchov 349: aproc_setout(f->pipe.file.rproc, rbuf);
350: }
351: if (f->mode & AMSG_REC) {
1.10 ratchov 352: wbuf = abuf_new(f->bufsz, &f->wpar);
1.1 ratchov 353: aproc_setin(f->pipe.file.wproc, wbuf);
354: }
1.14 ratchov 355: f->delta = 0;
356: f->tickpending = 0;
1.1 ratchov 357:
1.10 ratchov 358: DPRINTF("sock_allocbuf: %p, using %u frames buffer\n", f, f->bufsz);
1.1 ratchov 359:
360: f->pstate = SOCK_START;
361: if (!(f->mode & AMSG_PLAY))
362: (void)sock_attach(f, 0);
363: }
364:
365: /*
1.25 ratchov 366: * Set volume. Callback invoked when volume is modified externally
1.3 ratchov 367: */
368: void
1.25 ratchov 369: sock_setvol(void *arg, unsigned vol)
1.3 ratchov 370: {
1.25 ratchov 371: struct sock *f = (struct sock *)arg;
1.3 ratchov 372: struct abuf *rbuf;
1.12 ratchov 373:
1.3 ratchov 374: f->vol = vol;
1.12 ratchov 375: rbuf = LIST_FIRST(&f->pipe.file.rproc->obuflist);
1.3 ratchov 376: if (!rbuf) {
377: DPRINTF("sock_setvol: no read buffer yet\n");
378: return;
379: }
1.25 ratchov 380: dev_setvol(rbuf, MIDI_TO_ADATA(vol));
1.3 ratchov 381: }
382:
383: /*
1.20 ratchov 384: * Attach play and/or record buffers to dev_mix and/or dev_sub.
1.1 ratchov 385: */
386: int
387: sock_attach(struct sock *f, int force)
388: {
389: struct abuf *rbuf, *wbuf;
390:
391: rbuf = LIST_FIRST(&f->pipe.file.rproc->obuflist);
392: wbuf = LIST_FIRST(&f->pipe.file.wproc->ibuflist);
393:
394: /*
1.20 ratchov 395: * If in SOCK_START state, dont attach until
396: * the buffer isn't completely filled.
1.1 ratchov 397: */
398: if (!force && rbuf && ABUF_WOK(rbuf))
399: return 0;
1.12 ratchov 400:
1.1 ratchov 401: DPRINTF("sock_attach: %p\n", f);
402: f->pstate = SOCK_RUN;
403:
404: /*
1.20 ratchov 405: * Attach them to the device.
1.1 ratchov 406: */
407: dev_attach(f->pipe.file.name,
408: (f->mode & AMSG_PLAY) ? rbuf : NULL, &f->rpar, f->xrun,
1.4 ratchov 409: (f->mode & AMSG_REC) ? wbuf : NULL, &f->wpar, f->xrun,
1.19 ratchov 410: f->opt->maxweight);
1.3 ratchov 411: if (f->mode & AMSG_PLAY)
1.25 ratchov 412: dev_setvol(rbuf, MIDI_TO_ADATA(f->vol));
1.3 ratchov 413:
1.1 ratchov 414: /*
1.20 ratchov 415: * Send the initial position, if needed.
1.1 ratchov 416: */
417: for (;;) {
418: if (!sock_write(f))
419: break;
420: }
421: return 1;
422: }
423:
424: void
425: sock_reset(struct sock *f)
426: {
427: switch (f->pstate) {
428: case SOCK_START:
429: (void)sock_attach(f, 1);
430: f->pstate = SOCK_RUN;
431: /* PASSTHROUGH */
432: case SOCK_RUN:
433: sock_freebuf(f);
434: f->pstate = SOCK_INIT;
435: /* PASSTHROUGH */
436: case SOCK_INIT:
437: /* nothing yet */
438: break;
439: }
440: }
441:
442: /*
1.20 ratchov 443: * Read a message from the file descriptor, return 1 if done, 0
444: * otherwise. The message is stored in f->rmsg.
1.1 ratchov 445: */
446: int
447: sock_rmsg(struct sock *f)
448: {
449: unsigned count;
450: unsigned char *data;
451:
452: while (f->rtodo > 0) {
453: if (!(f->pipe.file.state & FILE_ROK)) {
454: DPRINTFN(4, "sock_rmsg: blk, rtodo = %u\n", f->rtodo);
455: return 0;
456: }
457: data = (unsigned char *)&f->rmsg;
458: data += sizeof(struct amsg) - f->rtodo;
459: count = file_read(&f->pipe.file, data, f->rtodo);
460: if (count == 0)
461: return 0;
462: f->rtodo -= count;
463: }
464: DPRINTFN(4, "sock_rmsg: %p: done\n", f);
465: return 1;
466: }
467:
468: /*
1.20 ratchov 469: * Write a message to the file descriptor, return 1 if done, 0
1.1 ratchov 470: * otherwise. The "m" argument is f->rmsg or f->wmsg, and the "ptodo"
471: * points to the f->rtodo or f->wtodo respectively.
472: */
473: int
474: sock_wmsg(struct sock *f, struct amsg *m, unsigned *ptodo)
475: {
476: unsigned count;
477: unsigned char *data;
478:
479: while (*ptodo > 0) {
480: if (!(f->pipe.file.state & FILE_WOK)) {
481: DPRINTFN(4, "sock_wmsg: blk, *ptodo = %u\n", *ptodo);
482: return 0;
483: }
484: data = (unsigned char *)m;
485: data += sizeof(struct amsg) - *ptodo;
486: count = file_write(&f->pipe.file, data, *ptodo);
487: if (count == 0)
488: return 0;
489: *ptodo -= count;
490: }
491: DPRINTFN(4, "sock_wmsg: %p: done\n", f);
492: return 1;
493: }
494:
495: /*
1.20 ratchov 496: * Read data chunk from the file descriptor, return 1 if at least one
1.1 ratchov 497: * byte was read, 0 if the file blocked.
498: */
499: int
500: sock_rdata(struct sock *f)
501: {
502: struct aproc *p;
503: struct abuf *obuf;
504: unsigned char *data;
505: unsigned count, n;
506:
507: #ifdef DEBUG
1.19 ratchov 508: if (f->pstate != SOCK_MIDI && f->rtodo == 0) {
1.1 ratchov 509: fprintf(stderr, "sock_rdata: bad call: zero arg\n");
510: abort();
511: }
512: #endif
513: p = f->pipe.file.rproc;
514: obuf = LIST_FIRST(&p->obuflist);
1.19 ratchov 515: if (obuf == NULL)
516: return 0;
1.1 ratchov 517: if (ABUF_FULL(obuf) || !(f->pipe.file.state & FILE_ROK))
518: return 0;
519: data = abuf_wgetblk(obuf, &count, 0);
1.19 ratchov 520: if (f->pstate != SOCK_MIDI && count > f->rtodo)
1.1 ratchov 521: count = f->rtodo;
522: n = file_read(&f->pipe.file, data, count);
523: if (n == 0)
524: return 0;
525: abuf_wcommit(obuf, n);
1.19 ratchov 526: if (f->pstate != SOCK_MIDI)
527: f->rtodo -= n;
1.1 ratchov 528: return 1;
529: }
530:
531: /*
1.20 ratchov 532: * Write data chunk to the file descriptor, return 1 if at least one
1.1 ratchov 533: * byte was written, 0 if the file blocked.
534: */
535: int
536: sock_wdata(struct sock *f)
537: {
538: struct aproc *p;
539: struct abuf *ibuf;
540: unsigned char *data;
541: unsigned count, n;
542: #define ZERO_MAX 0x1000
543: static char zero[ZERO_MAX];
544:
545: #ifdef DEBUG
1.19 ratchov 546: if (f->pstate != SOCK_MIDI && f->wtodo == 0) {
1.1 ratchov 547: fprintf(stderr, "sock_wdata: bad call: zero arg\n");
548: abort();
549: }
550: #endif
551: if (!(f->pipe.file.state & FILE_WOK))
552: return 0;
553: p = f->pipe.file.wproc;
554: ibuf = LIST_FIRST(&p->ibuflist);
555: if (ibuf) {
556: if (ABUF_EMPTY(ibuf))
557: return 0;
558: data = abuf_rgetblk(ibuf, &count, 0);
1.19 ratchov 559: if (f->pstate != SOCK_MIDI && count > f->wtodo)
1.1 ratchov 560: count = f->wtodo;
561: n = file_write(&f->pipe.file, data, count);
562: if (n == 0)
563: return 0;
564: abuf_rdiscard(ibuf, n);
1.19 ratchov 565: if (f->pstate != SOCK_MIDI)
566: f->wtodo -= n;
1.1 ratchov 567: } else {
1.19 ratchov 568: if (f->pstate == SOCK_MIDI)
569: return 0;
1.1 ratchov 570: /*
1.20 ratchov 571: * There's no dev_detach() routine yet,
1.1 ratchov 572: * so now we abruptly destroy the buffer.
573: * Until we implement dev_detach, complete
574: * the packet with zeros...
575: */
576: count = ZERO_MAX;
577: if (count > f->wtodo)
578: count = f->wtodo;
579: n = file_write(&f->pipe.file, zero, count);
580: if (n == 0)
581: return 0;
582: f->wtodo -= n;
1.12 ratchov 583: }
1.1 ratchov 584: return 1;
585: }
586:
587: int
588: sock_setpar(struct sock *f)
589: {
590: struct amsg_par *p = &f->rmsg.u.par;
1.9 ratchov 591: unsigned min, max, rate;
1.12 ratchov 592:
1.18 ratchov 593: if (AMSG_ISSET(p->legacy_mode)) {
594: /*
595: * XXX: allow old clients that don't support HELLO
596: * to work
597: */
598: if ((p->legacy_mode & ~(AMSG_PLAY | AMSG_REC)) ||
599: (p->legacy_mode == 0)) {
600: DPRINTF("sock_setpar: bad mode %x\n", p->legacy_mode);
1.1 ratchov 601: return 0;
602: }
603: f->mode = 0;
1.18 ratchov 604: if ((p->legacy_mode & AMSG_PLAY) && dev_mix)
1.1 ratchov 605: f->mode |= AMSG_PLAY;
1.18 ratchov 606: if ((p->legacy_mode & AMSG_REC) && dev_sub)
1.1 ratchov 607: f->mode |= AMSG_REC;
608: DPRINTF("sock_setpar: mode -> %x\n", f->mode);
609: }
610: if (AMSG_ISSET(p->bits)) {
611: if (p->bits < BITS_MIN || p->bits > BITS_MAX) {
612: DPRINTF("sock_setpar: bits out of bounds\n");
613: return 0;
614: }
615: if (AMSG_ISSET(p->bps)) {
616: if (p->bps < ((p->bits + 7) / 8) || p->bps > 4) {
617: DPRINTF("sock_setpar: bps out of bounds\n");
618: return 0;
619: }
620: } else
621: p->bps = APARAMS_BPS(p->bits);
622: f->rpar.bits = f->wpar.bits = p->bits;
623: f->rpar.bps = f->wpar.bps = p->bps;
624: DPRINTF("sock_setpar: bits/bps -> %u/%u\n", p->bits, p->bps);
625: }
626: if (AMSG_ISSET(p->sig))
627: f->rpar.sig = f->wpar.sig = p->sig ? 1 : 0;
628: if (AMSG_ISSET(p->le))
629: f->rpar.le = f->wpar.le = p->le ? 1 : 0;
630: if (AMSG_ISSET(p->msb))
631: f->rpar.msb = f->wpar.msb = p->msb ? 1 : 0;
632: if (AMSG_ISSET(p->rchan) && (f->mode & AMSG_REC)) {
633: if (p->rchan < 1)
634: p->rchan = 1;
1.6 ratchov 635: if (p->rchan > NCHAN_MAX)
636: p->rchan = NCHAN_MAX;
1.19 ratchov 637: f->wpar.cmin = f->opt->wpar.cmin;
638: f->wpar.cmax = f->opt->wpar.cmin + p->rchan - 1;
639: if (f->wpar.cmax > f->opt->wpar.cmax)
640: f->wpar.cmax = f->opt->wpar.cmax;
1.6 ratchov 641: DPRINTF("sock_setpar: rchan -> %u:%u\n",
642: f->wpar.cmin, f->wpar.cmax);
1.1 ratchov 643: }
644: if (AMSG_ISSET(p->pchan) && (f->mode & AMSG_PLAY)) {
645: if (p->pchan < 1)
646: p->pchan = 1;
1.6 ratchov 647: if (p->pchan > NCHAN_MAX)
648: p->pchan = NCHAN_MAX;
1.19 ratchov 649: f->rpar.cmin = f->opt->rpar.cmin;
650: f->rpar.cmax = f->opt->rpar.cmin + p->pchan - 1;
651: if (f->rpar.cmax > f->opt->rpar.cmax)
652: f->rpar.cmax = f->opt->rpar.cmax;
1.6 ratchov 653: DPRINTF("sock_setpar: pchan -> %u:%u\n",
654: f->rpar.cmin, f->rpar.cmax);
1.1 ratchov 655: }
656: if (AMSG_ISSET(p->rate)) {
657: if (p->rate < RATE_MIN)
658: p->rate = RATE_MIN;
659: if (p->rate > RATE_MAX)
660: p->rate = RATE_MAX;
1.9 ratchov 661: f->round = dev_roundof(p->rate);
1.1 ratchov 662: f->rpar.rate = f->wpar.rate = p->rate;
1.10 ratchov 663: if (!AMSG_ISSET(p->appbufsz)) {
664: p->appbufsz = dev_bufsz / dev_round * f->round;
665: DPRINTF("sock_setpar: appbufsz -> %u\n", p->appbufsz);
666: }
1.9 ratchov 667: DPRINTF("sock_setpar: rate -> %u, round -> %u\n",
668: p->rate, f->round);
1.1 ratchov 669: }
670: if (AMSG_ISSET(p->xrun)) {
671: if (p->xrun != AMSG_IGNORE &&
672: p->xrun != AMSG_SYNC &&
673: p->xrun != AMSG_ERROR) {
674: DPRINTF("sock_setpar: bad xrun: %u\n", p->xrun);
675: return 0;
676: }
677: f->xrun = p->xrun;
678: DPRINTF("sock_setpar: xrun -> %u\n", f->xrun);
679: }
680: if (AMSG_ISSET(p->bufsz)) {
1.10 ratchov 681: /*
682: * XXX: bufsz will become read-only, but for now
683: * allow old library to properly work
684: */
685: DPRINTF("sock_setpar: bufsz: %u\n", p->bufsz);
686: min = (dev_bufsz / dev_round) * f->round;
687: if (p->bufsz < min)
688: p->bufsz = min;
689: p->appbufsz = p->bufsz - min;
690: }
691: if (AMSG_ISSET(p->appbufsz)) {
1.9 ratchov 692: rate = (f->mode & AMSG_PLAY) ? f->rpar.rate : f->wpar.rate;
1.10 ratchov 693: min = 1;
694: max = 1 + rate / dev_round;
1.9 ratchov 695: min *= f->round;
696: max *= f->round;
1.10 ratchov 697: p->appbufsz += f->round - 1;
698: p->appbufsz -= p->appbufsz % f->round;
699: if (p->appbufsz < min)
700: p->appbufsz = min;
701: if (p->appbufsz > max)
702: p->appbufsz = max;
703: f->bufsz = p->appbufsz;
1.1 ratchov 704: DPRINTF("sock_setpar: bufsz -> %u\n", f->bufsz);
705: }
1.5 ratchov 706: #ifdef DEBUG
1.1 ratchov 707: if (debug_level > 0) {
708: fprintf(stderr, "sock_setpar: %p: rpar=", f);
709: aparams_print(&f->rpar);
710: fprintf(stderr, ", wpar=");
711: aparams_print(&f->wpar);
712: fprintf(stderr, ", mode=%u, bufsz=%u\n", f->mode, f->bufsz);
713: }
1.5 ratchov 714: #endif
1.1 ratchov 715: return 1;
716: }
717:
1.19 ratchov 718: /*
719: * allocate buffers, so client can start filling write-end.
720: */
721: void
722: sock_midiattach(struct sock *f, unsigned mode)
723: {
724: struct abuf *rbuf = NULL, *wbuf = NULL;
725:
726: if (mode & AMSG_MIDIOUT) {
1.22 ratchov 727: rbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
1.19 ratchov 728: aproc_setout(f->pipe.file.rproc, rbuf);
729: }
730: if (mode & AMSG_MIDIIN) {
1.22 ratchov 731: wbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
1.19 ratchov 732: aproc_setin(f->pipe.file.wproc, wbuf);
733: }
1.23 ratchov 734: dev_midiattach(rbuf, wbuf);
1.19 ratchov 735: }
736:
1.17 ratchov 737: int
738: sock_hello(struct sock *f)
739: {
740: struct amsg_hello *p = &f->rmsg.u.hello;
741:
1.19 ratchov 742: DPRINTF("sock_hello: from <%s>, mode = %x\n", p->who, p->proto);
743:
1.23 ratchov 744: if (dev_midi && (p->proto & (AMSG_MIDIIN | AMSG_MIDIOUT))) {
1.19 ratchov 745: if (p->proto & ~(AMSG_MIDIIN | AMSG_MIDIOUT)) {
746: DPRINTF("sock_hello: %x: bad proto\n", p->proto);
747: return 0;
748: }
749: f->mode = p->proto;
750: f->pstate = SOCK_MIDI;
751: sock_midiattach(f, p->proto);
752: return 1;
753: }
754: f->opt = opt_byname(p->opt);
755: if (f->opt == NULL)
756: return 0;
757: if (dev_rec)
758: f->wpar = f->opt->wpar;
759: if (dev_play)
760: f->rpar = f->opt->rpar;
1.18 ratchov 761: if ((p->proto & ~(AMSG_PLAY | AMSG_REC)) != 0 ||
762: (p->proto & (AMSG_PLAY | AMSG_REC)) == 0) {
763: DPRINTF("sock_hello: %x: unsupported proto\n", p->proto);
1.17 ratchov 764: return 0;
765: }
1.18 ratchov 766: f->mode = 0;
767: if (p->proto & AMSG_PLAY) {
768: if (!dev_mix) {
769: DPRINTF("sock_hello: playback not supported\n");
770: return 0;
771: }
772: f->mode |= AMSG_PLAY;
1.17 ratchov 773: }
1.18 ratchov 774: if (p->proto & AMSG_REC) {
775: if (!dev_sub) {
776: DPRINTF("sock_hello: recording not supported\n");
777: return 0;
778: }
779: f->mode |= AMSG_REC;
1.17 ratchov 780: }
1.24 ratchov 781: if (dev_midi) {
1.25 ratchov 782: f->slot = ctl_slotnew(dev_midi, p->who, sock_setvol, f);
1.24 ratchov 783: if (f->slot < 0) {
784: DPRINTF("sock_hello: out of mixer slots\n");
785: return 0;
786: }
787: }
1.18 ratchov 788: f->pstate = SOCK_INIT;
1.17 ratchov 789: return 1;
790: }
791:
1.1 ratchov 792: /*
1.20 ratchov 793: * Execute message in f->rmsg and change the state accordingly; return 1
1.1 ratchov 794: * on success, and 0 on failure, in which case the socket is destroyed.
795: */
796: int
797: sock_execmsg(struct sock *f)
798: {
799: struct amsg *m = &f->rmsg;
800:
1.18 ratchov 801: /*
1.19 ratchov 802: * XXX: allow old clients to work without hello on the default socket
1.18 ratchov 803: */
1.19 ratchov 804: if (f->pstate == SOCK_HELLO && m->cmd != AMSG_HELLO && f->opt != NULL) {
1.18 ratchov 805: DPRINTF("sock_execmsg: legacy client\n");
806: f->pstate = SOCK_INIT;
807: }
808:
1.1 ratchov 809: switch (m->cmd) {
810: case AMSG_DATA:
811: DPRINTFN(4, "sock_execmsg: %p: DATA\n", f);
812: if (f->pstate != SOCK_RUN && f->pstate != SOCK_START) {
813: DPRINTF("sock_execmsg: %p: DATA, bad state\n", f);
1.8 ratchov 814: aproc_del(f->pipe.file.rproc);
815: return 0;
816: }
817: if (!(f->mode & AMSG_PLAY)) {
818: DPRINTF("sock_execmsg: %p: DATA, not allowed\n", f);
1.1 ratchov 819: aproc_del(f->pipe.file.rproc);
820: return 0;
821: }
822: f->rstate = SOCK_RDATA;
823: f->rtodo = m->u.data.size;
824: if (f->rtodo == 0) {
825: DPRINTF("sock_execmsg: zero-length data chunk\n");
826: aproc_del(f->pipe.file.rproc);
827: return 0;
828: }
829: break;
830: case AMSG_START:
831: DPRINTFN(2, "sock_execmsg: %p: START\n", f);
832: if (f->pstate != SOCK_INIT) {
833: DPRINTF("sock_execmsg: %p: START, bad state\n", f);
834: aproc_del(f->pipe.file.rproc);
835: return 0;
836: }
837: sock_allocbuf(f);
838: f->rstate = SOCK_RMSG;
839: f->rtodo = sizeof(struct amsg);
840: break;
841: case AMSG_STOP:
842: DPRINTFN(2, "sock_execmsg: %p: STOP\n", f);
843: if (f->pstate != SOCK_RUN && f->pstate != SOCK_START) {
844: DPRINTF("sock_execmsg: %p: STOP, bad state\n", f);
845: aproc_del(f->pipe.file.rproc);
846: return 0;
847: }
848: if (f->pstate == SOCK_START)
849: (void)sock_attach(f, 1);
850: sock_freebuf(f);
851: AMSG_INIT(m);
852: m->cmd = AMSG_ACK;
853: f->rstate = SOCK_RRET;
854: f->rtodo = sizeof(struct amsg);
855: break;
856: case AMSG_SETPAR:
857: DPRINTFN(2, "sock_execmsg: %p: SETPAR\n", f);
858: if (f->pstate != SOCK_INIT) {
859: DPRINTF("sock_execmsg: %p: SETPAR, bad state\n", f);
860: aproc_del(f->pipe.file.rproc);
861: return 0;
862: }
863: if (!sock_setpar(f)) {
864: aproc_del(f->pipe.file.rproc);
865: return 0;
866: }
867: f->rtodo = sizeof(struct amsg);
868: f->rstate = SOCK_RMSG;
869: break;
870: case AMSG_GETPAR:
871: DPRINTFN(2, "sock_execmsg: %p: GETPAR\n", f);
872: if (f->pstate != SOCK_INIT) {
873: DPRINTF("sock_execmsg: %p: GETPAR, bad state\n", f);
874: aproc_del(f->pipe.file.rproc);
875: return 0;
876: }
877: AMSG_INIT(m);
878: m->cmd = AMSG_GETPAR;
1.18 ratchov 879: m->u.par.legacy_mode = f->mode;
1.1 ratchov 880: m->u.par.bits = f->rpar.bits;
881: m->u.par.bps = f->rpar.bps;
882: m->u.par.sig = f->rpar.sig;
883: m->u.par.le = f->rpar.le;
884: m->u.par.msb = f->rpar.msb;
885: m->u.par.rate = f->rpar.rate;
886: m->u.par.rchan = f->wpar.cmax - f->wpar.cmin + 1;
887: m->u.par.pchan = f->rpar.cmax - f->rpar.cmin + 1;
1.10 ratchov 888: m->u.par.appbufsz = f->bufsz;
1.12 ratchov 889: m->u.par.bufsz =
1.10 ratchov 890: f->bufsz + (dev_bufsz / dev_round) * f->round;
1.1 ratchov 891: m->u.par.round = f->round;
892: f->rstate = SOCK_RRET;
893: f->rtodo = sizeof(struct amsg);
894: break;
895: case AMSG_GETCAP:
896: DPRINTFN(2, "sock_execmsg: %p: GETCAP\n", f);
897: if (f->pstate != SOCK_INIT) {
898: DPRINTF("sock_execmsg: %p: GETCAP, bad state\n", f);
899: aproc_del(f->pipe.file.rproc);
900: return 0;
901: }
902: AMSG_INIT(m);
903: m->cmd = AMSG_GETCAP;
904: m->u.cap.rate = dev_rate;
1.6 ratchov 905: m->u.cap.pchan = dev_mix ?
1.19 ratchov 906: (f->opt->rpar.cmax - f->opt->rpar.cmin + 1) : 0;
1.6 ratchov 907: m->u.cap.rchan = dev_sub ?
1.19 ratchov 908: (f->opt->wpar.cmax - f->opt->wpar.cmin + 1) : 0;
1.1 ratchov 909: m->u.cap.bits = sizeof(short) * 8;
910: m->u.cap.bps = sizeof(short);
911: f->rstate = SOCK_RRET;
912: f->rtodo = sizeof(struct amsg);
1.3 ratchov 913: break;
914: case AMSG_SETVOL:
915: DPRINTFN(2, "sock_execmsg: %p: SETVOL\n", f);
916: if (f->pstate != SOCK_RUN &&
917: f->pstate != SOCK_START && f->pstate != SOCK_INIT) {
918: DPRINTF("sock_execmsg: %p: SETVOL, bad state\n", f);
919: aproc_del(f->pipe.file.rproc);
920: return 0;
921: }
922: if (m->u.vol.ctl > MIDI_MAXCTL) {
923: DPRINTF("sock_execmsg: %p: SETVOL, out of range\n", f);
924: aproc_del(f->pipe.file.rproc);
925: return 0;
926: }
927: DPRINTF("sock_execmsg: SETVOL %u\n", m->u.vol.ctl);
1.25 ratchov 928: sock_setvol(f, m->u.vol.ctl);
1.24 ratchov 929: if (dev_midi && f->slot >= 0)
930: ctl_slotvol(dev_midi, f->slot, m->u.vol.ctl);
1.3 ratchov 931: f->rtodo = sizeof(struct amsg);
932: f->rstate = SOCK_RMSG;
1.17 ratchov 933: break;
934: case AMSG_HELLO:
935: DPRINTFN(2, "sock_execmsg: %p: HELLO\n", f);
1.18 ratchov 936: if (f->pstate != SOCK_HELLO) {
1.17 ratchov 937: DPRINTF("sock_execmsg: %p: HELLO, bad state\n", f);
938: aproc_del(f->pipe.file.rproc);
939: return 0;
940: }
941: if (!sock_hello(f)) {
942: aproc_del(f->pipe.file.rproc);
943: return 0;
944: }
945: AMSG_INIT(m);
946: m->cmd = AMSG_ACK;
947: f->rstate = SOCK_RRET;
948: f->rtodo = sizeof(struct amsg);
1.1 ratchov 949: break;
950: default:
951: DPRINTF("sock_execmsg: %p bogus command\n", f);
952: aproc_del(f->pipe.file.rproc);
953: return 0;
954: }
955: if (f->rstate == SOCK_RRET) {
956: if (f->wstate != SOCK_WIDLE ||
957: !sock_wmsg(f, &f->rmsg, &f->rtodo))
958: return 0;
959: DPRINTF("sock_execmsg: %p RRET done\n", f);
1.19 ratchov 960: if (f->pstate == SOCK_MIDI && (f->mode & AMSG_MIDIOUT)) {
961: f->rstate = SOCK_RDATA;
962: f->rtodo = 0;
963: } else {
964: f->rstate = SOCK_RMSG;
965: f->rtodo = sizeof(struct amsg);
966: }
1.1 ratchov 967: }
968: return 1;
969: }
970:
971: /*
1.20 ratchov 972: * Create a new data/pos message.
1.1 ratchov 973: */
974: int
975: sock_buildmsg(struct sock *f)
976: {
977: struct aproc *p;
978: struct abuf *ibuf;
1.12 ratchov 979:
1.19 ratchov 980: if (f->pstate == SOCK_MIDI) {
981: DPRINTFN(4, "sock_buildmsg: %p: switched to midi\n", f);
982: f->wstate = SOCK_WDATA;
983: f->wtodo = 0;
984: return 1;
985: }
986:
1.1 ratchov 987: /*
1.20 ratchov 988: * If pos changed, build a MOVE message.
1.1 ratchov 989: */
1.14 ratchov 990: if (f->tickpending && f->delta >= 0) {
991: DPRINTFN(4, "sock_buildmsg: %p: POS: %d\n", f, f->delta);
1.1 ratchov 992: AMSG_INIT(&f->wmsg);
993: f->wmsg.cmd = AMSG_MOVE;
1.14 ratchov 994: f->wmsg.u.ts.delta = f->delta;
1.1 ratchov 995: f->wtodo = sizeof(struct amsg);
996: f->wstate = SOCK_WMSG;
1.14 ratchov 997: f->delta = 0;
998: f->tickpending = 0;
1.25 ratchov 999: return 1;
1000: }
1001:
1002: /*
1003: * if volume changed build a SETVOL message
1004: */
1.27 ! ratchov 1005: if (f->pstate >= SOCK_START && f->vol != f->lastvol) {
1.25 ratchov 1006: DPRINTFN(4, "sock_buildmsg: %p: SETVOL: %d\n", f, f->vol);
1007: AMSG_INIT(&f->wmsg);
1008: f->wmsg.cmd = AMSG_SETVOL;
1009: f->wmsg.u.vol.ctl = f->vol;
1010: f->wtodo = sizeof(struct amsg);
1011: f->wstate = SOCK_WMSG;
1012: f->lastvol = f->vol;
1.1 ratchov 1013: return 1;
1014: }
1015:
1016: /*
1.20 ratchov 1017: * If data available, build a DATA message.
1.1 ratchov 1018: */
1019: p = f->pipe.file.wproc;
1020: ibuf = LIST_FIRST(&p->ibuflist);
1021: if (ibuf && ABUF_ROK(ibuf)) {
1022: AMSG_INIT(&f->wmsg);
1023: f->wmsg.cmd = AMSG_DATA;
1024: f->wmsg.u.data.size = ibuf->used - (ibuf->used % ibuf->bpf);
1025: if (f->wmsg.u.data.size > AMSG_DATAMAX)
1026: f->wmsg.u.data.size =
1027: AMSG_DATAMAX - (AMSG_DATAMAX % ibuf->bpf);
1028: f->wtodo = sizeof(struct amsg);
1029: f->wstate = SOCK_WMSG;
1030: return 1;
1031: }
1032:
1033: DPRINTFN(4, "sock_buildmsg: %p: idling...\n", f);
1034: f->wstate = SOCK_WIDLE;
1035: return 0;
1036: }
1037:
1038: /*
1.20 ratchov 1039: * Read from the socket file descriptor, fill input buffer and update
1.1 ratchov 1040: * the state. Return 1 if at least one message or 1 data byte was
1041: * processed, 0 if something blocked.
1042: */
1043: int
1044: sock_read(struct sock *f)
1045: {
1046: DPRINTFN(4, "sock_read: %p; rstate = %u, rtodo = %u\n",
1047: f, f->rstate, f->rtodo);
1048:
1049: switch (f->rstate) {
1050: case SOCK_RMSG:
1051: if (!sock_rmsg(f))
1052: return 0;
1053: if (!sock_execmsg(f))
1054: return 0;
1055: break;
1056: case SOCK_RDATA:
1057: if (!sock_rdata(f))
1058: return 0;
1.19 ratchov 1059: if (f->pstate != SOCK_MIDI && f->rtodo == 0) {
1.1 ratchov 1060: f->rstate = SOCK_RMSG;
1061: f->rtodo = sizeof(struct amsg);
1062: }
1063: if (f->pstate == SOCK_START)
1064: (void)sock_attach(f, 0);
1065: break;
1066: case SOCK_RRET:
1067: DPRINTF("sock_read: %p: blocked in RRET\n", f);
1068: return 0;
1069: }
1070: DPRINTFN(4, "sock_read: %p: done, rstate = %u\n", f, f->rstate);
1071: return 1;
1072: }
1073:
1074: /*
1.20 ratchov 1075: * Process messages to return.
1.1 ratchov 1076: */
1077: int
1078: sock_return(struct sock *f)
1079: {
1080: struct aproc *rp;
1081:
1082: while (f->rstate == SOCK_RRET) {
1083: if (!sock_wmsg(f, &f->rmsg, &f->rtodo))
1084: return 0;
1085: DPRINTF("sock_return: %p: done\n", f);
1.19 ratchov 1086: if (f->pstate == SOCK_MIDI && (f->mode & AMSG_MIDIOUT)) {
1087: f->rstate = SOCK_RDATA;
1088: f->rtodo = 0;
1089: } else {
1090: f->rstate = SOCK_RMSG;
1091: f->rtodo = sizeof(struct amsg);
1092: }
1093: if (f->pipe.file.state & FILE_RINUSE)
1094: break;
1095: f->pipe.file.state |= FILE_RINUSE;
1.1 ratchov 1096: for (;;) {
1097: /*
1098: * in() may trigger rsock_done and destroy the
1.20 ratchov 1099: * wsock.
1.1 ratchov 1100: */
1101: rp = f->pipe.file.rproc;
1102: if (!rp || !rp->ops->in(rp, NULL))
1103: break;
1104: }
1.19 ratchov 1105: f->pipe.file.state &= ~FILE_RINUSE;
1.1 ratchov 1106: if (f->pipe.file.wproc == NULL)
1107: return 0;
1108: }
1109: return 1;
1110: }
1111:
1112: /*
1.20 ratchov 1113: * Write messages and data on the socket file descriptor. Return 1 if
1.1 ratchov 1114: * at least one message or one data byte was processed, 0 if something
1115: * blocked.
1116: */
1117: int
1118: sock_write(struct sock *f)
1119: {
1120: DPRINTFN(4, "sock_write: %p: wstate = %u, wtodo = %u\n",
1121: f, f->wstate, f->wtodo);
1122:
1123: switch (f->wstate) {
1124: case SOCK_WMSG:
1125: if (!sock_wmsg(f, &f->wmsg, &f->wtodo))
1126: return 0;
1127: if (f->wmsg.cmd != AMSG_DATA) {
1128: f->wstate = SOCK_WIDLE;
1129: f->wtodo = 0xdeadbeef;
1130: break;
1131: }
1132: f->wstate = SOCK_WDATA;
1133: f->wtodo = f->wmsg.u.data.size;
1134: /* PASSTHROUGH */
1135: case SOCK_WDATA:
1136: if (!sock_wdata(f))
1137: return 0;
1.19 ratchov 1138: if (f->pstate == SOCK_MIDI || f->wtodo > 0)
1.1 ratchov 1139: break;
1140: f->wstate = SOCK_WIDLE;
1141: f->wtodo = 0xdeadbeef;
1142: /* PASSTHROUGH */
1143: case SOCK_WIDLE:
1144: if (!sock_return(f))
1145: return 0;
1146: if (!sock_buildmsg(f))
1147: return 0;
1148: break;
1149: default:
1150: fprintf(stderr, "sock_write: unknown state\n");
1151: abort();
1152: }
1153: return 1;
1154: }