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