1/*** 2 This file is part of PulseAudio. 3 4 Copyright 2009 Lennart Poettering 5 6 PulseAudio is free software; you can redistribute it and/or modify 7 it under the terms of the GNU Lesser General Public License as 8 published by the Free Software Foundation; either version 2.1 of the 9 License, or (at your option) any later version. 10 11 PulseAudio is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU Lesser General Public 17 License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 18***/ 19 20#ifdef HAVE_CONFIG_H 21#include <config.h> 22#endif 23 24#include <string.h> 25#include <unistd.h> 26#include <stdlib.h> 27#include <signal.h> 28 29#include <pulse/xmalloc.h> 30#include <pulsecore/module.h> 31#include <pulsecore/core.h> 32#include <pulsecore/core-util.h> 33#include <pulsecore/log.h> 34#include <pulse/mainloop-api.h> 35#include <pulsecore/core-error.h> 36#include <pulsecore/start-child.h> 37 38#include "stdin-util.h" 39 40int fill_buf(struct userdata *u) { 41 ssize_t r; 42 pa_assert(u); 43 44 if (u->buf_fill >= BUF_MAX) { 45 pa_log("read buffer overflow"); 46 return -1; 47 } 48 49 if ((r = pa_read(u->fd, u->buf + u->buf_fill, BUF_MAX - u->buf_fill, &u->fd_type)) <= 0) 50 return -1; 51 52 u->buf_fill += (size_t) r; 53 return 0; 54} 55 56int read_byte(struct userdata *u) { 57 int ret; 58 pa_assert(u); 59 60 if (u->buf_fill < 1) 61 if (fill_buf(u) < 0) 62 return -1; 63 64 ret = u->buf[0]; 65 pa_assert(u->buf_fill > 0); 66 u->buf_fill--; 67 memmove(u->buf, u->buf+1, u->buf_fill); 68 return ret; 69} 70 71char *read_string(struct userdata *u) { 72 pa_assert(u); 73 74 for (;;) { 75 char *e; 76 77 if ((e = memchr(u->buf, 0, u->buf_fill))) { 78 char *ret = pa_xstrdup(u->buf); 79 u->buf_fill -= (size_t) (e - u->buf +1); 80 memmove(u->buf, e+1, u->buf_fill); 81 return ret; 82 } 83 84 if (fill_buf(u) < 0) 85 return NULL; 86 } 87} 88 89void unload_one_module(struct pa_module_info *m, unsigned i) { 90 struct userdata *u; 91 92 pa_assert(m); 93 pa_assert(i < m->n_items); 94 95 u = m->userdata; 96 97 if (m->items[i].index == PA_INVALID_INDEX) 98 return; 99 100 pa_log_debug("Unloading module #%i", m->items[i].index); 101 pa_module_unload_by_index(u->core, m->items[i].index, true); 102 m->items[i].index = PA_INVALID_INDEX; 103 pa_xfree(m->items[i].name); 104 pa_xfree(m->items[i].args); 105 m->items[i].name = m->items[i].args = NULL; 106} 107 108void unload_all_modules(struct pa_module_info *m) { 109 unsigned i; 110 111 pa_assert(m); 112 113 for (i = 0; i < m->n_items; i++) 114 unload_one_module(m, i); 115 116 m->n_items = 0; 117} 118 119void load_module( 120 struct pa_module_info *m, 121 unsigned i, 122 const char *name, 123 const char *args, 124 bool is_new) { 125 126 struct userdata *u; 127 pa_module *mod; 128 129 pa_assert(m); 130 pa_assert(name); 131 pa_assert(args); 132 133 u = m->userdata; 134 135 if (!is_new) { 136 if (m->items[i].index != PA_INVALID_INDEX && 137 pa_streq(m->items[i].name, name) && 138 pa_streq(m->items[i].args, args)) 139 return; 140 141 unload_one_module(m, i); 142 } 143 144 pa_log_debug("Loading module '%s' with args '%s' due to GConf/GSettings configuration.", name, args); 145 146 m->items[i].name = pa_xstrdup(name); 147 m->items[i].args = pa_xstrdup(args); 148 m->items[i].index = PA_INVALID_INDEX; 149 150 if (pa_module_load(&mod, u->core, name, args) < 0) { 151 pa_log("pa_module_load() failed"); 152 return; 153 } 154 155 m->items[i].index = mod->index; 156} 157 158void module_info_free(void *p) { 159 struct pa_module_info *m = p; 160 161 pa_assert(m); 162 163 unload_all_modules(m); 164 pa_xfree(m->name); 165 pa_xfree(m); 166} 167 168int handle_event(struct userdata *u) { 169 int opcode; 170 int ret = 0; 171 172 do { 173 if ((opcode = read_byte(u)) < 0) { 174 if (errno == EINTR || errno == EAGAIN) 175 break; 176 goto fail; 177 } 178 179 switch (opcode) { 180 case '!': 181 /* The helper tool is now initialized */ 182 ret = 1; 183 break; 184 185 case '+': { 186 char *name; 187 struct pa_module_info *m; 188 unsigned i, j; 189 190 if (!(name = read_string(u))) 191 goto fail; 192 193 if (!(m = pa_hashmap_get(u->module_infos, name))) { 194 m = pa_xnew(struct pa_module_info, 1); 195 m->userdata = u; 196 m->name = name; 197 m->n_items = 0; 198 pa_hashmap_put(u->module_infos, m->name, m); 199 } else 200 pa_xfree(name); 201 202 i = 0; 203 while (i < MAX_MODULES) { 204 char *module, *args; 205 206 if (!(module = read_string(u))) { 207 if (i > m->n_items) m->n_items = i; 208 goto fail; 209 } 210 211 if (!*module) { 212 pa_xfree(module); 213 break; 214 } 215 216 if (!(args = read_string(u))) { 217 pa_xfree(module); 218 219 if (i > m->n_items) m->n_items = i; 220 goto fail; 221 } 222 223 load_module(m, i, module, args, i >= m->n_items); 224 225 i++; 226 227 pa_xfree(module); 228 pa_xfree(args); 229 } 230 231 /* Unload all removed modules */ 232 for (j = i; j < m->n_items; j++) 233 unload_one_module(m, j); 234 235 m->n_items = i; 236 237 break; 238 } 239 240 case '-': { 241 char *name; 242 243 if (!(name = read_string(u))) 244 goto fail; 245 246 pa_hashmap_remove_and_free(u->module_infos, name); 247 pa_xfree(name); 248 249 break; 250 } 251 } 252 } while (u->buf_fill > 0 && ret == 0); 253 254 return ret; 255 256fail: 257 pa_log("Unable to read or parse data from client."); 258 return -1; 259} 260 261void io_event_cb( 262 pa_mainloop_api*a, 263 pa_io_event* e, 264 int fd, 265 pa_io_event_flags_t events, 266 void *userdata) { 267 268 struct userdata *u = userdata; 269 270 if (events & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) { 271 pa_log("Lost I/O connection in module \"%s\"", u->module->name); 272 goto fail; 273 } 274 275 if (handle_event(u) >= 0) 276 return; 277 278fail: 279 if (u->io_event) { 280 u->core->mainloop->io_free(u->io_event); 281 u->io_event = NULL; 282 } 283 284 pa_module_unload_request(u->module, true); 285} 286