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