GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/sndiod/sock.c Lines: 0 905 0.0 %
Date: 2016-12-06 Branches: 0 537 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: sock.c,v 1.18 2016/03/23 06:16:35 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 socke 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 socke 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
 * read data into 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
		if (f->slot)
544
			data = abuf_rgetblk(&f->slot->sub.buf, &count);
545
		else if (f->midi)
546
			data = abuf_rgetblk(&f->midi->obuf, &count);
547
		if (count > f->wtodo)
548
			count = f->wtodo;
549
		n = sock_fdwrite(f, data, count);
550
		if (n == 0)
551
			return 0;
552
		f->wtodo -= n;
553
		if (f->slot)
554
			abuf_rdiscard(&f->slot->sub.buf, n);
555
		else if (f->midi)
556
			abuf_rdiscard(&f->midi->obuf, n);
557
	}
558
	if (f->slot)
559
		slot_read(f->slot);
560
	if (f->midi)
561
		midi_fill(f->midi);
562
#ifdef DEBUG
563
	if (log_level >= 4) {
564
		sock_log(f);
565
		log_puts(": wrote complete block\n");
566
	}
567
#endif
568
	return 1;
569
}
570
571
int
572
sock_setpar(struct sock *f)
573
{
574
	struct slot *s = f->slot;
575
	struct dev *d = s->dev;
576
	struct amsg_par *p = &f->rmsg.u.par;
577
	unsigned int min, max;
578
	uint32_t rate, appbufsz;
579
	uint16_t pchan, rchan;
580
581
	rchan = ntohs(p->rchan);
582
	pchan = ntohs(p->pchan);
583
	appbufsz = ntohl(p->appbufsz);
584
	rate = ntohl(p->rate);
585
586
	if (AMSG_ISSET(p->bits)) {
587
		if (p->bits < BITS_MIN || p->bits > BITS_MAX) {
588
#ifdef DEBUG
589
			if (log_level >= 1) {
590
				sock_log(f);
591
				log_puts(": ");
592
				log_putu(p->bits);
593
				log_puts(": bits out of bounds\n");
594
			}
595
#endif
596
			return 0;
597
		}
598
		if (AMSG_ISSET(p->bps)) {
599
			if (p->bps < ((p->bits + 7) / 8) || p->bps > 4) {
600
#ifdef DEBUG
601
				if (log_level >= 1) {
602
					sock_log(f);
603
					log_puts(": ");
604
					log_putu(p->bps);
605
					log_puts(": wrong bytes per sample\n");
606
				}
607
#endif
608
				return 0;
609
			}
610
		} else
611
			p->bps = APARAMS_BPS(p->bits);
612
		s->par.bits = p->bits;
613
		s->par.bps = p->bps;
614
	}
615
	if (AMSG_ISSET(p->sig))
616
		s->par.sig = p->sig ? 1 : 0;
617
	if (AMSG_ISSET(p->le))
618
		s->par.le = p->le ? 1 : 0;
619
	if (AMSG_ISSET(p->msb))
620
		s->par.msb = p->msb ? 1 : 0;
621
	if (AMSG_ISSET(rchan) && (s->mode & MODE_RECMASK)) {
622
		if (rchan < 1)
623
			rchan = 1;
624
		if (rchan > NCHAN_MAX)
625
			rchan = NCHAN_MAX;
626
		s->sub.slot_cmin = f->opt->rmin;
627
		s->sub.slot_cmax = f->opt->rmin + rchan - 1;
628
		s->sub.dev_cmin = f->opt->rmin;
629
		s->sub.dev_cmax = f->opt->rmax;
630
#ifdef DEBUG
631
		if (log_level >= 3) {
632
			sock_log(f);
633
			log_puts(": recording channels ");
634
			log_putu(s->sub.dev_cmin);
635
			log_puts(":");
636
			log_putu(s->sub.dev_cmax);
637
			log_puts(" -> ");
638
			log_putu(s->sub.slot_cmin);
639
			log_puts(":");
640
			log_putu(s->sub.slot_cmax);
641
			log_puts("\n");
642
		}
643
#endif
644
	}
645
	if (AMSG_ISSET(pchan) && (s->mode & MODE_PLAY)) {
646
		if (pchan < 1)
647
			pchan = 1;
648
		if (pchan > NCHAN_MAX)
649
			pchan = NCHAN_MAX;
650
		s->mix.slot_cmin = f->opt->pmin;
651
		s->mix.slot_cmax = f->opt->pmin + pchan - 1;
652
		s->mix.dev_cmin = f->opt->pmin;
653
		s->mix.dev_cmax = f->opt->pmax;
654
#ifdef DEBUG
655
		if (log_level >= 3) {
656
			sock_log(f);
657
			log_puts(": playback channels ");
658
			log_putu(s->mix.slot_cmin);
659
			log_puts(":");
660
			log_putu(s->mix.slot_cmax);
661
			log_puts(" -> ");
662
			log_putu(s->mix.dev_cmin);
663
			log_puts(":");
664
			log_putu(s->mix.dev_cmax);
665
			log_puts("\n");
666
		}
667
#endif
668
	}
669
	if (AMSG_ISSET(rate)) {
670
		if (rate < RATE_MIN)
671
			rate = RATE_MIN;
672
		if (rate > RATE_MAX)
673
			rate = RATE_MAX;
674
		s->round = dev_roundof(d, rate);
675
		s->rate = rate;
676
		if (!AMSG_ISSET(appbufsz)) {
677
			appbufsz = d->bufsz / d->round * s->round;
678
#ifdef DEBUG
679
			if (log_level >= 3) {
680
				sock_log(f);
681
				log_puts(": ");
682
				log_putu(appbufsz);
683
				log_puts(" frame buffer\n");
684
			}
685
#endif
686
		}
687
#ifdef DEBUG
688
		if (log_level >= 3) {
689
			sock_log(f);
690
			log_puts(": ");
691
			log_putu(rate);
692
			log_puts("Hz sample rate, ");
693
			log_putu(s->round);
694
			log_puts(" frame blocks\n");
695
		}
696
#endif
697
	}
698
	if (AMSG_ISSET(p->xrun)) {
699
		if (p->xrun != XRUN_IGNORE &&
700
		    p->xrun != XRUN_SYNC &&
701
		    p->xrun != XRUN_ERROR) {
702
#ifdef DEBUG
703
			if (log_level >= 1) {
704
				sock_log(f);
705
				log_puts(": ");
706
				log_putx(p->xrun);
707
				log_puts(": bad xrun policy\n");
708
			}
709
#endif
710
			return 0;
711
		}
712
		s->xrun = p->xrun;
713
		if (f->opt->mmc && s->xrun == XRUN_IGNORE)
714
			s->xrun = XRUN_SYNC;
715
#ifdef DEBUG
716
		if (log_level >= 3) {
717
			sock_log(f);
718
			log_puts(": 0x");
719
			log_putx(s->xrun);
720
			log_puts(" xrun policy\n");
721
		}
722
#endif
723
	}
724
	if (AMSG_ISSET(appbufsz)) {
725
		rate = s->rate;
726
		min = 1;
727
		max = 1 + rate / d->round;
728
		min *= s->round;
729
		max *= s->round;
730
		appbufsz += s->round / 2;
731
		appbufsz -= appbufsz % s->round;
732
		if (appbufsz < min)
733
			appbufsz = min;
734
		if (appbufsz > max)
735
			appbufsz = max;
736
		s->appbufsz = appbufsz;
737
#ifdef DEBUG
738
		if (log_level >= 3) {
739
			sock_log(f);
740
			log_puts(": ");
741
			log_putu(s->appbufsz);
742
			log_puts(" frame buffer\n");
743
		}
744
#endif
745
	}
746
	return 1;
747
}
748
749
int
750
sock_auth(struct sock *f)
751
{
752
	struct amsg_auth *p = &f->rmsg.u.auth;
753
754
	if (sock_sesrefs == 0) {
755
		/* start a new session */
756
		memcpy(sock_sescookie, p->cookie, AMSG_COOKIELEN);
757
	} else if (memcmp(sock_sescookie, p->cookie, AMSG_COOKIELEN) != 0) {
758
		/* another session is active, drop connection */
759
		return 0;
760
	}
761
	sock_sesrefs++;
762
	f->pstate = SOCK_HELLO;
763
	return 1;
764
}
765
766
int
767
sock_hello(struct sock *f)
768
{
769
	struct amsg_hello *p = &f->rmsg.u.hello;
770
	struct slot *s;
771
	struct port *c;
772
	struct dev *d;
773
	unsigned int mode;
774
775
	mode = ntohs(p->mode);
776
#ifdef DEBUG
777
	if (log_level >= 3) {
778
		sock_log(f);
779
		log_puts(": hello from <");
780
		log_puts(p->who);
781
		log_puts(">, mode = ");
782
		log_putx(mode);
783
		log_puts(", ver ");
784
		log_putu(p->version);
785
		log_puts("\n");
786
	}
787
#endif
788
	if (p->version != AMSG_VERSION) {
789
		if (log_level >= 1) {
790
			sock_log(f);
791
			log_puts(": ");
792
			log_putu(p->version);
793
			log_puts(": unsupported protocol version\n");
794
		}
795
		return 0;
796
	}
797
	switch (mode) {
798
	case MODE_MIDIIN:
799
	case MODE_MIDIOUT:
800
	case MODE_MIDIOUT | MODE_MIDIIN:
801
	case MODE_REC:
802
	case MODE_PLAY:
803
	case MODE_PLAY | MODE_REC:
804
		break;
805
	default:
806
#ifdef DEBUG
807
		if (log_level >= 1) {
808
			sock_log(f);
809
			log_puts(": ");
810
			log_putx(mode);
811
			log_puts(": unsupported mode\n");
812
		}
813
#endif
814
		return 0;
815
	}
816
	f->pstate = SOCK_INIT;
817
	f->port = NULL;
818
	if (mode & MODE_MIDIMASK) {
819
		f->slot = NULL;
820
		f->midi = midi_new(&sock_midiops, f, mode);
821
		if (f->midi == NULL)
822
			return 0;
823
		/* XXX: add 'devtype' to libsndio */
824
		if (p->devnum < 16) {
825
			d = dev_bynum(p->devnum);
826
			if (d == NULL)
827
				return 0;
828
			midi_tag(f->midi, p->devnum);
829
		} else if (p->devnum < 32) {
830
			midi_tag(f->midi, p->devnum);
831
		} else if (p->devnum < 48) {
832
			c = port_bynum(p->devnum - 32);
833
			if (c == NULL || !port_ref(c))
834
				return 0;
835
			f->port = c;
836
			midi_link(f->midi, c->midi);
837
		} else
838
			return 0;
839
		return 1;
840
	}
841
	f->opt = opt_byname(p->opt, p->devnum);
842
	if (f->opt == NULL)
843
		return 0;
844
#ifdef DEBUG
845
	if (log_level >= 3) {
846
		sock_log(f);
847
		log_puts(": using ");
848
		dev_log(f->opt->dev);
849
		log_puts(".");
850
		log_puts(f->opt->name);
851
		log_puts(", mode = ");
852
		log_putx(mode);
853
		log_puts("\n");
854
	}
855
#endif
856
	if ((mode & MODE_REC) && (f->opt->mode & MODE_MON)) {
857
		mode |= MODE_MON;
858
		mode &= ~MODE_REC;
859
	}
860
	if ((mode & f->opt->mode) != mode) {
861
		if (log_level >= 1) {
862
			sock_log(f);
863
			log_puts(": requested mode not allowed\n");
864
		}
865
		return 0;
866
	}
867
	s = slot_new(f->opt->dev, p->who, &sock_slotops, f, mode);
868
	if (s == NULL)
869
		return 0;
870
	f->midi = NULL;
871
	if (s->mode & MODE_PLAY) {
872
		s->mix.slot_cmin = s->mix.dev_cmin = f->opt->pmin;
873
		s->mix.slot_cmax = s->mix.dev_cmax = f->opt->pmax;
874
	}
875
	if (s->mode & MODE_RECMASK) {
876
		s->sub.slot_cmin = s->sub.dev_cmin = f->opt->rmin;
877
		s->sub.slot_cmax = s->sub.dev_cmax = f->opt->rmax;
878
	}
879
	if (f->opt->mmc) {
880
		s->xrun = XRUN_SYNC;
881
		s->tstate = MMC_STOP;
882
	} else {
883
		s->xrun = XRUN_IGNORE;
884
		s->tstate = MMC_OFF;
885
	}
886
	s->mix.maxweight = f->opt->maxweight;
887
	s->dup = f->opt->dup;
888
	f->slot = s;
889
	return 1;
890
}
891
892
/*
893
 * execute the message in f->rmsg, return 1 on success
894
 */
