GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/sndiod/sock.c Lines: 0 909 0.0 %
Date: 2017-11-07 Branches: 0 502 0.0 %

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