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