895
int
896
sock_execmsg(struct sock *f)
897
{
898
	struct slot *s = f->slot;
899
	struct amsg *m = &f->rmsg;
900
	unsigned char *data;
901
	int size, ctl;
902
903
	switch (ntohl(m->cmd)) {
904
	case AMSG_DATA:
905
#ifdef DEBUG
906
		if (log_level >= 4) {
907
			sock_log(f);
908
			log_puts(": DATA message\n");
909
		}
910
#endif
911
		if (s != NULL && f->pstate != SOCK_START) {
912
#ifdef DEBUG
913
			if (log_level >= 1) {
914
				sock_log(f);
915
				log_puts(": DATA, wrong state\n");
916
			}
917
#endif
918
			sock_close(f);
919
			return 0;
920
		}
921
		if ((f->slot && !(f->slot->mode & MODE_PLAY)) ||
922
		    (f->midi && !(f->midi->mode & MODE_MIDIOUT))) {
923
#ifdef DEBUG
924
			if (log_level >= 1) {
925
				sock_log(f);
926
				log_puts(": DATA, input-only mode\n");
927
			}
928
#endif
929
			sock_close(f);
930
			return 0;
931
		}
932
		size = ntohl(m->u.data.size);
933
		if (size <= 0) {
934
#ifdef DEBUG
935
			if (log_level >= 1) {
936
				sock_log(f);
937
				log_puts(": zero size payload\n");
938
			}
939
#endif
940
			sock_close(f);
941
			return 0;
942
		}
943
		if (s != NULL && size % s->mix.bpf != 0) {
944
#ifdef DEBUG
945
			if (log_level >= 1) {
946
				sock_log(f);
947
				log_puts(": not aligned to frame\n");
948
			}
949
#endif
950
			sock_close(f);
951
			return 0;
952
		}
953
		if (s != NULL && size > f->ralign) {
954
#ifdef DEBUG
955
			if (log_level >= 1) {
956
				sock_log(f);
957
				log_puts(": size = ");
958
				log_puti(size);
959
				log_puts(": ralign = ");
960
				log_puti(f->ralign);
961
				log_puts(": not aligned to block\n");
962
			}
963
#endif
964
			sock_close(f);
965
			return 0;
966
		}
967
		f->rstate = SOCK_RDATA;
968
		f->rsize = f->rtodo = size;
969
		if (s != NULL) {
970
			f->ralign -= size;
971
			if (f->ralign == 0)
972
				f->ralign = s->round * s->mix.bpf;
973
		}
974
		if (f->rtodo > f->rmax) {
975
#ifdef DEBUG
976
			if (log_level >= 1) {
977
				sock_log(f);
978
				log_puts(": unexpected data, size = ");
979
				log_putu(size);
980
				log_puts(", rmax = ");
981
				log_putu(f->rmax);
982
				log_puts("\n");
983
			}
984
#endif
985
			sock_close(f);
986
			return 0;
987
		}
988
		f->rmax -= f->rtodo;
989
		if (f->rtodo == 0) {
990
#ifdef DEBUG
991
			if (log_level >= 1) {
992
				sock_log(f);
993
				log_puts(": zero-length data chunk\n");
994
			}
995
#endif
996
			sock_close(f);
997
			return 0;
998
		}
999
		break;
1000
	case AMSG_START:
1001
#ifdef DEBUG
1002
		if (log_level >= 3) {
1003
			sock_log(f);
1004
			log_puts(": START message\n");
1005
		}
1006
#endif
1007
		if (f->pstate != SOCK_INIT || s == NULL) {
1008
#ifdef DEBUG
1009
			if (log_level >= 1) {
1010
				sock_log(f);
1011
				log_puts(": START, wrong state\n");
1012
			}
1013
#endif
1014
			sock_close(f);
1015
			return 0;
1016
		}
1017
		f->tickpending = 0;
1018
		f->stoppending = 0;
1019
		slot_start(s);
1020
		if (s->mode & MODE_PLAY) {
1021
			f->fillpending = s->appbufsz;
1022
			f->ralign = s->round * s->mix.bpf;
1023
			f->rmax = 0;
1024
		}
1025
		if (s->mode & MODE_RECMASK) {
1026
			f->walign = s->round * s->sub.bpf;
1027
			f->wmax = 0;
1028
		}
1029
		f->pstate = SOCK_START;
1030
		f->rstate = SOCK_RMSG;
1031
		f->rtodo = sizeof(struct amsg);
1032
		if (log_level >= 2) {
1033
			slot_log(f->slot);
1034
			log_puts(": ");
1035
			log_putu(s->rate);
1036
			log_puts("Hz, ");
1037
			aparams_log(&s->par);
1038
			if (s->mode & MODE_PLAY) {
1039
				log_puts(", play ");
1040
				log_puti(s->mix.slot_cmin);
1041
				log_puts(":");
1042
				log_puti(s->mix.slot_cmax);
1043
			}
1044
			if (s->mode & MODE_RECMASK) {
1045
				log_puts(", rec ");
1046
				log_puti(s->sub.slot_cmin);
1047
				log_puts(":");
1048
				log_puti(s->sub.slot_cmax);
1049
			}
1050
			log_puts(", ");
1051
			log_putu(s->appbufsz / s->round);
1052
			log_puts(" blocks of ");
1053
			log_putu(s->round);
1054
			log_puts(" frames\n");
1055
		}
1056
		break;
1057
	case AMSG_STOP:
1058
#ifdef DEBUG
1059
		if (log_level >= 3) {
1060
			sock_log(f);
1061
			log_puts(": STOP message\n");
1062
		}
1063
#endif
1064
		if (f->pstate != SOCK_START) {
1065
#ifdef DEBUG
1066
			if (log_level >= 1) {
1067
				sock_log(f);
1068
				log_puts(": STOP, wrong state\n");
1069
			}
1070
#endif
1071
			sock_close(f);
1072
			return 0;
1073
		}
1074
		f->rmax = 0;
1075
		if (!(s->mode & MODE_PLAY))
1076
			f->stoppending = 1;
1077
		f->pstate = SOCK_STOP;
1078
		f->rstate = SOCK_RMSG;
1079
		f->rtodo = sizeof(struct amsg);
1080
		if (s->mode & MODE_PLAY) {
1081
			if (f->ralign < s->round * s->mix.bpf) {
1082
				data = abuf_wgetblk(&s->mix.buf, &size);
1083
#ifdef DEBUG
1084
				if (size < f->ralign) {
1085
					sock_log(f);
1086
					log_puts(": unaligned stop, size = ");
1087
					log_putu(size);
1088
					log_puts(", ralign = ");
1089
					log_putu(f->ralign);
1090
					log_puts("\n");
1091
					panic();
1092
				}
1093
#endif
1094
				memset(data, 0, f->ralign);
1095
				abuf_wcommit(&s->mix.buf, f->ralign);
1096
				f->ralign = s->round * s->mix.bpf;
1097
			}
1098
		}
1099
		slot_stop(s);
1100
		break;
1101
	case AMSG_SETPAR:
1102
#ifdef DEBUG
1103
		if (log_level >= 3) {
1104
			sock_log(f);
1105
			log_puts(": SETPAR message\n");
1106
		}
1107
#endif
1108
		if (f->pstate != SOCK_INIT || s == NULL) {
1109
#ifdef DEBUG
1110
			if (log_level >= 1) {
1111
				sock_log(f);
1112
				log_puts(": SETPAR, wrong state\n");
1113
			}
1114
#endif
1115
			sock_close(f);
1116
			return 0;
1117
		}
1118
		if (!sock_setpar(f)) {
1119
			sock_close(f);
1120
			return 0;
1121
		}
1122
		f->rtodo = sizeof(struct amsg);
1123
		f->rstate = SOCK_RMSG;
1124
		break;
1125
	case AMSG_GETPAR:
1126
#ifdef DEBUG
1127
		if (log_level >= 3) {
1128
			sock_log(f);
1129
			log_puts(": GETPAR message\n");
1130
		}
1131
#endif
1132
		if (f->pstate != SOCK_INIT || s == NULL) {
1133
#ifdef DEBUG
1134
			if (log_level >= 1) {
1135
				sock_log(f);
1136
				log_puts(": GETPAR, wrong state\n");
1137
			}
1138
#endif
1139
			sock_close(f);
1140
			return 0;
1141
		}
1142
		AMSG_INIT(m);
1143
		m->cmd = htonl(AMSG_GETPAR);
1144
		m->u.par.legacy_mode = s->mode;
1145
		m->u.par.xrun = s->xrun;
1146
		m->u.par.bits = s->par.bits;
1147
		m->u.par.bps = s->par.bps;
1148
		m->u.par.sig = s->par.sig;
1149
		m->u.par.le = s->par.le;
1150
		m->u.par.msb = s->par.msb;
1151
		if (s->mode & MODE_PLAY) {
1152
			m->u.par.pchan = htons(s->mix.slot_cmax -
1153
			    s->mix.slot_cmin + 1);
1154
		}
1155
		if (s->mode & MODE_RECMASK) {
1156
			m->u.par.rchan = htons(s->sub.slot_cmax -
1157
			    s->sub.slot_cmin + 1);
1158
		}
1159
		m->u.par.rate = htonl(s->rate);
1160
		m->u.par.appbufsz = htonl(s->appbufsz);
1161
		m->u.par.bufsz = htonl(SLOT_BUFSZ(s));
1162
		m->u.par.round = htonl(s->round);
1163
		f->rstate = SOCK_RRET;
1164
		f->rtodo = sizeof(struct amsg);
1165
		break;
1166
	case AMSG_SETVOL:
1167
#ifdef DEBUG
1168
		if (log_level >= 3) {
1169
			sock_log(f);
1170
			log_puts(": SETVOL message\n");
1171
		}
1172
#endif
1173
		if (f->pstate < SOCK_INIT || s == NULL) {
1174
#ifdef DEBUG
1175
			if (log_level >= 1) {
1176
				sock_log(f);
1177
				log_puts(": SETVOL, wrong state\n");
1178
			}
1179
#endif
1180
			sock_close(f);
1181
			return 0;
1182
		}
1183
		ctl = ntohl(m->u.vol.ctl);
1184
		if (ctl > MIDI_MAXCTL) {
1185
#ifdef DEBUG
1186
			if (log_level >= 1) {
1187
				sock_log(f);
1188
				log_puts(": SETVOL, volume out of range\n");
1189
			}
1190
#endif
1191
			sock_close(f);
1192
			return 0;
1193
		}
1194
		f->rtodo = sizeof(struct amsg);
1195
		f->rstate = SOCK_RMSG;
1196
		f->lastvol = ctl; /* dont trigger feedback message */
1197
		slot_setvol(s, ctl);
1198
		dev_midi_vol(s->dev, s);
1199
		break;
1200
	case AMSG_AUTH:
1201
#ifdef DEBUG
1202
		if (log_level >= 3) {
1203
			sock_log(f);
1204
			log_puts(": AUTH message\n");
1205
		}
1206
#endif
1207
		if (f->pstate != SOCK_AUTH) {
1208
#ifdef DEBUG
1209
			if (log_level >= 1) {
1210
				sock_log(f);
1211
				log_puts(": AUTH, wrong state\n");
1212
			}
1213
#endif
1214
			sock_close(f);
1215
			return 0;
1216
		}
1217
		if (!sock_auth(f)) {
1218
			sock_close(f);
1219
			return 0;
1220
		}
1221
		f->rstate = SOCK_RMSG;
1222
		f->rtodo = sizeof(struct amsg);
1223
		break;
1224
	case AMSG_HELLO:
1225
#ifdef DEBUG
1226
		if (log_level >= 3) {
1227
			sock_log(f);
1228
			log_puts(": HELLO message\n");
1229
		}
1230
#endif
1231
		if (f->pstate != SOCK_HELLO) {
1232
#ifdef DEBUG
1233
			if (log_level >= 1) {
1234
				sock_log(f);
1235
				log_puts(": HELLO, wrong state\n");
1236
			}
1237
#endif
1238
			sock_close(f);
1239
			return 0;
1240
		}
1241
		if (!sock_hello(f)) {
1242
			sock_close(f);
1243
			return 0;
1244
		}
1245
		AMSG_INIT(m);
1246
		m->cmd = htonl(AMSG_ACK);
1247
		f->rstate = SOCK_RRET;
1248
		f->rtodo = sizeof(struct amsg);
1249
		break;
1250
	case AMSG_BYE:
1251
#ifdef DEBUG
1252
		if (log_level >= 3) {
1253
			sock_log(f);
1254
			log_puts(": BYE message\n");
1255
		}
1256
#endif
1257
		if (s != NULL && f->pstate != SOCK_INIT) {
1258
#ifdef DEBUG
1259
			if (log_level >= 1) {
1260
				sock_log(f);
1261
				log_puts(": BYE, wrong state\n");
1262
			}
1263
#endif
1264
		}
1265
		sock_close(f);
1266
		return 0;
1267
	default:
1268
#ifdef DEBUG
1269
		if (log_level >= 1) {
1270
			sock_log(f);
1271
			log_puts(": unknown command in message\n");
1272
		}
1273
#endif
1274
		sock_close(f);
1275
		return 0;
1276
	}
1277
	return 1;
1278
}
1279
1280
/*
1281
 * build a message in f->wmsg, return 1 on success and 0 if
1282
 * there's nothing to do. Assume f->wstate is SOCK_WIDLE
1283
 */
