2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
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.
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.
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
33 #ifdef HAVE_SYS_SOCKET_H
34 #include <sys/socket.h>
36 #ifdef HAVE_ARPA_INET_H
37 #include <arpa/inet.h>
39 #ifdef HAVE_NETINET_IN_H
40 #include <netinet/in.h>
43 #include <pulse/xmalloc.h>
45 #include <pulsecore/winsock.h>
46 #include <pulsecore/core-error.h>
47 #include <pulsecore/module.h>
48 #include <pulsecore/socket-server.h>
49 #include <pulsecore/socket-util.h>
50 #include <pulsecore/core-util.h>
51 #include <pulsecore/modargs.h>
52 #include <pulsecore/log.h>
53 #include <pulsecore/native-common.h>
54 #include <pulsecore/creds.h>
56 #ifdef USE_TCP_SOCKETS
57 #define SOCKET_DESCRIPTION "(TCP sockets)"
58 #define SOCKET_USAGE "port=<TCP port number> listen=<address to listen on>"
60 #define SOCKET_DESCRIPTION "(UNIX sockets)"
61 #define SOCKET_USAGE "socket=<path to UNIX socket>"
64 #if defined(USE_PROTOCOL_SIMPLE)
65 # include <pulsecore/protocol-simple.h>
66 # define TCPWRAP_SERVICE "pulseaudio-simple"
67 # define IPV4_PORT 4711
68 # define UNIX_SOCKET "simple"
69 # define MODULE_ARGUMENTS "rate", "format", "channels", "sink", "source", "playback", "record",
71 # if defined(USE_TCP_SOCKETS)
72 # include "module-simple-protocol-tcp-symdef.h"
74 # include "module-simple-protocol-unix-symdef.h"
77 PA_MODULE_DESCRIPTION("Simple protocol "SOCKET_DESCRIPTION);
78 PA_MODULE_USAGE("rate=<sample rate> "
79 "format=<sample format> "
80 "channels=<number of channels> "
81 "sink=<sink to connect to> "
82 "source=<source to connect to> "
83 "playback=<enable playback?> "
84 "record=<enable record?> "
86 #elif defined(USE_PROTOCOL_CLI)
87 # include <pulsecore/protocol-cli.h>
88 # define TCPWRAP_SERVICE "pulseaudio-cli"
89 # define IPV4_PORT 4712
90 # define UNIX_SOCKET "cli"
91 # define MODULE_ARGUMENTS
93 # ifdef USE_TCP_SOCKETS
94 # include "module-cli-protocol-tcp-symdef.h"
96 # include "module-cli-protocol-unix-symdef.h"
99 PA_MODULE_DESCRIPTION("Command line interface protocol "SOCKET_DESCRIPTION);
100 PA_MODULE_USAGE(SOCKET_USAGE);
101 #elif defined(USE_PROTOCOL_HTTP)
102 # include <pulsecore/protocol-http.h>
103 # define TCPWRAP_SERVICE "pulseaudio-http"
104 # define IPV4_PORT 4714
105 # define UNIX_SOCKET "http"
106 # define MODULE_ARGUMENTS
108 # ifdef USE_TCP_SOCKETS
109 # include "module-http-protocol-tcp-symdef.h"
111 # include "module-http-protocol-unix-symdef.h"
114 PA_MODULE_DESCRIPTION("HTTP "SOCKET_DESCRIPTION);
115 PA_MODULE_USAGE(SOCKET_USAGE);
116 #elif defined(USE_PROTOCOL_NATIVE)
117 # include <pulsecore/protocol-native.h>
118 # define TCPWRAP_SERVICE "pulseaudio-native"
119 # define IPV4_PORT PA_NATIVE_DEFAULT_PORT
120 # define UNIX_SOCKET PA_NATIVE_DEFAULT_UNIX_SOCKET
121 # define MODULE_ARGUMENTS_COMMON "cookie", "auth-cookie", "auth-cookie-enabled", "auth-anonymous",
123 # ifdef USE_TCP_SOCKETS
124 # include "module-native-protocol-tcp-symdef.h"
126 # include "module-native-protocol-unix-symdef.h"
129 # if defined(HAVE_CREDS) && !defined(USE_TCP_SOCKETS)
130 # define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON "auth-group", "auth-group-enable",
131 # define AUTH_USAGE "auth-group=<system group to allow access> auth-group-enable=<enable auth by UNIX group?> "
132 # elif defined(USE_TCP_SOCKETS)
133 # define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON "auth-ip-acl",
134 # define AUTH_USAGE "auth-ip-acl=<IP address ACL to allow access> "
136 # define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON
140 PA_MODULE_DESCRIPTION("Native protocol "SOCKET_DESCRIPTION);
141 PA_MODULE_USAGE("auth-anonymous=<don't check for cookies?> "
142 "auth-cookie=<path to cookie file> "
143 "auth-cookie-enabled=<enable cookie authentification? "
146 #elif defined(USE_PROTOCOL_ESOUND)
147 # include <pulsecore/protocol-esound.h>
148 # include <pulsecore/esound.h>
149 # define TCPWRAP_SERVICE "esound"
150 # define IPV4_PORT ESD_DEFAULT_PORT
151 # define MODULE_ARGUMENTS_COMMON "sink", "source", "auth-anonymous", "cookie", "auth-cookie", "auth-cookie-enabled",
153 # ifdef USE_TCP_SOCKETS
154 # include "module-esound-protocol-tcp-symdef.h"
156 # include "module-esound-protocol-unix-symdef.h"
159 # if defined(USE_TCP_SOCKETS)
160 # define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON "auth-ip-acl",
161 # define AUTH_USAGE "auth-ip-acl=<IP address ACL to allow access> "
163 # define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON
167 PA_MODULE_DESCRIPTION("ESOUND protocol "SOCKET_DESCRIPTION);
168 PA_MODULE_USAGE("sink=<sink to connect to> "
169 "source=<source to connect to> "
170 "auth-anonymous=<don't verify cookies?> "
171 "auth-cookie=<path to cookie file> "
172 "auth-cookie-enabled=<enable cookie authentification? "
176 # error "Broken build system"
179 PA_MODULE_LOAD_ONCE(FALSE);
180 PA_MODULE_AUTHOR("Lennart Poettering");
181 PA_MODULE_VERSION(PACKAGE_VERSION);
183 static const char* const valid_modargs[] = {
185 #if defined(USE_TCP_SOCKETS)
197 #if defined(USE_PROTOCOL_SIMPLE)
198 pa_simple_protocol *simple_protocol;
199 pa_simple_options *simple_options;
200 #elif defined(USE_PROTOCOL_CLI)
201 pa_cli_protocol *cli_protocol;
202 #elif defined(USE_PROTOCOL_HTTP)
203 pa_http_protocol *http_protocol;
204 #elif defined(USE_PROTOCOL_NATIVE)
205 pa_native_protocol *native_protocol;
206 pa_native_options *native_options;
208 pa_esound_protocol *esound_protocol;
209 pa_esound_options *esound_options;
212 #if defined(USE_TCP_SOCKETS)
213 pa_socket_server *socket_server_ipv4;
215 pa_socket_server *socket_server_ipv6;
218 pa_socket_server *socket_server_unix;
223 static void socket_server_on_connection_cb(pa_socket_server*s, pa_iochannel *io, void *userdata) {
224 struct userdata *u = userdata;
230 #if defined(USE_PROTOCOL_SIMPLE)
231 pa_simple_protocol_connect(u->simple_protocol, io, u->simple_options);
232 #elif defined(USE_PROTOCOL_CLI)
233 pa_cli_protocol_connect(u->cli_protocol, io, u->module);
234 #elif defined(USE_PROTOCOL_HTTP)
235 pa_http_protocol_connect(u->http_protocol, io, u->module);
236 #elif defined(USE_PROTOCOL_NATIVE)
237 pa_native_protocol_connect(u->native_protocol, io, u->native_options);
239 pa_esound_protocol_connect(u->esound_protocol, io, u->esound_options);
243 int pa__init(pa_module*m) {
244 pa_modargs *ma = NULL;
245 struct userdata *u = NULL;
247 #if defined(USE_TCP_SOCKETS)
248 uint32_t port = IPV4_PORT;
249 pa_bool_t port_fallback = TRUE;
250 const char *listen_on;
255 #if defined(USE_PROTOCOL_NATIVE) || defined(USE_PROTOCOL_HTTP)
261 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
262 pa_log("Failed to parse module arguments");
266 m->userdata = u = pa_xnew0(struct userdata, 1);
269 #if defined(USE_PROTOCOL_SIMPLE)
270 u->simple_protocol = pa_simple_protocol_get(m->core);
272 u->simple_options = pa_simple_options_new();
273 if (pa_simple_options_parse(u->simple_options, m->core, ma) < 0)
275 u->simple_options->module = m;
276 #elif defined(USE_PROTOCOL_CLI)
277 u->cli_protocol = pa_cli_protocol_get(m->core);
278 #elif defined(USE_PROTOCOL_HTTP)
279 u->http_protocol = pa_http_protocol_get(m->core);
280 #elif defined(USE_PROTOCOL_NATIVE)
281 u->native_protocol = pa_native_protocol_get(m->core);
283 u->native_options = pa_native_options_new();
284 if (pa_native_options_parse(u->native_options, m->core, ma) < 0)
286 u->native_options->module = m;
288 u->esound_protocol = pa_esound_protocol_get(m->core);
290 u->esound_options = pa_esound_options_new();
291 if (pa_esound_options_parse(u->esound_options, m->core, ma) < 0)
293 u->esound_options->module = m;
296 #if defined(USE_TCP_SOCKETS)
298 if (pa_in_system_mode() || pa_modargs_get_value(ma, "port", NULL))
299 port_fallback = FALSE;
301 if (pa_modargs_get_value_u32(ma, "port", &port) < 0 || port < 1 || port > 0xFFFF) {
302 pa_log("port= expects a numerical argument between 1 and 65535.");
306 listen_on = pa_modargs_get_value(ma, "listen", NULL);
310 u->socket_server_ipv6 = pa_socket_server_new_ipv6_string(m->core->mainloop, listen_on, (uint16_t) port, port_fallback, TCPWRAP_SERVICE);
312 u->socket_server_ipv4 = pa_socket_server_new_ipv4_string(m->core->mainloop, listen_on, (uint16_t) port, port_fallback, TCPWRAP_SERVICE);
315 u->socket_server_ipv6 = pa_socket_server_new_ipv6_any(m->core->mainloop, (uint16_t) port, port_fallback, TCPWRAP_SERVICE);
317 u->socket_server_ipv4 = pa_socket_server_new_ipv4_any(m->core->mainloop, (uint16_t) port, port_fallback, TCPWRAP_SERVICE);
321 if (!u->socket_server_ipv4 && !u->socket_server_ipv6)
323 if (!u->socket_server_ipv4)
327 if (u->socket_server_ipv4)
328 pa_socket_server_set_callback(u->socket_server_ipv4, socket_server_on_connection_cb, u);
330 if (u->socket_server_ipv6)
331 pa_socket_server_set_callback(u->socket_server_ipv6, socket_server_on_connection_cb, u);
336 # if defined(USE_PROTOCOL_ESOUND)
338 # if defined(USE_PER_USER_ESOUND_SOCKET)
339 u->socket_path = pa_sprintf_malloc("/tmp/.esd-%lu/socket", (unsigned long) getuid());
341 u->socket_path = pa_xstrdup("/tmp/.esd/socket");
344 /* This socket doesn't reside in our own runtime dir but in
345 * /tmp/.esd/, hence we have to create the dir first */
347 if (pa_make_secure_parent_dir(u->socket_path, pa_in_system_mode() ? 0755U : 0700U, (uid_t)-1, (gid_t)-1) < 0) {
348 pa_log("Failed to create socket directory '%s': %s\n", u->socket_path, pa_cstrerror(errno));
353 if (!(u->socket_path = pa_runtime_path(pa_modargs_get_value(ma, "socket", UNIX_SOCKET)))) {
354 pa_log("Failed to generate socket path.");
359 if ((r = pa_unix_socket_remove_stale(u->socket_path)) < 0) {
360 pa_log("Failed to remove stale UNIX socket '%s': %s", u->socket_path, pa_cstrerror(errno));
363 pa_log_info("Removed stale UNIX socket '%s'.", u->socket_path);
365 if (!(u->socket_server_unix = pa_socket_server_new_unix(m->core->mainloop, u->socket_path)))
368 pa_socket_server_set_callback(u->socket_server_unix, socket_server_on_connection_cb, u);
372 #if defined(USE_PROTOCOL_NATIVE)
373 # if defined(USE_TCP_SOCKETS)
374 if (u->socket_server_ipv4)
375 if (pa_socket_server_get_address(u->socket_server_ipv4, t, sizeof(t)))
376 pa_native_protocol_add_server_string(u->native_protocol, t);
379 if (u->socket_server_ipv6)
380 if (pa_socket_server_get_address(u->socket_server_ipv6, t, sizeof(t)))
381 pa_native_protocol_add_server_string(u->native_protocol, t);
384 if (pa_socket_server_get_address(u->socket_server_unix, t, sizeof(t)))
385 pa_native_protocol_add_server_string(u->native_protocol, t);
390 #if defined(USE_PROTOCOL_HTTP)
391 #if defined(USE_TCP_SOCKETS)
392 if (u->socket_server_ipv4)
393 if (pa_socket_server_get_address(u->socket_server_ipv4, t, sizeof(t)))
394 pa_http_protocol_add_server_string(u->http_protocol, t);
397 if (u->socket_server_ipv6)
398 if (pa_socket_server_get_address(u->socket_server_ipv6, t, sizeof(t)))
399 pa_http_protocol_add_server_string(u->http_protocol, t);
400 #endif /* HAVE_IPV6 */
401 #else /* USE_TCP_SOCKETS */
402 if (pa_socket_server_get_address(u->socket_server_unix, t, sizeof(t)))
403 pa_http_protocol_add_server_string(u->http_protocol, t);
405 #endif /* USE_TCP_SOCKETS */
406 #endif /* USE_PROTOCOL_HTTP */
423 void pa__done(pa_module*m) {
428 if (!(u = m->userdata))
431 #if defined(USE_PROTOCOL_SIMPLE)
432 if (u->simple_protocol) {
433 pa_simple_protocol_disconnect(u->simple_protocol, u->module);
434 pa_simple_protocol_unref(u->simple_protocol);
436 if (u->simple_options)
437 pa_simple_options_unref(u->simple_options);
438 #elif defined(USE_PROTOCOL_CLI)
439 if (u->cli_protocol) {
440 pa_cli_protocol_disconnect(u->cli_protocol, u->module);
441 pa_cli_protocol_unref(u->cli_protocol);
443 #elif defined(USE_PROTOCOL_HTTP)
444 if (u->http_protocol) {
447 #if defined(USE_TCP_SOCKETS)
448 if (u->socket_server_ipv4)
449 if (pa_socket_server_get_address(u->socket_server_ipv4, t, sizeof(t)))
450 pa_http_protocol_remove_server_string(u->http_protocol, t);
453 if (u->socket_server_ipv6)
454 if (pa_socket_server_get_address(u->socket_server_ipv6, t, sizeof(t)))
455 pa_http_protocol_remove_server_string(u->http_protocol, t);
456 #endif /* HAVE_IPV6 */
457 #else /* USE_TCP_SOCKETS */
458 if (u->socket_server_unix)
459 if (pa_socket_server_get_address(u->socket_server_unix, t, sizeof(t)))
460 pa_http_protocol_remove_server_string(u->http_protocol, t);
461 #endif /* USE_PROTOCOL_HTTP */
463 pa_http_protocol_disconnect(u->http_protocol, u->module);
464 pa_http_protocol_unref(u->http_protocol);
466 #elif defined(USE_PROTOCOL_NATIVE)
467 if (u->native_protocol) {
471 # if defined(USE_TCP_SOCKETS)
472 if (u->socket_server_ipv4)
473 if (pa_socket_server_get_address(u->socket_server_ipv4, t, sizeof(t)))
474 pa_native_protocol_remove_server_string(u->native_protocol, t);
477 if (u->socket_server_ipv6)
478 if (pa_socket_server_get_address(u->socket_server_ipv6, t, sizeof(t)))
479 pa_native_protocol_remove_server_string(u->native_protocol, t);
482 if (u->socket_server_unix)
483 if (pa_socket_server_get_address(u->socket_server_unix, t, sizeof(t)))
484 pa_native_protocol_remove_server_string(u->native_protocol, t);
487 pa_native_protocol_disconnect(u->native_protocol, u->module);
488 pa_native_protocol_unref(u->native_protocol);
490 if (u->native_options)
491 pa_native_options_unref(u->native_options);
493 if (u->esound_protocol) {
494 pa_esound_protocol_disconnect(u->esound_protocol, u->module);
495 pa_esound_protocol_unref(u->esound_protocol);
497 if (u->esound_options)
498 pa_esound_options_unref(u->esound_options);
501 #if defined(USE_TCP_SOCKETS)
502 if (u->socket_server_ipv4)
503 pa_socket_server_unref(u->socket_server_ipv4);
505 if (u->socket_server_ipv6)
506 pa_socket_server_unref(u->socket_server_ipv6);
509 if (u->socket_server_unix)
510 pa_socket_server_unref(u->socket_server_unix);
512 # if defined(USE_PROTOCOL_ESOUND) && !defined(USE_PER_USER_ESOUND_SOCKET)
513 if (u->socket_path) {
514 char *p = pa_parent_dir(u->socket_path);
520 pa_xfree(u->socket_path);