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