1284
int
1285
sock_buildmsg(struct sock *f)
1286
{
1287
	unsigned int size;
1288
1289
	/*
1290
	 * If pos changed (or initial tick), build a MOVE message.
1291
	 */
1292
	if (f->tickpending) {
1293
#ifdef DEBUG
1294
		if (log_level >= 4) {
1295
			sock_log(f);
1296
			log_puts(": building MOVE message, delta = ");
1297
			log_puti(f->slot->delta);
1298
			log_puts("\n");
1299
		}
1300
#endif
1301
		AMSG_INIT(&f->wmsg);
1302
		f->wmsg.cmd = htonl(AMSG_MOVE);
1303
		f->wmsg.u.ts.delta = htonl(f->slot->delta);
1304
		f->wtodo = sizeof(struct amsg);
1305
		f->wstate = SOCK_WMSG;
1306
		f->tickpending = 0;
1307
		/*
1308
		 * XXX: use tickpending as accumulator rather than
1309
		 * slot->delta
1310
		 */
1311
		f->slot->delta = 0;
1312
		return 1;
1313
	}
1314
1315
	if (f->fillpending > 0) {
1316
		AMSG_INIT(&f->wmsg);
1317
		f->wmsg.cmd = htonl(AMSG_FLOWCTL);
1318
		f->wmsg.u.ts.delta = htonl(f->fillpending);
1319
		size = f->fillpending;
1320
		if (f->slot)
1321
			size *= f->slot->mix.bpf;
1322
		f->rmax += size;
1323
#ifdef DEBUG
1324
		if (log_level >= 4) {
1325
			sock_log(f);
1326
			log_puts(": building FLOWCTL message, count = ");
1327
			log_puti(f->fillpending);
1328
			log_puts(", rmax -> ");
1329
			log_puti(f->rmax);
1330
			log_puts("\n");
1331
		}
1332
#endif
1333
		f->wtodo = sizeof(struct amsg);
1334
		f->wstate = SOCK_WMSG;
1335
		f->fillpending = 0;
1336
		return 1;
1337
	}
1338
1339
	/*
1340
	 * if volume changed build a SETVOL message
1341
	 */
1342
	if (f->pstate >= SOCK_START && f->slot->vol != f->lastvol) {
1343
#ifdef DEBUG
1344
		if (log_level >= 3) {
1345
			sock_log(f);
1346
			log_puts(": building SETVOL message, vol = ");
1347
			log_puti(f->slot->vol);
1348
			log_puts("\n");
1349
		}
1350
#endif
1351
		AMSG_INIT(&f->wmsg);
1352
		f->wmsg.cmd = htonl(AMSG_SETVOL);
1353
		f->wmsg.u.vol.ctl = htonl(f->slot->vol);
1354
		f->wtodo = sizeof(struct amsg);
1355
		f->wstate = SOCK_WMSG;
1356
		f->lastvol = f->slot->vol;
1357
		return 1;
1358
	}
1359
1360
	if (f->midi != NULL && f->midi->obuf.used > 0) {
1361
		size = f->midi->obuf.used;
1362
		if (size > AMSG_DATAMAX)
1363
			size = AMSG_DATAMAX;
1364
		AMSG_INIT(&f->wmsg);
1365
		f->wmsg.cmd = htonl(AMSG_DATA);
1366
		f->wmsg.u.data.size = htonl(size);
1367
		f->wtodo = sizeof(struct amsg);
1368
		f->wstate = SOCK_WMSG;
1369
		return 1;
1370
	}
1371
1372
	/*
1373
	 * If data available, build a DATA message.
1374
	 */
1375
	if (f->slot != NULL && f->wmax > 0 && f->slot->sub.buf.used > 0) {
1376
		size = f->slot->sub.buf.used;
1377
		if (size > AMSG_DATAMAX)
1378
			size = AMSG_DATAMAX;
1379
		if (size > f->walign)
1380
			size = f->walign;
1381
		if (size > f->wmax)
1382
			size = f->wmax;
1383
		size -= size % f->slot->sub.bpf;
1384
#ifdef DEBUG
1385
		if (size == 0) {
1386
			sock_log(f);
1387
			log_puts(": sock_buildmsg size == 0\n");
1388
			panic();
1389
		}
1390
#endif
1391
		f->walign -= size;
1392
		f->wmax -= size;
1393
		if (f->walign == 0)
1394
			f->walign = f->slot->round * f->slot->sub.bpf;
1395
#ifdef DEBUG
1396
		if (log_level >= 4) {
1397
			sock_log(f);
1398
			log_puts(": building audio DATA message, size = ");
1399
			log_puti(size);
1400
			log_puts("\n");
1401
		}
1402
#endif
1403
		AMSG_INIT(&f->wmsg);
1404
		f->wmsg.cmd = htonl(AMSG_DATA);
1405
		f->wmsg.u.data.size = htonl(size);
1406
		f->wtodo = sizeof(struct amsg);
1407
		f->wstate = SOCK_WMSG;
1408
		return 1;
1409
	}
1410
1411
	if (f->stoppending) {
1412
#ifdef DEBUG
1413
		if (log_level >= 3) {
1414
			sock_log(f);
1415
			log_puts(": building STOP message\n");
1416
		}
1417
#endif
1418
		f->stoppending = 0;
1419
		f->pstate = SOCK_INIT;
1420
		AMSG_INIT(&f->wmsg);
1421
		f->wmsg.cmd = htonl(AMSG_STOP);
1422
		f->wtodo = sizeof(struct amsg);
1423
		f->wstate = SOCK_WMSG;
1424
		return 1;
1425
	}
1426
#ifdef DEBUG
1427
	if (log_level >= 4) {
1428
		sock_log(f);
1429
		log_puts(": no messages to build anymore, idling...\n");
1430
	}
1431
#endif
1432
	f->wstate = SOCK_WIDLE;
1433
	return 0;
1434
}
1435
1436
/*
1437
 * iteration of the socket reader loop, return 1 on success
1438
 */
