153a5a1b3Sopenharmony_ci/*** 253a5a1b3Sopenharmony_ci This file is part of PulseAudio. 353a5a1b3Sopenharmony_ci 453a5a1b3Sopenharmony_ci Copyright 2009 Lennart Poettering 553a5a1b3Sopenharmony_ci 653a5a1b3Sopenharmony_ci PulseAudio is free software; you can redistribute it and/or modify 753a5a1b3Sopenharmony_ci it under the terms of the GNU Lesser General Public License as 853a5a1b3Sopenharmony_ci published by the Free Software Foundation; either version 2.1 of the 953a5a1b3Sopenharmony_ci License, or (at your option) any later version. 1053a5a1b3Sopenharmony_ci 1153a5a1b3Sopenharmony_ci PulseAudio is distributed in the hope that it will be useful, but 1253a5a1b3Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 1353a5a1b3Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1453a5a1b3Sopenharmony_ci General Public License for more details. 1553a5a1b3Sopenharmony_ci 1653a5a1b3Sopenharmony_ci You should have received a copy of the GNU Lesser General Public 1753a5a1b3Sopenharmony_ci License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 1853a5a1b3Sopenharmony_ci***/ 1953a5a1b3Sopenharmony_ci 2053a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H 2153a5a1b3Sopenharmony_ci#include <config.h> 2253a5a1b3Sopenharmony_ci#endif 2353a5a1b3Sopenharmony_ci 2453a5a1b3Sopenharmony_ci#include <string.h> 2553a5a1b3Sopenharmony_ci#include <unistd.h> 2653a5a1b3Sopenharmony_ci#include <stdlib.h> 2753a5a1b3Sopenharmony_ci#include <signal.h> 2853a5a1b3Sopenharmony_ci 2953a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h> 3053a5a1b3Sopenharmony_ci#include <pulsecore/module.h> 3153a5a1b3Sopenharmony_ci#include <pulsecore/core.h> 3253a5a1b3Sopenharmony_ci#include <pulsecore/core-util.h> 3353a5a1b3Sopenharmony_ci#include <pulsecore/log.h> 3453a5a1b3Sopenharmony_ci#include <pulse/mainloop-api.h> 3553a5a1b3Sopenharmony_ci#include <pulsecore/core-error.h> 3653a5a1b3Sopenharmony_ci#include <pulsecore/start-child.h> 3753a5a1b3Sopenharmony_ci 3853a5a1b3Sopenharmony_ci#include "stdin-util.h" 3953a5a1b3Sopenharmony_ci 4053a5a1b3Sopenharmony_ciint fill_buf(struct userdata *u) { 4153a5a1b3Sopenharmony_ci ssize_t r; 4253a5a1b3Sopenharmony_ci pa_assert(u); 4353a5a1b3Sopenharmony_ci 4453a5a1b3Sopenharmony_ci if (u->buf_fill >= BUF_MAX) { 4553a5a1b3Sopenharmony_ci pa_log("read buffer overflow"); 4653a5a1b3Sopenharmony_ci return -1; 4753a5a1b3Sopenharmony_ci } 4853a5a1b3Sopenharmony_ci 4953a5a1b3Sopenharmony_ci if ((r = pa_read(u->fd, u->buf + u->buf_fill, BUF_MAX - u->buf_fill, &u->fd_type)) <= 0) 5053a5a1b3Sopenharmony_ci return -1; 5153a5a1b3Sopenharmony_ci 5253a5a1b3Sopenharmony_ci u->buf_fill += (size_t) r; 5353a5a1b3Sopenharmony_ci return 0; 5453a5a1b3Sopenharmony_ci} 5553a5a1b3Sopenharmony_ci 5653a5a1b3Sopenharmony_ciint read_byte(struct userdata *u) { 5753a5a1b3Sopenharmony_ci int ret; 5853a5a1b3Sopenharmony_ci pa_assert(u); 5953a5a1b3Sopenharmony_ci 6053a5a1b3Sopenharmony_ci if (u->buf_fill < 1) 6153a5a1b3Sopenharmony_ci if (fill_buf(u) < 0) 6253a5a1b3Sopenharmony_ci return -1; 6353a5a1b3Sopenharmony_ci 6453a5a1b3Sopenharmony_ci ret = u->buf[0]; 6553a5a1b3Sopenharmony_ci pa_assert(u->buf_fill > 0); 6653a5a1b3Sopenharmony_ci u->buf_fill--; 6753a5a1b3Sopenharmony_ci memmove(u->buf, u->buf+1, u->buf_fill); 6853a5a1b3Sopenharmony_ci return ret; 6953a5a1b3Sopenharmony_ci} 7053a5a1b3Sopenharmony_ci 7153a5a1b3Sopenharmony_cichar *read_string(struct userdata *u) { 7253a5a1b3Sopenharmony_ci pa_assert(u); 7353a5a1b3Sopenharmony_ci 7453a5a1b3Sopenharmony_ci for (;;) { 7553a5a1b3Sopenharmony_ci char *e; 7653a5a1b3Sopenharmony_ci 7753a5a1b3Sopenharmony_ci if ((e = memchr(u->buf, 0, u->buf_fill))) { 7853a5a1b3Sopenharmony_ci char *ret = pa_xstrdup(u->buf); 7953a5a1b3Sopenharmony_ci u->buf_fill -= (size_t) (e - u->buf +1); 8053a5a1b3Sopenharmony_ci memmove(u->buf, e+1, u->buf_fill); 8153a5a1b3Sopenharmony_ci return ret; 8253a5a1b3Sopenharmony_ci } 8353a5a1b3Sopenharmony_ci 8453a5a1b3Sopenharmony_ci if (fill_buf(u) < 0) 8553a5a1b3Sopenharmony_ci return NULL; 8653a5a1b3Sopenharmony_ci } 8753a5a1b3Sopenharmony_ci} 8853a5a1b3Sopenharmony_ci 8953a5a1b3Sopenharmony_civoid unload_one_module(struct pa_module_info *m, unsigned i) { 9053a5a1b3Sopenharmony_ci struct userdata *u; 9153a5a1b3Sopenharmony_ci 9253a5a1b3Sopenharmony_ci pa_assert(m); 9353a5a1b3Sopenharmony_ci pa_assert(i < m->n_items); 9453a5a1b3Sopenharmony_ci 9553a5a1b3Sopenharmony_ci u = m->userdata; 9653a5a1b3Sopenharmony_ci 9753a5a1b3Sopenharmony_ci if (m->items[i].index == PA_INVALID_INDEX) 9853a5a1b3Sopenharmony_ci return; 9953a5a1b3Sopenharmony_ci 10053a5a1b3Sopenharmony_ci pa_log_debug("Unloading module #%i", m->items[i].index); 10153a5a1b3Sopenharmony_ci pa_module_unload_by_index(u->core, m->items[i].index, true); 10253a5a1b3Sopenharmony_ci m->items[i].index = PA_INVALID_INDEX; 10353a5a1b3Sopenharmony_ci pa_xfree(m->items[i].name); 10453a5a1b3Sopenharmony_ci pa_xfree(m->items[i].args); 10553a5a1b3Sopenharmony_ci m->items[i].name = m->items[i].args = NULL; 10653a5a1b3Sopenharmony_ci} 10753a5a1b3Sopenharmony_ci 10853a5a1b3Sopenharmony_civoid unload_all_modules(struct pa_module_info *m) { 10953a5a1b3Sopenharmony_ci unsigned i; 11053a5a1b3Sopenharmony_ci 11153a5a1b3Sopenharmony_ci pa_assert(m); 11253a5a1b3Sopenharmony_ci 11353a5a1b3Sopenharmony_ci for (i = 0; i < m->n_items; i++) 11453a5a1b3Sopenharmony_ci unload_one_module(m, i); 11553a5a1b3Sopenharmony_ci 11653a5a1b3Sopenharmony_ci m->n_items = 0; 11753a5a1b3Sopenharmony_ci} 11853a5a1b3Sopenharmony_ci 11953a5a1b3Sopenharmony_civoid load_module( 12053a5a1b3Sopenharmony_ci struct pa_module_info *m, 12153a5a1b3Sopenharmony_ci unsigned i, 12253a5a1b3Sopenharmony_ci const char *name, 12353a5a1b3Sopenharmony_ci const char *args, 12453a5a1b3Sopenharmony_ci bool is_new) { 12553a5a1b3Sopenharmony_ci 12653a5a1b3Sopenharmony_ci struct userdata *u; 12753a5a1b3Sopenharmony_ci pa_module *mod; 12853a5a1b3Sopenharmony_ci 12953a5a1b3Sopenharmony_ci pa_assert(m); 13053a5a1b3Sopenharmony_ci pa_assert(name); 13153a5a1b3Sopenharmony_ci pa_assert(args); 13253a5a1b3Sopenharmony_ci 13353a5a1b3Sopenharmony_ci u = m->userdata; 13453a5a1b3Sopenharmony_ci 13553a5a1b3Sopenharmony_ci if (!is_new) { 13653a5a1b3Sopenharmony_ci if (m->items[i].index != PA_INVALID_INDEX && 13753a5a1b3Sopenharmony_ci pa_streq(m->items[i].name, name) && 13853a5a1b3Sopenharmony_ci pa_streq(m->items[i].args, args)) 13953a5a1b3Sopenharmony_ci return; 14053a5a1b3Sopenharmony_ci 14153a5a1b3Sopenharmony_ci unload_one_module(m, i); 14253a5a1b3Sopenharmony_ci } 14353a5a1b3Sopenharmony_ci 14453a5a1b3Sopenharmony_ci pa_log_debug("Loading module '%s' with args '%s' due to GConf/GSettings configuration.", name, args); 14553a5a1b3Sopenharmony_ci 14653a5a1b3Sopenharmony_ci m->items[i].name = pa_xstrdup(name); 14753a5a1b3Sopenharmony_ci m->items[i].args = pa_xstrdup(args); 14853a5a1b3Sopenharmony_ci m->items[i].index = PA_INVALID_INDEX; 14953a5a1b3Sopenharmony_ci 15053a5a1b3Sopenharmony_ci if (pa_module_load(&mod, u->core, name, args) < 0) { 15153a5a1b3Sopenharmony_ci pa_log("pa_module_load() failed"); 15253a5a1b3Sopenharmony_ci return; 15353a5a1b3Sopenharmony_ci } 15453a5a1b3Sopenharmony_ci 15553a5a1b3Sopenharmony_ci m->items[i].index = mod->index; 15653a5a1b3Sopenharmony_ci} 15753a5a1b3Sopenharmony_ci 15853a5a1b3Sopenharmony_civoid module_info_free(void *p) { 15953a5a1b3Sopenharmony_ci struct pa_module_info *m = p; 16053a5a1b3Sopenharmony_ci 16153a5a1b3Sopenharmony_ci pa_assert(m); 16253a5a1b3Sopenharmony_ci 16353a5a1b3Sopenharmony_ci unload_all_modules(m); 16453a5a1b3Sopenharmony_ci pa_xfree(m->name); 16553a5a1b3Sopenharmony_ci pa_xfree(m); 16653a5a1b3Sopenharmony_ci} 16753a5a1b3Sopenharmony_ci 16853a5a1b3Sopenharmony_ciint handle_event(struct userdata *u) { 16953a5a1b3Sopenharmony_ci int opcode; 17053a5a1b3Sopenharmony_ci int ret = 0; 17153a5a1b3Sopenharmony_ci 17253a5a1b3Sopenharmony_ci do { 17353a5a1b3Sopenharmony_ci if ((opcode = read_byte(u)) < 0) { 17453a5a1b3Sopenharmony_ci if (errno == EINTR || errno == EAGAIN) 17553a5a1b3Sopenharmony_ci break; 17653a5a1b3Sopenharmony_ci goto fail; 17753a5a1b3Sopenharmony_ci } 17853a5a1b3Sopenharmony_ci 17953a5a1b3Sopenharmony_ci switch (opcode) { 18053a5a1b3Sopenharmony_ci case '!': 18153a5a1b3Sopenharmony_ci /* The helper tool is now initialized */ 18253a5a1b3Sopenharmony_ci ret = 1; 18353a5a1b3Sopenharmony_ci break; 18453a5a1b3Sopenharmony_ci 18553a5a1b3Sopenharmony_ci case '+': { 18653a5a1b3Sopenharmony_ci char *name; 18753a5a1b3Sopenharmony_ci struct pa_module_info *m; 18853a5a1b3Sopenharmony_ci unsigned i, j; 18953a5a1b3Sopenharmony_ci 19053a5a1b3Sopenharmony_ci if (!(name = read_string(u))) 19153a5a1b3Sopenharmony_ci goto fail; 19253a5a1b3Sopenharmony_ci 19353a5a1b3Sopenharmony_ci if (!(m = pa_hashmap_get(u->module_infos, name))) { 19453a5a1b3Sopenharmony_ci m = pa_xnew(struct pa_module_info, 1); 19553a5a1b3Sopenharmony_ci m->userdata = u; 19653a5a1b3Sopenharmony_ci m->name = name; 19753a5a1b3Sopenharmony_ci m->n_items = 0; 19853a5a1b3Sopenharmony_ci pa_hashmap_put(u->module_infos, m->name, m); 19953a5a1b3Sopenharmony_ci } else 20053a5a1b3Sopenharmony_ci pa_xfree(name); 20153a5a1b3Sopenharmony_ci 20253a5a1b3Sopenharmony_ci i = 0; 20353a5a1b3Sopenharmony_ci while (i < MAX_MODULES) { 20453a5a1b3Sopenharmony_ci char *module, *args; 20553a5a1b3Sopenharmony_ci 20653a5a1b3Sopenharmony_ci if (!(module = read_string(u))) { 20753a5a1b3Sopenharmony_ci if (i > m->n_items) m->n_items = i; 20853a5a1b3Sopenharmony_ci goto fail; 20953a5a1b3Sopenharmony_ci } 21053a5a1b3Sopenharmony_ci 21153a5a1b3Sopenharmony_ci if (!*module) { 21253a5a1b3Sopenharmony_ci pa_xfree(module); 21353a5a1b3Sopenharmony_ci break; 21453a5a1b3Sopenharmony_ci } 21553a5a1b3Sopenharmony_ci 21653a5a1b3Sopenharmony_ci if (!(args = read_string(u))) { 21753a5a1b3Sopenharmony_ci pa_xfree(module); 21853a5a1b3Sopenharmony_ci 21953a5a1b3Sopenharmony_ci if (i > m->n_items) m->n_items = i; 22053a5a1b3Sopenharmony_ci goto fail; 22153a5a1b3Sopenharmony_ci } 22253a5a1b3Sopenharmony_ci 22353a5a1b3Sopenharmony_ci load_module(m, i, module, args, i >= m->n_items); 22453a5a1b3Sopenharmony_ci 22553a5a1b3Sopenharmony_ci i++; 22653a5a1b3Sopenharmony_ci 22753a5a1b3Sopenharmony_ci pa_xfree(module); 22853a5a1b3Sopenharmony_ci pa_xfree(args); 22953a5a1b3Sopenharmony_ci } 23053a5a1b3Sopenharmony_ci 23153a5a1b3Sopenharmony_ci /* Unload all removed modules */ 23253a5a1b3Sopenharmony_ci for (j = i; j < m->n_items; j++) 23353a5a1b3Sopenharmony_ci unload_one_module(m, j); 23453a5a1b3Sopenharmony_ci 23553a5a1b3Sopenharmony_ci m->n_items = i; 23653a5a1b3Sopenharmony_ci 23753a5a1b3Sopenharmony_ci break; 23853a5a1b3Sopenharmony_ci } 23953a5a1b3Sopenharmony_ci 24053a5a1b3Sopenharmony_ci case '-': { 24153a5a1b3Sopenharmony_ci char *name; 24253a5a1b3Sopenharmony_ci 24353a5a1b3Sopenharmony_ci if (!(name = read_string(u))) 24453a5a1b3Sopenharmony_ci goto fail; 24553a5a1b3Sopenharmony_ci 24653a5a1b3Sopenharmony_ci pa_hashmap_remove_and_free(u->module_infos, name); 24753a5a1b3Sopenharmony_ci pa_xfree(name); 24853a5a1b3Sopenharmony_ci 24953a5a1b3Sopenharmony_ci break; 25053a5a1b3Sopenharmony_ci } 25153a5a1b3Sopenharmony_ci } 25253a5a1b3Sopenharmony_ci } while (u->buf_fill > 0 && ret == 0); 25353a5a1b3Sopenharmony_ci 25453a5a1b3Sopenharmony_ci return ret; 25553a5a1b3Sopenharmony_ci 25653a5a1b3Sopenharmony_cifail: 25753a5a1b3Sopenharmony_ci pa_log("Unable to read or parse data from client."); 25853a5a1b3Sopenharmony_ci return -1; 25953a5a1b3Sopenharmony_ci} 26053a5a1b3Sopenharmony_ci 26153a5a1b3Sopenharmony_civoid io_event_cb( 26253a5a1b3Sopenharmony_ci pa_mainloop_api*a, 26353a5a1b3Sopenharmony_ci pa_io_event* e, 26453a5a1b3Sopenharmony_ci int fd, 26553a5a1b3Sopenharmony_ci pa_io_event_flags_t events, 26653a5a1b3Sopenharmony_ci void *userdata) { 26753a5a1b3Sopenharmony_ci 26853a5a1b3Sopenharmony_ci struct userdata *u = userdata; 26953a5a1b3Sopenharmony_ci 27053a5a1b3Sopenharmony_ci if (events & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) { 27153a5a1b3Sopenharmony_ci pa_log("Lost I/O connection in module \"%s\"", u->module->name); 27253a5a1b3Sopenharmony_ci goto fail; 27353a5a1b3Sopenharmony_ci } 27453a5a1b3Sopenharmony_ci 27553a5a1b3Sopenharmony_ci if (handle_event(u) >= 0) 27653a5a1b3Sopenharmony_ci return; 27753a5a1b3Sopenharmony_ci 27853a5a1b3Sopenharmony_cifail: 27953a5a1b3Sopenharmony_ci if (u->io_event) { 28053a5a1b3Sopenharmony_ci u->core->mainloop->io_free(u->io_event); 28153a5a1b3Sopenharmony_ci u->io_event = NULL; 28253a5a1b3Sopenharmony_ci } 28353a5a1b3Sopenharmony_ci 28453a5a1b3Sopenharmony_ci pa_module_unload_request(u->module, true); 28553a5a1b3Sopenharmony_ci} 286