• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  ALSA server
3  *  Copyright (c) by Abramo Bagnara <abramo@alsa-project.org>
4  *
5  *   This program is free software; you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation; either version 2 of the License, or
8  *   (at your option) any later version.
9  *
10  *   This program is distributed in the hope that it will be useful,
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *   GNU General Public License for more details.
14  *
15  *   You should have received a copy of the GNU General Public License
16  *   along with this program; if not, write to the Free Software
17  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18  *
19  */
20 
21 #include <sys/shm.h>
22 #include <sys/socket.h>
23 #include <poll.h>
24 #include <sys/un.h>
25 #include <sys/uio.h>
26 #include <stdio.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include <stddef.h>
30 #include <getopt.h>
31 #include <netinet/in.h>
32 #include <netdb.h>
33 #include <limits.h>
34 #include <signal.h>
35 
36 #include "aserver.h"
37 
38 char *command;
39 
40 #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
41 #define ERROR(...) do {\
42 	fprintf(stderr, "%s %s:%i:(%s) ", command, __FILE__, __LINE__, __func__); \
43 	fprintf(stderr, __VA_ARGS__); \
44 	putc('\n', stderr); \
45 } while (0)
46 #else
47 #define ERROR(args...) do {\
48 	fprintf(stderr, "%s %s:%i:(%s) ", command, __FILE__, __LINE__, __func__); \
49 	fprintf(stderr, ##args); \
50 	putc('\n', stderr); \
51 } while (0)
52 #endif
53 
54 #define SYSERROR(string) ERROR(string ": %s", strerror(errno))
55 
make_local_socket(const char * filename)56 static int make_local_socket(const char *filename)
57 {
58 	size_t l = strlen(filename);
59 	size_t size = offsetof(struct sockaddr_un, sun_path) + l;
60 	struct sockaddr_un *addr = alloca(size);
61 	int sock;
62 
63 	sock = socket(PF_LOCAL, SOCK_STREAM, 0);
64 	if (sock < 0) {
65 		int result = -errno;
66 		SYSERROR("socket failed");
67 		return result;
68 	}
69 
70 	unlink(filename);
71 
72 	addr->sun_family = AF_LOCAL;
73 	memcpy(addr->sun_path, filename, l);
74 
75 	if (bind(sock, (struct sockaddr *) addr, size) < 0) {
76 		int result = -errno;
77 		SYSERROR("bind failed");
78 		close(sock);
79 		return result;
80 	}
81 
82 	return sock;
83 }
84 
make_inet_socket(int port)85 static int make_inet_socket(int port)
86 {
87 	struct sockaddr_in addr;
88 	int sock;
89 
90 	sock = socket(PF_INET, SOCK_STREAM, 0);
91 	if (sock < 0) {
92 		int result = -errno;
93 		SYSERROR("socket failed");
94 		return result;
95 	}
96 
97 	memset(&addr, 0, sizeof(addr));
98 	addr.sin_family = AF_INET;
99 	addr.sin_port = htons(port);
100 	addr.sin_addr.s_addr = INADDR_ANY;
101 
102 	if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
103 		int result = -errno;
104 		SYSERROR("bind failed");
105 		close(sock);
106 		return result;
107 	}
108 
109 	return sock;
110 }
111 
112 struct pollfd *pollfds;
113 unsigned int pollfds_count = 0;
114 typedef struct waiter waiter_t;
115 typedef int (*waiter_handler_t)(waiter_t *waiter, unsigned short events);
116 struct waiter {
117 	int fd;
118 	void *private_data;
119 	waiter_handler_t handler;
120 };
121 waiter_t *waiters;
122 
add_waiter(int fd,unsigned short events,waiter_handler_t handler,void * data)123 static void add_waiter(int fd, unsigned short events, waiter_handler_t handler,
124 		void *data)
125 {
126 	waiter_t *w = &waiters[fd];
127 	struct pollfd *pfd = &pollfds[pollfds_count];
128 	assert(!w->handler);
129 	pfd->fd = fd;
130 	pfd->events = events;
131 	pfd->revents = 0;
132 	w->fd = fd;
133 	w->private_data = data;
134 	w->handler = handler;
135 	pollfds_count++;
136 }
137 
del_waiter(int fd)138 static void del_waiter(int fd)
139 {
140 	waiter_t *w = &waiters[fd];
141 	unsigned int k;
142 	assert(w->handler);
143 	w->handler = 0;
144 	for (k = 0; k < pollfds_count; ++k) {
145 		if (pollfds[k].fd == fd)
146 			break;
147 	}
148 	assert(k < pollfds_count);
149 	pollfds_count--;
150 	memmove(&pollfds[k], &pollfds[k + 1], pollfds_count - k);
151 }
152 
153 typedef struct client client_t;
154 
155 typedef struct {
156 	int (*open)(client_t *client, int *cookie);
157 	int (*cmd)(client_t *client);
158 	int (*close)(client_t *client);
159 } transport_ops_t;
160 
161 struct client {
162 	struct list_head list;
163 	int poll_fd;
164 	int ctrl_fd;
165 	int local;
166 	int transport_type;
167 	int dev_type;
168 	char name[256];
169 	int stream;
170 	int mode;
171 	transport_ops_t *ops;
172 	snd_async_handler_t *async_handler;
173 	int async_sig;
174 	pid_t async_pid;
175 	union {
176 		struct {
177 			snd_pcm_t *handle;
178 			int fd;
179 		} pcm;
180 		struct {
181 			snd_ctl_t *handle;
182 			int fd;
183 		} ctl;
184 #if 0
185 		struct {
186 			snd_rawmidi_t *handle;
187 		} rawmidi;
188 		struct {
189 			snd_timer_open_t *handle;
190 		} timer;
191 		struct {
192 			snd_hwdep_t *handle;
193 		} hwdep;
194 		struct {
195 			snd_seq_t *handle;
196 		} seq;
197 #endif
198 	} device;
199 	int polling;
200 	int open;
201 	int cookie;
202 	union {
203 		struct {
204 			int ctrl_id;
205 			void *ctrl;
206 		} shm;
207 	} transport;
208 };
209 
210 LIST_HEAD(clients);
211 
212 typedef struct {
213 	struct list_head list;
214 	int fd;
215 	uint32_t cookie;
216 } inet_pending_t;
217 LIST_HEAD(inet_pendings);
218 
219 #if 0
220 static int pcm_handler(waiter_t *waiter, unsigned short events)
221 {
222 	client_t *client = waiter->private_data;
223 	char buf[1];
224 	ssize_t n;
225 	if (events & POLLIN) {
226 		n = write(client->poll_fd, buf, 1);
227 		if (n != 1) {
228 			SYSERROR("write failed");
229 			return -errno;
230 		}
231 	} else if (events & POLLOUT) {
232 		n = read(client->poll_fd, buf, 1);
233 		if (n != 1) {
234 			SYSERROR("read failed");
235 			return -errno;
236 		}
237 	}
238 	del_waiter(waiter->fd);
239 	client->polling = 0;
240 	return 0;
241 }
242 #endif
243 
pcm_shm_hw_ptr_changed(snd_pcm_t * pcm,snd_pcm_t * src ATTRIBUTE_UNUSED)244 static void pcm_shm_hw_ptr_changed(snd_pcm_t *pcm, snd_pcm_t *src ATTRIBUTE_UNUSED)
245 {
246 	client_t *client = pcm->hw.private_data;
247 	volatile snd_pcm_shm_ctrl_t *ctrl = client->transport.shm.ctrl;
248 	snd_pcm_t *loop;
249 
250 	ctrl->hw.changed = 1;
251 	if (pcm->hw.fd >= 0) {
252 		ctrl->hw.use_mmap = 1;
253 		ctrl->hw.offset = pcm->hw.offset;
254 		return;
255 	}
256 	ctrl->hw.use_mmap = 0;
257 	ctrl->hw.ptr = pcm->hw.ptr ? *pcm->hw.ptr : 0;
258 	for (loop = pcm->hw.master; loop; loop = loop->hw.master)
259 		loop->hw.ptr = &ctrl->hw.ptr;
260 	pcm->hw.ptr = &ctrl->hw.ptr;
261 }
262 
pcm_shm_appl_ptr_changed(snd_pcm_t * pcm,snd_pcm_t * src ATTRIBUTE_UNUSED)263 static void pcm_shm_appl_ptr_changed(snd_pcm_t *pcm, snd_pcm_t *src ATTRIBUTE_UNUSED)
264 {
265 	client_t *client = pcm->appl.private_data;
266 	volatile snd_pcm_shm_ctrl_t *ctrl = client->transport.shm.ctrl;
267 	snd_pcm_t *loop;
268 
269 	ctrl->appl.changed = 1;
270 	if (pcm->appl.fd >= 0) {
271 		ctrl->appl.use_mmap = 1;
272 		ctrl->appl.offset = pcm->appl.offset;
273 		return;
274 	}
275 	ctrl->appl.use_mmap = 0;
276 	ctrl->appl.ptr = pcm->appl.ptr ? *pcm->appl.ptr : 0;
277 	for (loop = pcm->appl.master; loop; loop = loop->appl.master)
278 		loop->appl.ptr = &ctrl->appl.ptr;
279 	pcm->appl.ptr = &ctrl->appl.ptr;
280 }
281 
pcm_shm_open(client_t * client,int * cookie)282 static int pcm_shm_open(client_t *client, int *cookie)
283 {
284 	int shmid;
285 	snd_pcm_t *pcm;
286 	int err;
287 	int result;
288 	err = snd_pcm_open(&pcm, client->name, client->stream, SND_PCM_NONBLOCK);
289 	if (err < 0)
290 		return err;
291 	client->device.pcm.handle = pcm;
292 	client->device.pcm.fd = _snd_pcm_poll_descriptor(pcm);
293 	pcm->hw.private_data = client;
294 	pcm->hw.changed = pcm_shm_hw_ptr_changed;
295 	pcm->appl.private_data = client;
296 	pcm->appl.changed = pcm_shm_appl_ptr_changed;
297 
298 	shmid = shmget(IPC_PRIVATE, PCM_SHM_SIZE, 0666);
299 	if (shmid < 0) {
300 		result = -errno;
301 		SYSERROR("shmget failed");
302 		goto _err;
303 	}
304 	client->transport.shm.ctrl_id = shmid;
305 	client->transport.shm.ctrl = shmat(shmid, 0, 0);
306 	if (client->transport.shm.ctrl == (void*) -1) {
307 		result = -errno;
308 		shmctl(shmid, IPC_RMID, 0);
309 		SYSERROR("shmat failed");
310 		goto _err;
311 	}
312 	*cookie = shmid;
313 	return 0;
314 
315  _err:
316 	snd_pcm_close(pcm);
317 	return result;
318 
319 }
320 
pcm_shm_close(client_t * client)321 static int pcm_shm_close(client_t *client)
322 {
323 	int err;
324 	snd_pcm_shm_ctrl_t *ctrl = client->transport.shm.ctrl;
325 	if (client->polling) {
326 		del_waiter(client->device.pcm.fd);
327 		client->polling = 0;
328 	}
329 	err = snd_pcm_close(client->device.pcm.handle);
330 	ctrl->result = err;
331 	if (err < 0)
332 		ERROR("snd_pcm_close");
333 	if (client->transport.shm.ctrl) {
334 		err = shmdt((void *)client->transport.shm.ctrl);
335 		if (err < 0)
336 			SYSERROR("shmdt failed");
337 		err = shmctl(client->transport.shm.ctrl_id, IPC_RMID, 0);
338 		if (err < 0)
339 			SYSERROR("shmctl IPC_RMID failed");
340 		client->transport.shm.ctrl = 0;
341 	}
342 	client->open = 0;
343 	return 0;
344 }
345 
shm_ack(client_t * client)346 static int shm_ack(client_t *client)
347 {
348 	struct pollfd pfd;
349 	int err;
350 	char buf[1];
351 	pfd.fd = client->ctrl_fd;
352 	pfd.events = POLLHUP;
353 	if (poll(&pfd, 1, 0) == 1)
354 		return -EBADFD;
355 	err = write(client->ctrl_fd, buf, 1);
356 	if (err != 1)
357 		return -EBADFD;
358 	return 0;
359 }
360 
shm_ack_fd(client_t * client,int fd)361 static int shm_ack_fd(client_t *client, int fd)
362 {
363 	struct pollfd pfd;
364 	int err;
365 	char buf[1];
366 	pfd.fd = client->ctrl_fd;
367 	pfd.events = POLLHUP;
368 	if (poll(&pfd, 1, 0) == 1)
369 		return -EBADFD;
370 	err = snd_send_fd(client->ctrl_fd, buf, 1, fd);
371 	if (err != 1)
372 		return -EBADFD;
373 	return 0;
374 }
375 
shm_rbptr_fd(client_t * client,snd_pcm_rbptr_t * rbptr)376 static int shm_rbptr_fd(client_t *client, snd_pcm_rbptr_t *rbptr)
377 {
378 	if (rbptr->fd < 0)
379 		return -EINVAL;
380 	return shm_ack_fd(client, rbptr->fd);
381 }
382 
async_handler(snd_async_handler_t * handler)383 static void async_handler(snd_async_handler_t *handler)
384 {
385 	client_t *client = snd_async_handler_get_callback_private(handler);
386 	/* FIXME: use sigqueue */
387 	kill(client->async_pid, client->async_sig);
388 }
389 
pcm_shm_cmd(client_t * client)390 static int pcm_shm_cmd(client_t *client)
391 {
392 	volatile snd_pcm_shm_ctrl_t *ctrl = client->transport.shm.ctrl;
393 	char buf[1];
394 	int err;
395 	int cmd;
396 	snd_pcm_t *pcm;
397 	err = read(client->ctrl_fd, buf, 1);
398 	if (err != 1)
399 		return -EBADFD;
400 	cmd = ctrl->cmd;
401 	ctrl->cmd = 0;
402 	pcm = client->device.pcm.handle;
403 	switch (cmd) {
404 	case SND_PCM_IOCTL_ASYNC:
405 		ctrl->result = snd_pcm_async(pcm, ctrl->u.async.sig, ctrl->u.async.pid);
406 		if (ctrl->result < 0)
407 			break;
408 		if (ctrl->u.async.sig >= 0) {
409 			assert(client->async_sig < 0);
410 			ctrl->result = snd_async_add_pcm_handler(&client->async_handler, pcm, async_handler, client);
411 			if (ctrl->result < 0)
412 				break;
413 		} else {
414 			assert(client->async_sig >= 0);
415 			snd_async_del_handler(client->async_handler);
416 		}
417 		client->async_sig = ctrl->u.async.sig;
418 		client->async_pid = ctrl->u.async.pid;
419 		break;
420 	case SNDRV_PCM_IOCTL_INFO:
421 		ctrl->result = snd_pcm_info(pcm, (snd_pcm_info_t *) &ctrl->u.info);
422 		break;
423 	case SNDRV_PCM_IOCTL_HW_REFINE:
424 		ctrl->result = snd_pcm_hw_refine(pcm, (snd_pcm_hw_params_t *) &ctrl->u.hw_refine);
425 		break;
426 	case SNDRV_PCM_IOCTL_HW_PARAMS:
427 		ctrl->result = snd_pcm_hw_params(pcm, (snd_pcm_hw_params_t *) &ctrl->u.hw_params);
428 		break;
429 	case SNDRV_PCM_IOCTL_HW_FREE:
430 		ctrl->result = snd_pcm_hw_free(pcm);
431 		break;
432 	case SNDRV_PCM_IOCTL_SW_PARAMS:
433 		ctrl->result = snd_pcm_sw_params(pcm, (snd_pcm_sw_params_t *) &ctrl->u.sw_params);
434 		break;
435 	case SNDRV_PCM_IOCTL_STATUS:
436 		ctrl->result = snd_pcm_status(pcm, (snd_pcm_status_t *) &ctrl->u.status);
437 		break;
438 	case SND_PCM_IOCTL_STATE:
439 		ctrl->result = snd_pcm_state(pcm);
440 		break;
441 	case SND_PCM_IOCTL_HWSYNC:
442 		ctrl->result = snd_pcm_hwsync(pcm);
443 		break;
444 	case SNDRV_PCM_IOCTL_DELAY:
445 		ctrl->result = snd_pcm_delay(pcm, (snd_pcm_sframes_t *) &ctrl->u.delay.frames);
446 		break;
447 	case SND_PCM_IOCTL_AVAIL_UPDATE:
448 		ctrl->result = snd_pcm_avail_update(pcm);
449 		break;
450 	case SNDRV_PCM_IOCTL_PREPARE:
451 		ctrl->result = snd_pcm_prepare(pcm);
452 		break;
453 	case SNDRV_PCM_IOCTL_RESET:
454 		ctrl->result = snd_pcm_reset(pcm);
455 		break;
456 	case SNDRV_PCM_IOCTL_START:
457 		ctrl->result = snd_pcm_start(pcm);
458 		break;
459 	case SNDRV_PCM_IOCTL_DRAIN:
460 		ctrl->result = snd_pcm_drain(pcm);
461 		break;
462 	case SNDRV_PCM_IOCTL_DROP:
463 		ctrl->result = snd_pcm_drop(pcm);
464 		break;
465 	case SNDRV_PCM_IOCTL_PAUSE:
466 		ctrl->result = snd_pcm_pause(pcm, ctrl->u.pause.enable);
467 		break;
468 	case SNDRV_PCM_IOCTL_CHANNEL_INFO:
469 		ctrl->result = snd_pcm_channel_info(pcm, (snd_pcm_channel_info_t *) &ctrl->u.channel_info);
470 		if (ctrl->result >= 0 &&
471 		    ctrl->u.channel_info.type == SND_PCM_AREA_MMAP)
472 			return shm_ack_fd(client, ctrl->u.channel_info.u.mmap.fd);
473 		break;
474 	case SNDRV_PCM_IOCTL_REWIND:
475 		ctrl->result = snd_pcm_rewind(pcm, ctrl->u.rewind.frames);
476 		break;
477 	case SND_PCM_IOCTL_FORWARD:
478 		ctrl->result = snd_pcm_forward(pcm, ctrl->u.forward.frames);
479 		break;
480 	case SNDRV_PCM_IOCTL_LINK:
481 	{
482 		/* FIXME */
483 		ctrl->result = -ENOSYS;
484 		break;
485 	}
486 	case SNDRV_PCM_IOCTL_UNLINK:
487 		ctrl->result = snd_pcm_unlink(pcm);
488 		break;
489 	case SNDRV_PCM_IOCTL_RESUME:
490 		ctrl->result = snd_pcm_resume(pcm);
491 		break;
492 	case SND_PCM_IOCTL_MMAP:
493 	{
494 		ctrl->result = snd_pcm_mmap(pcm);
495 		break;
496 	}
497 	case SND_PCM_IOCTL_MUNMAP:
498 	{
499 		ctrl->result = snd_pcm_munmap(pcm);
500 		break;
501 	}
502 	case SND_PCM_IOCTL_MMAP_COMMIT:
503 		ctrl->result = snd_pcm_mmap_commit(pcm,
504 						   ctrl->u.mmap_commit.offset,
505 						   ctrl->u.mmap_commit.frames);
506 		break;
507 	case SND_PCM_IOCTL_POLL_DESCRIPTOR:
508 		ctrl->result = 0;
509 		return shm_ack_fd(client, _snd_pcm_poll_descriptor(pcm));
510 	case SND_PCM_IOCTL_CLOSE:
511 		client->ops->close(client);
512 		break;
513 	case SND_PCM_IOCTL_HW_PTR_FD:
514 		return shm_rbptr_fd(client, &pcm->hw);
515 	case SND_PCM_IOCTL_APPL_PTR_FD:
516 		return shm_rbptr_fd(client, &pcm->appl);
517 	default:
518 		ERROR("Bogus cmd: %x", ctrl->cmd);
519 		ctrl->result = -ENOSYS;
520 	}
521 	return shm_ack(client);
522 }
523 
524 transport_ops_t pcm_shm_ops = {
525 	.open	= pcm_shm_open,
526 	.cmd	= pcm_shm_cmd,
527 	.close	= pcm_shm_close,
528 };
529 
ctl_handler(waiter_t * waiter,unsigned short events)530 static int ctl_handler(waiter_t *waiter, unsigned short events)
531 {
532 	client_t *client = waiter->private_data;
533 	char buf[1];
534 	ssize_t n;
535 	if (events & POLLIN) {
536 		n = write(client->poll_fd, buf, 1);
537 		if (n != 1) {
538 			SYSERROR("write failed");
539 			return -errno;
540 		}
541 	}
542 	del_waiter(waiter->fd);
543 	client->polling = 0;
544 	return 0;
545 }
546 
ctl_shm_open(client_t * client,int * cookie)547 static int ctl_shm_open(client_t *client, int *cookie)
548 {
549 	int shmid;
550 	snd_ctl_t *ctl;
551 	int err;
552 	int result;
553 	err = snd_ctl_open(&ctl, client->name, SND_CTL_NONBLOCK);
554 	if (err < 0)
555 		return err;
556 	client->device.ctl.handle = ctl;
557 	client->device.ctl.fd = _snd_ctl_poll_descriptor(ctl);
558 
559 	shmid = shmget(IPC_PRIVATE, CTL_SHM_SIZE, 0666);
560 	if (shmid < 0) {
561 		result = -errno;
562 		SYSERROR("shmget failed");
563 		goto _err;
564 	}
565 	client->transport.shm.ctrl_id = shmid;
566 	client->transport.shm.ctrl = shmat(shmid, 0, 0);
567 	if (!client->transport.shm.ctrl) {
568 		result = -errno;
569 		shmctl(shmid, IPC_RMID, 0);
570 		SYSERROR("shmat failed");
571 		goto _err;
572 	}
573 	*cookie = shmid;
574 	add_waiter(client->device.ctl.fd, POLLIN, ctl_handler, client);
575 	client->polling = 1;
576 	return 0;
577 
578  _err:
579 	snd_ctl_close(ctl);
580 	return result;
581 
582 }
583 
ctl_shm_close(client_t * client)584 static int ctl_shm_close(client_t *client)
585 {
586 	int err;
587 	snd_ctl_shm_ctrl_t *ctrl = client->transport.shm.ctrl;
588 	if (client->polling) {
589 		del_waiter(client->device.ctl.fd);
590 		client->polling = 0;
591 	}
592 	err = snd_ctl_close(client->device.ctl.handle);
593 	ctrl->result = err;
594 	if (err < 0)
595 		ERROR("snd_ctl_close");
596 	if (client->transport.shm.ctrl) {
597 		err = shmdt((void *)client->transport.shm.ctrl);
598 		if (err < 0)
599 			SYSERROR("shmdt failed");
600 		err = shmctl(client->transport.shm.ctrl_id, IPC_RMID, 0);
601 		if (err < 0)
602 			SYSERROR("shmctl failed");
603 		client->transport.shm.ctrl = 0;
604 	}
605 	client->open = 0;
606 	return 0;
607 }
608 
ctl_shm_cmd(client_t * client)609 static int ctl_shm_cmd(client_t *client)
610 {
611 	snd_ctl_shm_ctrl_t *ctrl = client->transport.shm.ctrl;
612 	char buf[1];
613 	int err;
614 	int cmd;
615 	snd_ctl_t *ctl;
616 	err = read(client->ctrl_fd, buf, 1);
617 	if (err != 1)
618 		return -EBADFD;
619 	cmd = ctrl->cmd;
620 	ctrl->cmd = 0;
621 	ctl = client->device.ctl.handle;
622 	switch (cmd) {
623 	case SND_CTL_IOCTL_ASYNC:
624 		ctrl->result = snd_ctl_async(ctl, ctrl->u.async.sig, ctrl->u.async.pid);
625 		if (ctrl->result < 0)
626 			break;
627 		if (ctrl->u.async.sig >= 0) {
628 			assert(client->async_sig < 0);
629 			ctrl->result = snd_async_add_ctl_handler(&client->async_handler, ctl, async_handler, client);
630 			if (ctrl->result < 0)
631 				break;
632 		} else {
633 			assert(client->async_sig >= 0);
634 			snd_async_del_handler(client->async_handler);
635 		}
636 		client->async_sig = ctrl->u.async.sig;
637 		client->async_pid = ctrl->u.async.pid;
638 		break;
639 		break;
640 	case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS:
641 		ctrl->result = snd_ctl_subscribe_events(ctl, ctrl->u.subscribe_events);
642 		break;
643 	case SNDRV_CTL_IOCTL_CARD_INFO:
644 		ctrl->result = snd_ctl_card_info(ctl, &ctrl->u.card_info);
645 		break;
646 	case SNDRV_CTL_IOCTL_ELEM_LIST:
647 	{
648 		size_t maxsize = CTL_SHM_DATA_MAXLEN;
649 		if (ctrl->u.element_list.space * sizeof(*ctrl->u.element_list.pids) > maxsize) {
650 			ctrl->result = -EFAULT;
651 			break;
652 		}
653 		ctrl->u.element_list.pids = (snd_ctl_elem_id_t*) ctrl->data;
654 		ctrl->result = snd_ctl_elem_list(ctl, &ctrl->u.element_list);
655 		break;
656 	}
657 	case SNDRV_CTL_IOCTL_ELEM_INFO:
658 		ctrl->result = snd_ctl_elem_info(ctl, &ctrl->u.element_info);
659 		break;
660 	case SNDRV_CTL_IOCTL_ELEM_READ:
661 		ctrl->result = snd_ctl_elem_read(ctl, &ctrl->u.element_read);
662 		break;
663 	case SNDRV_CTL_IOCTL_ELEM_WRITE:
664 		ctrl->result = snd_ctl_elem_write(ctl, &ctrl->u.element_write);
665 		break;
666 	case SNDRV_CTL_IOCTL_ELEM_LOCK:
667 		ctrl->result = snd_ctl_elem_lock(ctl, &ctrl->u.element_lock);
668 		break;
669 	case SNDRV_CTL_IOCTL_ELEM_UNLOCK:
670 		ctrl->result = snd_ctl_elem_unlock(ctl, &ctrl->u.element_unlock);
671 		break;
672 	case SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE:
673 		ctrl->result = snd_ctl_hwdep_next_device(ctl, &ctrl->u.device);
674 		break;
675 	case SNDRV_CTL_IOCTL_HWDEP_INFO:
676 		ctrl->result = snd_ctl_hwdep_info(ctl, &ctrl->u.hwdep_info);
677 		break;
678 	case SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE:
679 		ctrl->result = snd_ctl_pcm_next_device(ctl, &ctrl->u.device);
680 		break;
681 	case SNDRV_CTL_IOCTL_PCM_INFO:
682 		ctrl->result = snd_ctl_pcm_info(ctl, &ctrl->u.pcm_info);
683 		break;
684 	case SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE:
685 		ctrl->result = snd_ctl_pcm_prefer_subdevice(ctl, ctrl->u.pcm_prefer_subdevice);
686 		break;
687 	case SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE:
688 		ctrl->result = snd_ctl_rawmidi_next_device(ctl, &ctrl->u.device);
689 		break;
690 	case SNDRV_CTL_IOCTL_RAWMIDI_INFO:
691 		ctrl->result = snd_ctl_rawmidi_info(ctl, &ctrl->u.rawmidi_info);
692 		break;
693 	case SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE:
694 		ctrl->result = snd_ctl_rawmidi_prefer_subdevice(ctl, ctrl->u.rawmidi_prefer_subdevice);
695 		break;
696 	case SNDRV_CTL_IOCTL_POWER:
697 		ctrl->result = snd_ctl_set_power_state(ctl, ctrl->u.power_state);
698 		break;
699 	case SNDRV_CTL_IOCTL_POWER_STATE:
700 		ctrl->result = snd_ctl_get_power_state(ctl, &ctrl->u.power_state);
701 		break;
702 	case SND_CTL_IOCTL_READ:
703 		ctrl->result = snd_ctl_read(ctl, &ctrl->u.read);
704 		break;
705 	case SND_CTL_IOCTL_CLOSE:
706 		client->ops->close(client);
707 		break;
708 	case SND_CTL_IOCTL_POLL_DESCRIPTOR:
709 		ctrl->result = 0;
710 		return shm_ack_fd(client, _snd_ctl_poll_descriptor(ctl));
711 	default:
712 		ERROR("Bogus cmd: %x", ctrl->cmd);
713 		ctrl->result = -ENOSYS;
714 	}
715 	return shm_ack(client);
716 }
717 
718 transport_ops_t ctl_shm_ops = {
719 	.open	= ctl_shm_open,
720 	.cmd	= ctl_shm_cmd,
721 	.close	= ctl_shm_close,
722 };
723 
snd_client_open(client_t * client)724 static int snd_client_open(client_t *client)
725 {
726 	int err;
727 	snd_client_open_request_t req;
728 	snd_client_open_answer_t ans;
729 	char *name;
730 	memset(&ans, 0, sizeof(ans));
731 	err = read(client->ctrl_fd, &req, sizeof(req));
732 	if (err < 0) {
733 		SYSERROR("read failed");
734 		exit(1);
735 	}
736 	if (err != sizeof(req)) {
737 		ans.result = -EINVAL;
738 		goto _answer;
739 	}
740 	name = alloca(req.namelen);
741 	err = read(client->ctrl_fd, name, req.namelen);
742 	if (err < 0) {
743 		SYSERROR("read failed");
744 		exit(1);
745 	}
746 	if (err != req.namelen) {
747 		ans.result = -EINVAL;
748 		goto _answer;
749 	}
750 
751 	switch (req.transport_type) {
752 	case SND_TRANSPORT_TYPE_SHM:
753 		if (!client->local) {
754 			ans.result = -EINVAL;
755 			goto _answer;
756 		}
757 		switch (req.dev_type) {
758 		case SND_DEV_TYPE_PCM:
759 			client->ops = &pcm_shm_ops;
760 			break;
761 		case SND_DEV_TYPE_CONTROL:
762 			client->ops = &ctl_shm_ops;
763 			break;
764 		default:
765 			ans.result = -EINVAL;
766 			goto _answer;
767 		}
768 		break;
769 	default:
770 		ans.result = -EINVAL;
771 		goto _answer;
772 	}
773 
774 	name[req.namelen] = '\0';
775 
776 	client->transport_type = req.transport_type;
777 	strcpy(client->name, name);
778 	client->stream = req.stream;
779 	client->mode = req.mode;
780 
781 	err = client->ops->open(client, &ans.cookie);
782 	if (err < 0) {
783 		ans.result = err;
784 	} else {
785 		client->open = 1;
786 		ans.result = 0;
787 	}
788 
789  _answer:
790 	err = write(client->ctrl_fd, &ans, sizeof(ans));
791 	if (err != sizeof(ans)) {
792 		SYSERROR("write failed");
793 		exit(1);
794 	}
795 	return 0;
796 }
797 
client_poll_handler(waiter_t * waiter,unsigned short events ATTRIBUTE_UNUSED)798 static int client_poll_handler(waiter_t *waiter, unsigned short events ATTRIBUTE_UNUSED)
799 {
800 	client_t *client = waiter->private_data;
801 	if (client->open)
802 		client->ops->close(client);
803 	close(client->poll_fd);
804 	close(client->ctrl_fd);
805 	del_waiter(client->poll_fd);
806 	del_waiter(client->ctrl_fd);
807 	list_del(&client->list);
808 	free(client);
809 	return 0;
810 }
811 
client_ctrl_handler(waiter_t * waiter,unsigned short events)812 static int client_ctrl_handler(waiter_t *waiter, unsigned short events)
813 {
814 	client_t *client = waiter->private_data;
815 	if (events & POLLHUP) {
816 		if (client->open)
817 			client->ops->close(client);
818 		close(client->ctrl_fd);
819 		del_waiter(client->ctrl_fd);
820 		list_del(&client->list);
821 		free(client);
822 		return 0;
823 	}
824 	if (client->open)
825 		return client->ops->cmd(client);
826 	else
827 		return snd_client_open(client);
828 }
829 
inet_pending_handler(waiter_t * waiter,unsigned short events)830 static int inet_pending_handler(waiter_t *waiter, unsigned short events)
831 {
832 	inet_pending_t *pending = waiter->private_data;
833 	inet_pending_t *pdata;
834 	client_t *client;
835 	uint32_t cookie;
836 	struct list_head *item;
837 	int remove = 0;
838 	if (events & POLLHUP)
839 		remove = 1;
840 	else {
841 		int err = read(waiter->fd, &cookie, sizeof(cookie));
842 		if (err != sizeof(cookie))
843 			remove = 1;
844 		else {
845 			err = write(waiter->fd, &cookie, sizeof(cookie));
846 			if (err != sizeof(cookie))
847 				remove = 1;
848 		}
849 	}
850 	del_waiter(waiter->fd);
851 	if (remove) {
852 		close(waiter->fd);
853 		list_del(&pending->list);
854 		free(pending);
855 		return 0;
856 	}
857 
858 	list_for_each(item, &inet_pendings) {
859 		pdata = list_entry(item, inet_pending_t, list);
860 		if (pdata->cookie == cookie)
861 			goto found;
862 	}
863 	pending->cookie = cookie;
864 	return 0;
865 
866  found:
867 	client = calloc(1, sizeof(*client));
868 	client->local = 0;
869 	client->poll_fd = pdata->fd;
870 	client->ctrl_fd = waiter->fd;
871 	add_waiter(client->ctrl_fd, POLLIN | POLLHUP, client_ctrl_handler, client);
872 	add_waiter(client->poll_fd, POLLHUP, client_poll_handler, client);
873 	client->open = 0;
874 	list_add_tail(&client->list, &clients);
875 	list_del(&pending->list);
876 	list_del(&pdata->list);
877 	free(pending);
878 	free(pdata);
879 	return 0;
880 }
881 
local_handler(waiter_t * waiter,unsigned short events ATTRIBUTE_UNUSED)882 static int local_handler(waiter_t *waiter, unsigned short events ATTRIBUTE_UNUSED)
883 {
884 	int sock;
885 	sock = accept(waiter->fd, 0, 0);
886 	if (sock < 0) {
887 		int result = -errno;
888 		SYSERROR("accept failed");
889 		return result;
890 	} else {
891 		client_t *client = calloc(1, sizeof(*client));
892 		client->ctrl_fd = sock;
893 		client->local = 1;
894 		client->open = 0;
895 		add_waiter(sock, POLLIN | POLLHUP, client_ctrl_handler, client);
896 		list_add_tail(&client->list, &clients);
897 	}
898 	return 0;
899 }
900 
inet_handler(waiter_t * waiter,unsigned short events ATTRIBUTE_UNUSED)901 static int inet_handler(waiter_t *waiter, unsigned short events ATTRIBUTE_UNUSED)
902 {
903 	int sock;
904 	sock = accept(waiter->fd, 0, 0);
905 	if (sock < 0) {
906 		int result = -errno;
907 		SYSERROR("accept failed");
908 		return result;
909 	} else {
910 		inet_pending_t *pending = calloc(1, sizeof(*pending));
911 		pending->fd = sock;
912 		pending->cookie = 0;
913 		add_waiter(sock, POLLIN, inet_pending_handler, pending);
914 		list_add_tail(&pending->list, &inet_pendings);
915 	}
916 	return 0;
917 }
918 
server(const char * sockname,int port)919 static int server(const char *sockname, int port)
920 {
921 	int err, result, sockn = -1, socki = -1;
922 	unsigned int k;
923 	long open_max;
924 
925 	if (!sockname && port < 0)
926 		return -EINVAL;
927 	open_max = sysconf(_SC_OPEN_MAX);
928 	if (open_max < 0) {
929 		result = -errno;
930 		SYSERROR("sysconf failed");
931 		return result;
932 	}
933 	pollfds = calloc((size_t) open_max, sizeof(*pollfds));
934 	waiters = calloc((size_t) open_max, sizeof(*waiters));
935 
936 	if (sockname) {
937 		sockn = make_local_socket(sockname);
938 		if (sockn < 0)
939 			return sockn;
940 		if (fcntl(sockn, F_SETFL, O_NONBLOCK) < 0) {
941 			result = -errno;
942 			SYSERROR("fcntl O_NONBLOCK failed");
943 			goto _end;
944 		}
945 		if (listen(sockn, 4) < 0) {
946 			result = -errno;
947 			SYSERROR("listen failed");
948 			goto _end;
949 		}
950 		add_waiter(sockn, POLLIN, local_handler, NULL);
951 	}
952 	if (port >= 0) {
953 		socki = make_inet_socket(port);
954 		if (socki < 0)
955 			return socki;
956 		if (fcntl(socki, F_SETFL, O_NONBLOCK) < 0) {
957 			result = -errno;
958 			SYSERROR("fcntl failed");
959 			goto _end;
960 		}
961 		if (listen(socki, 4) < 0) {
962 			result = -errno;
963 			SYSERROR("listen failed");
964 			goto _end;
965 		}
966 		add_waiter(socki, POLLIN, inet_handler, NULL);
967 	}
968 
969 	while (1) {
970 		struct pollfd pfds[open_max];
971 		size_t pfds_count;
972 		do {
973 			err = poll(pollfds, pollfds_count, -1);
974 		} while (err == 0);
975 		if (err < 0) {
976 			SYSERROR("poll failed");
977 			continue;
978 		}
979 
980 		pfds_count = pollfds_count;
981 		memcpy(pfds, pollfds, sizeof(*pfds) * pfds_count);
982 		for (k = 0; k < pfds_count; k++) {
983 			struct pollfd *pfd = &pfds[k];
984 			if (pfd->revents) {
985 				waiter_t *w = &waiters[pfd->fd];
986 				if (!w->handler)
987 					continue;
988 				err = w->handler(w, pfd->revents);
989 				if (err < 0)
990 					ERROR("waiter handler failed");
991 			}
992 		}
993 	}
994  _end:
995 	if (sockn >= 0)
996 		close(sockn);
997 	if (socki >= 0)
998 		close(socki);
999 	free(pollfds);
1000 	free(waiters);
1001 	return result;
1002 }
1003 
1004 
usage(void)1005 static void usage(void)
1006 {
1007 	fprintf(stderr,
1008 		"Usage: %s [OPTIONS] server\n"
1009 		"--help			help\n",
1010 		command);
1011 }
1012 
main(int argc,char ** argv)1013 int main(int argc, char **argv)
1014 {
1015 	static const struct option long_options[] = {
1016 		{"help", 0, 0, 'h'},
1017 		{ 0 , 0 , 0, 0 }
1018 	};
1019 	int c;
1020 	snd_config_t *conf;
1021 	snd_config_iterator_t i, next;
1022 	const char *sockname = NULL;
1023 	long port = -1;
1024 	int err;
1025 	char *srvname;
1026 
1027 	command = argv[0];
1028 	while ((c = getopt_long(argc, argv, "h", long_options, 0)) != -1) {
1029 		switch (c) {
1030 		case 'h':
1031 			usage();
1032 			return 0;
1033 		default:
1034 			fprintf(stderr, "Try `%s --help' for more information\n", command);
1035 			return 1;
1036 		}
1037 	}
1038 	if (argc - optind != 1) {
1039 		ERROR("you need to specify server name");
1040 		return 1;
1041 	}
1042 	err = snd_config_update();
1043 	if (err < 0) {
1044 		ERROR("cannot read configuration file");
1045 		return 1;
1046 	}
1047 	srvname = argv[optind];
1048 	err = snd_config_search_definition(snd_config, "server", srvname, &conf);
1049 	if (err < 0) {
1050 		ERROR("Missing definition for server %s", srvname);
1051 		return 1;
1052 	}
1053 	if (snd_config_get_type(conf) != SND_CONFIG_TYPE_COMPOUND) {
1054 		SNDERR("Invalid type for server %s definition", srvname);
1055 		return -EINVAL;
1056 	}
1057 	snd_config_for_each(i, next, conf) {
1058 		snd_config_t *n = snd_config_iterator_entry(i);
1059 		const char *id;
1060 		if (snd_config_get_id(n, &id) < 0)
1061 			continue;
1062 		if (strcmp(id, "comment") == 0)
1063 			continue;
1064 		if (strcmp(id, "host") == 0)
1065 			continue;
1066 		if (strcmp(id, "socket") == 0) {
1067 			err = snd_config_get_string(n, &sockname);
1068 			if (err < 0) {
1069 				ERROR("Invalid type for %s", id);
1070 				return 1;
1071 			}
1072 			continue;
1073 		}
1074 		if (strcmp(id, "port") == 0) {
1075 			err = snd_config_get_integer(n, &port);
1076 			if (err < 0) {
1077 				ERROR("Invalid type for %s", id);
1078 				return 1;
1079 			}
1080 			continue;
1081 		}
1082 		ERROR("Unknown field %s", id);
1083 		return 1;
1084 	}
1085 	if (!sockname && port < 0) {
1086 		ERROR("either socket or port need to be defined");
1087 		return 1;
1088 	}
1089 	server(sockname, port);
1090 	return 0;
1091 }
1092