1439
int
1440
sock_read(struct sock *f)
1441
{
1442
#ifdef DEBUG
1443
	if (log_level >= 4) {
1444
		sock_log(f);
1445
		log_puts(": reading ");
1446
		log_putu(f->rtodo);
1447
		log_puts(" todo\n");
1448
	}
1449
#endif
1450
	switch (f->rstate) {
1451
	case SOCK_RIDLE:
1452
		return 0;
1453
	case SOCK_RMSG:
1454
		if (!sock_rmsg(f))
1455
			return 0;
1456
		if (!sock_execmsg(f))
1457
			return 0;
1458
		break;
1459
	case SOCK_RDATA:
1460
		if (!sock_rdata(f))
1461
			return 0;
1462
		f->rstate = SOCK_RMSG;
1463
		f->rtodo = sizeof(struct amsg);
1464
		break;
1465
	case SOCK_RRET:
1466
		if (f->wstate != SOCK_WIDLE) {
1467
#ifdef DEBUG
1468
			if (log_level >= 4) {
1469
				sock_log(f);
1470
				log_puts(": can't reply, write-end blocked\n");
1471
			}
1472
#endif
1473
			return 0;
1474
		}
1475
		f->wmsg = f->rmsg;
1476
		f->wstate = SOCK_WMSG;
1477
		f->wtodo = sizeof(struct amsg);
1478
		f->rstate = SOCK_RMSG;
1479
		f->rtodo = sizeof(struct amsg);
1480
#ifdef DEBUG
1481
		if (log_level >= 4) {
1482
			sock_log(f);
1483
			log_puts(": copied RRET message\n");
1484
		}
1485
#endif
1486
	}
1487
	return 1;
1488
}
1489
1490
/*
1491
 * iteration of the socket writer loop, return 1 on success
1492
 */
