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