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