1493
int
1494
sock_write(struct sock *f)
1495
{
1496
#ifdef DEBUG
1497
	if (log_level >= 4) {
1498
		sock_log(f);
1499
		log_puts(": writing");
1500
		if (f->wstate != SOCK_WIDLE) {
1501
			log_puts(" todo = ");
1502
			log_putu(f->wtodo);
1503
		}
1504
		log_puts("\n");
1505
	}
1506
#endif
1507
	switch (f->wstate) {
1508
	case SOCK_WMSG:
1509
		if (!sock_wmsg(f))
1510
			return 0;
1511
		if (ntohl(f->wmsg.cmd) != AMSG_DATA) {
1512
			f->wstate = SOCK_WIDLE;
1513
			f->wtodo = 0xdeadbeef;
1514
			break;
1515
		}
1516
		f->wstate = SOCK_WDATA;
1517
		f->wsize = f->wtodo = ntohl(f->wmsg.u.data.size);
1518
		/* PASSTHROUGH */
1519
	case SOCK_WDATA:
1520
		if (!sock_wdata(f))
1521
			return 0;
1522
		if (f->wtodo > 0)
1523
			break;
1524
		f->wstate = SOCK_WIDLE;
1525
		f->wtodo = 0xdeadbeef;
1526
		if (f->pstate == SOCK_STOP) {
1527
			f->pstate = SOCK_INIT;
1528
			f->wmax = 0;
1529
#ifdef DEBUG
1530
			if (log_level >= 4) {
1531
				sock_log(f);
1532
				log_puts(": drained, moved to INIT state\n");
1533
			}
1534
#endif
1535
		}
1536
		/* PASSTHROUGH */
1537
	case SOCK_WIDLE:
1538
		if (f->rstate == SOCK_RRET) {
1539
			f->wmsg = f->rmsg;
1540
			f->wstate = SOCK_WMSG;
1541
			f->wtodo = sizeof(struct amsg);
1542
			f->rstate = SOCK_RMSG;
1543
			f->rtodo = sizeof(struct amsg);
1544
#ifdef DEBUG
1545
			if (log_level >= 4) {
1546
				sock_log(f);
1547
				log_puts(": copied RRET message\n");
1548
			}
1549
#endif
1550
		} else {
1551
			if (!sock_buildmsg(f))
1552
				return 0;
1553
		}
1554
		break;
1555
#ifdef DEBUG
1556
	default:
1557
		sock_log(f);
1558
		log_puts(": bad writing end state\n");
1559
		panic();
1560
#endif
1561
	}
1562
	return 1;
1563
}
1564
1565
int
1566
sock_pollfd(void *arg, struct pollfd *pfd)
1567
{
1568
	struct sock *f = arg;
1569
	int events = 0;
1570
1571
	/*
1572
	 * feedback counters, clock ticks and alike may have changed,
1573
	 * prepare a message to trigger writes
1574
	 *
1575
	 * XXX: doing this at the beginning of the cycle is not optimal,
1576
	 * because state is changed at the end of the read cycle, and
1577
	 * thus counters, ret message and alike are generated then.
1578
	 */
1579
	if (f->wstate == SOCK_WIDLE && f->rstate != SOCK_RRET)
1580
		sock_buildmsg(f);
1581
1582
	if (f->rstate == SOCK_RMSG ||
1583
	    f->rstate == SOCK_RDATA)
1584
		events |= POLLIN;
1585
	if (f->rstate == SOCK_RRET ||
1586
	    f->wstate == SOCK_WMSG ||
1587
	    f->wstate == SOCK_WDATA)
1588
		events |= POLLOUT;
1589
	pfd->fd = f->fd;
1590
	pfd->events = events;
1591
	return 1;
1592
}
1593
1594
int
1595
sock_revents(void *arg, struct pollfd *pfd)
1596
{
1597
	return pfd->revents;
1598
}
1599
1600
void
1601
sock_in(void *arg)
1602
{
1603
	struct sock *f = arg;
1604
1605
	while (sock_read(f))
1606
		;
1607
}
1608
1609
void
1610
sock_out(void *arg)
1611
{
1612
	struct sock *f = arg;
1613
1614
	while (sock_write(f))
1615
		;
1616
}
1617
1618
void
1619
sock_hup(void *arg)
1620
{
1621
	struct sock *f = arg;
1622
1623
	sock_close(f);
1624
}