1/*** 2 This file is part of PulseAudio. 3 4 Copyright 2004-2006 Lennart Poettering 5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB 6 7 PulseAudio is free software; you can redistribute it and/or modify 8 it under the terms of the GNU Lesser General Public License as published 9 by the Free Software Foundation; either version 2.1 of the License, 10 or (at your option) any later version. 11 12 PulseAudio is distributed in the hope that it will be useful, but 13 WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 General Public License for more details. 16 17 You should have received a copy of the GNU Lesser General Public License 18 along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 19***/ 20 21#ifdef HAVE_CONFIG_H 22#include <config.h> 23#endif 24 25#include <errno.h> 26#include <stdio.h> 27#include <unistd.h> 28 29#ifdef HAVE_NETINET_IN_H 30#include <netinet/in.h> 31#endif 32 33#include <pulse/xmalloc.h> 34 35#include <pulsecore/core-error.h> 36#include <pulsecore/module.h> 37#include <pulsecore/socket.h> 38#include <pulsecore/socket-server.h> 39#include <pulsecore/socket-util.h> 40#include <pulsecore/core-util.h> 41#include <pulsecore/modargs.h> 42#include <pulsecore/log.h> 43#include <pulsecore/native-common.h> 44#include <pulsecore/creds.h> 45#include <pulsecore/arpa-inet.h> 46 47#ifdef USE_TCP_SOCKETS 48#define SOCKET_DESCRIPTION "(TCP sockets)" 49#define SOCKET_USAGE "port=<TCP port number> listen=<address to listen on>" 50#else 51#define SOCKET_DESCRIPTION "(UNIX sockets)" 52#define SOCKET_USAGE "socket=<path to UNIX socket>" 53#endif 54 55#if defined(USE_PROTOCOL_SIMPLE) 56# include <pulsecore/protocol-simple.h> 57# define TCPWRAP_SERVICE "pulseaudio-simple" 58# define IPV4_PORT 4711 59# define UNIX_SOCKET "simple" 60# define MODULE_ARGUMENTS "rate", "format", "channels", "sink", "source", "playback", "record", 61 62 PA_MODULE_DESCRIPTION("Simple protocol "SOCKET_DESCRIPTION); 63 PA_MODULE_USAGE("rate=<sample rate> " 64 "format=<sample format> " 65 "channels=<number of channels> " 66 "sink=<sink to connect to> " 67 "source=<source to connect to> " 68 "playback=<enable playback?> " 69 "record=<enable record?> " 70 SOCKET_USAGE); 71#elif defined(USE_PROTOCOL_CLI) 72# include <pulsecore/protocol-cli.h> 73# define TCPWRAP_SERVICE "pulseaudio-cli" 74# define IPV4_PORT 4712 75# define UNIX_SOCKET "cli" 76# define MODULE_ARGUMENTS 77 78 PA_MODULE_DESCRIPTION("Command line interface protocol "SOCKET_DESCRIPTION); 79 PA_MODULE_USAGE(SOCKET_USAGE); 80#elif defined(USE_PROTOCOL_HTTP) 81# include <pulsecore/protocol-http.h> 82# define TCPWRAP_SERVICE "pulseaudio-http" 83# define IPV4_PORT 4714 84# define UNIX_SOCKET "http" 85# define MODULE_ARGUMENTS 86 87 PA_MODULE_DESCRIPTION("HTTP "SOCKET_DESCRIPTION); 88 PA_MODULE_USAGE(SOCKET_USAGE); 89#elif defined(USE_PROTOCOL_NATIVE) 90# include <pulsecore/protocol-native.h> 91# define TCPWRAP_SERVICE "pulseaudio-native" 92# define IPV4_PORT PA_NATIVE_DEFAULT_PORT 93# define UNIX_SOCKET PA_NATIVE_DEFAULT_UNIX_SOCKET 94# define MODULE_ARGUMENTS_COMMON "cookie", "auth-cookie", "auth-cookie-enabled", "auth-anonymous", 95 96# if defined(HAVE_CREDS) && !defined(USE_TCP_SOCKETS) 97# define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON "auth-group", "auth-group-enable", "srbchannel", 98# define AUTH_USAGE "auth-group=<system group to allow access> auth-group-enable=<enable auth by UNIX group?> " 99# define SRB_USAGE "srbchannel=<enable shared ringbuffer communication channel?> " 100# elif defined(USE_TCP_SOCKETS) 101# define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON "auth-ip-acl", 102# define AUTH_USAGE "auth-ip-acl=<IP address ACL to allow access> " 103# define SRB_USAGE 104# else 105# define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON 106# define AUTH_USAGE 107# define SRB_USAGE 108# endif 109 110 PA_MODULE_DESCRIPTION("Native protocol "SOCKET_DESCRIPTION); 111 PA_MODULE_USAGE("auth-anonymous=<don't check for cookies?> " 112 "auth-cookie=<path to cookie file> " 113 "auth-cookie-enabled=<enable cookie authentication?> " 114 AUTH_USAGE 115 SRB_USAGE 116 SOCKET_USAGE); 117#elif defined(USE_PROTOCOL_ESOUND) 118# include <pulsecore/protocol-esound.h> 119# include <pulsecore/esound.h> 120# define TCPWRAP_SERVICE "esound" 121# define IPV4_PORT ESD_DEFAULT_PORT 122# define MODULE_ARGUMENTS_COMMON "sink", "source", "auth-anonymous", "cookie", "auth-cookie", "auth-cookie-enabled", 123 124# if defined(USE_TCP_SOCKETS) 125# define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON "auth-ip-acl", 126# define AUTH_USAGE "auth-ip-acl=<IP address ACL to allow access> " 127# else 128# define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON 129# define AUTH_USAGE 130# endif 131 132 PA_MODULE_DESCRIPTION("ESOUND protocol "SOCKET_DESCRIPTION); 133 PA_MODULE_USAGE("sink=<sink to connect to> " 134 "source=<source to connect to> " 135 "auth-anonymous=<don't verify cookies?> " 136 "auth-cookie=<path to cookie file> " 137 "auth-cookie-enabled=<enable cookie authentication?> " 138 AUTH_USAGE 139 SOCKET_USAGE); 140#else 141# error "Broken build system" 142#endif 143 144PA_MODULE_LOAD_ONCE(false); 145PA_MODULE_AUTHOR("Lennart Poettering"); 146PA_MODULE_VERSION(PACKAGE_VERSION); 147 148static const char* const valid_modargs[] = { 149 MODULE_ARGUMENTS 150#if defined(USE_TCP_SOCKETS) 151 "port", 152 "listen", 153#else 154 "socket", 155#endif 156 NULL 157}; 158 159struct userdata { 160 pa_module *module; 161 162#if defined(USE_PROTOCOL_SIMPLE) 163 pa_simple_protocol *simple_protocol; 164 pa_simple_options *simple_options; 165#elif defined(USE_PROTOCOL_CLI) 166 pa_cli_protocol *cli_protocol; 167#elif defined(USE_PROTOCOL_HTTP) 168 pa_http_protocol *http_protocol; 169#elif defined(USE_PROTOCOL_NATIVE) 170 pa_native_protocol *native_protocol; 171 pa_native_options *native_options; 172#else 173 pa_esound_protocol *esound_protocol; 174 pa_esound_options *esound_options; 175#endif 176 177#if defined(USE_TCP_SOCKETS) 178 pa_socket_server *socket_server_ipv4; 179# ifdef HAVE_IPV6 180 pa_socket_server *socket_server_ipv6; 181# endif 182#else 183 pa_socket_server *socket_server_unix; 184 char *socket_path; 185#endif 186}; 187 188static void socket_server_on_connection_cb(pa_socket_server*s, pa_iochannel *io, void *userdata) { 189 struct userdata *u = userdata; 190 191 pa_assert(s); 192 pa_assert(io); 193 pa_assert(u); 194 195#if defined(USE_PROTOCOL_SIMPLE) 196 pa_simple_protocol_connect(u->simple_protocol, io, u->simple_options); 197#elif defined(USE_PROTOCOL_CLI) 198 pa_cli_protocol_connect(u->cli_protocol, io, u->module); 199#elif defined(USE_PROTOCOL_HTTP) 200 pa_http_protocol_connect(u->http_protocol, io, u->module); 201#elif defined(USE_PROTOCOL_NATIVE) 202 pa_native_protocol_connect(u->native_protocol, io, u->native_options); 203#else 204 pa_esound_protocol_connect(u->esound_protocol, io, u->esound_options); 205#endif 206} 207 208int pa__init(pa_module*m) { 209 pa_modargs *ma = NULL; 210 struct userdata *u = NULL; 211 212#if defined(USE_TCP_SOCKETS) 213 uint32_t port = IPV4_PORT; 214 bool port_fallback = true; 215 const char *listen_on; 216#else 217 int r; 218#endif 219 220#if defined(USE_PROTOCOL_NATIVE) || defined(USE_PROTOCOL_HTTP) 221 char t[256]; 222#endif 223 224 pa_assert(m); 225 226 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { 227 pa_log("Failed to parse module arguments"); 228 goto fail; 229 } 230 231 m->userdata = u = pa_xnew0(struct userdata, 1); 232 u->module = m; 233 234#if defined(USE_PROTOCOL_SIMPLE) 235 u->simple_protocol = pa_simple_protocol_get(m->core); 236 237 u->simple_options = pa_simple_options_new(); 238 if (pa_simple_options_parse(u->simple_options, m->core, ma) < 0) 239 goto fail; 240 u->simple_options->module = m; 241#elif defined(USE_PROTOCOL_CLI) 242 u->cli_protocol = pa_cli_protocol_get(m->core); 243#elif defined(USE_PROTOCOL_HTTP) 244 u->http_protocol = pa_http_protocol_get(m->core); 245#elif defined(USE_PROTOCOL_NATIVE) 246 u->native_protocol = pa_native_protocol_get(m->core); 247 248 u->native_options = pa_native_options_new(); 249 if (pa_native_options_parse(u->native_options, m->core, ma) < 0) 250 goto fail; 251 u->native_options->module = m; 252#else 253 u->esound_protocol = pa_esound_protocol_get(m->core); 254 255 u->esound_options = pa_esound_options_new(); 256 if (pa_esound_options_parse(u->esound_options, m->core, ma) < 0) 257 goto fail; 258 u->esound_options->module = m; 259#endif 260 261#if defined(USE_TCP_SOCKETS) 262 263 if (pa_in_system_mode() || pa_modargs_get_value(ma, "port", NULL)) 264 port_fallback = false; 265 266 if (pa_modargs_get_value_u32(ma, "port", &port) < 0 || port < 1 || port > 0xFFFF) { 267 pa_log("port= expects a numerical argument between 1 and 65535."); 268 goto fail; 269 } 270 271 listen_on = pa_modargs_get_value(ma, "listen", NULL); 272 273 if (listen_on) { 274# ifdef HAVE_IPV6 275 u->socket_server_ipv6 = pa_socket_server_new_ipv6_string(m->core->mainloop, listen_on, (uint16_t) port, port_fallback, TCPWRAP_SERVICE); 276# endif 277 u->socket_server_ipv4 = pa_socket_server_new_ipv4_string(m->core->mainloop, listen_on, (uint16_t) port, port_fallback, TCPWRAP_SERVICE); 278 } else { 279# ifdef HAVE_IPV6 280 u->socket_server_ipv6 = pa_socket_server_new_ipv6_any(m->core->mainloop, (uint16_t) port, port_fallback, TCPWRAP_SERVICE); 281# endif 282 u->socket_server_ipv4 = pa_socket_server_new_ipv4_any(m->core->mainloop, (uint16_t) port, port_fallback, TCPWRAP_SERVICE); 283 } 284 285# ifdef HAVE_IPV6 286 if (!u->socket_server_ipv4 && !u->socket_server_ipv6) 287# else 288 if (!u->socket_server_ipv4) 289# endif 290 goto fail; 291 292 if (u->socket_server_ipv4) 293 pa_socket_server_set_callback(u->socket_server_ipv4, socket_server_on_connection_cb, u); 294# ifdef HAVE_IPV6 295 if (u->socket_server_ipv6) 296 pa_socket_server_set_callback(u->socket_server_ipv6, socket_server_on_connection_cb, u); 297# endif 298 299#else 300 301# if defined(USE_PROTOCOL_ESOUND) 302 303 /* Windows doesn't support getuid(), so we ignore the per-user Esound socket compile flag. 304 * Moreover, Esound Unix sockets haven't been supported on Windows historically. */ 305# if defined(USE_PER_USER_ESOUND_SOCKET) && !defined(OS_IS_WIN32) 306 u->socket_path = pa_sprintf_malloc("/tmp/.esd-%lu/socket", (unsigned long) getuid()); 307# else 308 u->socket_path = pa_xstrdup("/tmp/.esd/socket"); 309# endif 310 311 /* This socket doesn't reside in our own runtime dir but in 312 * /tmp/.esd/, hence we have to create the dir first */ 313 314 if (pa_make_secure_parent_dir(u->socket_path, pa_in_system_mode() ? 0755U : 0700U, (uid_t)-1, (gid_t)-1, false) < 0) { 315 pa_log("Failed to create socket directory '%s': %s\n", u->socket_path, pa_cstrerror(errno)); 316 goto fail; 317 } 318 319# else 320 if (!(u->socket_path = pa_runtime_path(pa_modargs_get_value(ma, "socket", UNIX_SOCKET)))) { 321 pa_log("Failed to generate socket path."); 322 goto fail; 323 } 324# endif 325 326 /* In ohos as socket is created by init, in pulseaudio we ignore the remove error 327 * due to lack of permission */ 328 if ((r = pa_unix_socket_remove_stale(u->socket_path)) < 0) { 329 pa_log("Failed to remove stale UNIX socket '%s': %s", u->socket_path, pa_cstrerror(errno)); 330 } else if (r > 0) 331 pa_log_info("Removed stale UNIX socket '%s'.", u->socket_path); 332 333 if (!(u->socket_server_unix = pa_socket_server_new_unix(m->core->mainloop, u->socket_path))) 334 goto fail; 335 336 pa_socket_server_set_callback(u->socket_server_unix, socket_server_on_connection_cb, u); 337 338#endif 339 340#if defined(USE_PROTOCOL_NATIVE) 341# if defined(USE_TCP_SOCKETS) 342 if (u->socket_server_ipv4) 343 if (pa_socket_server_get_address(u->socket_server_ipv4, t, sizeof(t))) 344 pa_native_protocol_add_server_string(u->native_protocol, t); 345 346# ifdef HAVE_IPV6 347 if (u->socket_server_ipv6) 348 if (pa_socket_server_get_address(u->socket_server_ipv6, t, sizeof(t))) 349 pa_native_protocol_add_server_string(u->native_protocol, t); 350# endif 351# else 352 if (pa_socket_server_get_address(u->socket_server_unix, t, sizeof(t))) 353 pa_native_protocol_add_server_string(u->native_protocol, t); 354 355# endif 356#endif 357 358#if defined(USE_PROTOCOL_HTTP) 359#if defined(USE_TCP_SOCKETS) 360 if (u->socket_server_ipv4) 361 if (pa_socket_server_get_address(u->socket_server_ipv4, t, sizeof(t))) 362 pa_http_protocol_add_server_string(u->http_protocol, t); 363 364#ifdef HAVE_IPV6 365 if (u->socket_server_ipv6) 366 if (pa_socket_server_get_address(u->socket_server_ipv6, t, sizeof(t))) 367 pa_http_protocol_add_server_string(u->http_protocol, t); 368#endif /* HAVE_IPV6 */ 369#else /* USE_TCP_SOCKETS */ 370 if (pa_socket_server_get_address(u->socket_server_unix, t, sizeof(t))) 371 pa_http_protocol_add_server_string(u->http_protocol, t); 372 373#endif /* USE_TCP_SOCKETS */ 374#endif /* USE_PROTOCOL_HTTP */ 375 376 if (ma) 377 pa_modargs_free(ma); 378 379 return 0; 380 381fail: 382 383 if (ma) 384 pa_modargs_free(ma); 385 386 pa__done(m); 387 388 return -1; 389} 390 391void pa__done(pa_module*m) { 392 struct userdata *u; 393 394 pa_assert(m); 395 396 if (!(u = m->userdata)) 397 return; 398 399#if defined(USE_PROTOCOL_SIMPLE) 400 if (u->simple_protocol) { 401 pa_simple_protocol_disconnect(u->simple_protocol, u->module); 402 pa_simple_protocol_unref(u->simple_protocol); 403 } 404 if (u->simple_options) 405 pa_simple_options_unref(u->simple_options); 406#elif defined(USE_PROTOCOL_CLI) 407 if (u->cli_protocol) { 408 pa_cli_protocol_disconnect(u->cli_protocol, u->module); 409 pa_cli_protocol_unref(u->cli_protocol); 410 } 411#elif defined(USE_PROTOCOL_HTTP) 412 if (u->http_protocol) { 413 char t[256]; 414 415#if defined(USE_TCP_SOCKETS) 416 if (u->socket_server_ipv4) 417 if (pa_socket_server_get_address(u->socket_server_ipv4, t, sizeof(t))) 418 pa_http_protocol_remove_server_string(u->http_protocol, t); 419 420#ifdef HAVE_IPV6 421 if (u->socket_server_ipv6) 422 if (pa_socket_server_get_address(u->socket_server_ipv6, t, sizeof(t))) 423 pa_http_protocol_remove_server_string(u->http_protocol, t); 424#endif /* HAVE_IPV6 */ 425#else /* USE_TCP_SOCKETS */ 426 if (u->socket_server_unix) 427 if (pa_socket_server_get_address(u->socket_server_unix, t, sizeof(t))) 428 pa_http_protocol_remove_server_string(u->http_protocol, t); 429#endif /* USE_PROTOCOL_HTTP */ 430 431 pa_http_protocol_disconnect(u->http_protocol, u->module); 432 pa_http_protocol_unref(u->http_protocol); 433 } 434#elif defined(USE_PROTOCOL_NATIVE) 435 if (u->native_protocol) { 436 437 char t[256]; 438 439# if defined(USE_TCP_SOCKETS) 440 if (u->socket_server_ipv4) 441 if (pa_socket_server_get_address(u->socket_server_ipv4, t, sizeof(t))) 442 pa_native_protocol_remove_server_string(u->native_protocol, t); 443 444# ifdef HAVE_IPV6 445 if (u->socket_server_ipv6) 446 if (pa_socket_server_get_address(u->socket_server_ipv6, t, sizeof(t))) 447 pa_native_protocol_remove_server_string(u->native_protocol, t); 448# endif 449# else 450 if (u->socket_server_unix) 451 if (pa_socket_server_get_address(u->socket_server_unix, t, sizeof(t))) 452 pa_native_protocol_remove_server_string(u->native_protocol, t); 453# endif 454 455 pa_native_protocol_disconnect(u->native_protocol, u->module); 456 pa_native_protocol_unref(u->native_protocol); 457 } 458 if (u->native_options) 459 pa_native_options_unref(u->native_options); 460#else 461 if (u->esound_protocol) { 462 pa_esound_protocol_disconnect(u->esound_protocol, u->module); 463 pa_esound_protocol_unref(u->esound_protocol); 464 } 465 if (u->esound_options) 466 pa_esound_options_unref(u->esound_options); 467#endif 468 469#if defined(USE_TCP_SOCKETS) 470 if (u->socket_server_ipv4) 471 pa_socket_server_unref(u->socket_server_ipv4); 472# ifdef HAVE_IPV6 473 if (u->socket_server_ipv6) 474 pa_socket_server_unref(u->socket_server_ipv6); 475# endif 476#else 477 if (u->socket_server_unix) 478 pa_socket_server_unref(u->socket_server_unix); 479 480# if defined(USE_PROTOCOL_ESOUND) && !defined(USE_PER_USER_ESOUND_SOCKET) 481 if (u->socket_path) { 482 char *p = pa_parent_dir(u->socket_path); 483 rmdir(p); 484 pa_xfree(p); 485 } 486# endif 487 488 pa_xfree(u->socket_path); 489#endif 490 491 pa_xfree(u); 492} 493