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
144 PA_MODULE_LOAD_ONCE(false);
145 PA_MODULE_AUTHOR("Lennart Poettering");
146 PA_MODULE_VERSION(PACKAGE_VERSION);
147
148 static 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
159 struct 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
socket_server_on_connection_cb(pa_socket_server * s,pa_iochannel * io,void * userdata)188 static 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
pa__init(pa_module * m)208 int 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 # if defined(USE_PER_USER_ESOUND_SOCKET)
304 u->socket_path = pa_sprintf_malloc("/tmp/.esd-%lu/socket", (unsigned long) getuid());
305 # else
306 u->socket_path = pa_xstrdup("/tmp/.esd/socket");
307 # endif
308
309 /* This socket doesn't reside in our own runtime dir but in
310 * /tmp/.esd/, hence we have to create the dir first */
311
312 if (pa_make_secure_parent_dir(u->socket_path, pa_in_system_mode() ? 0755U : 0700U, (uid_t)-1, (gid_t)-1, false) < 0) {
313 pa_log("Failed to create socket directory '%s': %s\n", u->socket_path, pa_cstrerror(errno));
314 goto fail;
315 }
316
317 # else
318 if (!(u->socket_path = pa_runtime_path(pa_modargs_get_value(ma, "socket", UNIX_SOCKET)))) {
319 pa_log("Failed to generate socket path.");
320 goto fail;
321 }
322 # endif
323
324 /* In ohos as socket is created by init, in pulseaudio we ignore the remove error
325 * due to lack of permission */
326 if ((r = pa_unix_socket_remove_stale(u->socket_path)) < 0) {
327 pa_log("Failed to remove stale UNIX socket '%s': %s", u->socket_path, pa_cstrerror(errno));
328 } else if (r > 0)
329 pa_log_info("Removed stale UNIX socket '%s'.", u->socket_path);
330
331 if (!(u->socket_server_unix = pa_socket_server_new_unix(m->core->mainloop, u->socket_path)))
332 goto fail;
333
334 pa_socket_server_set_callback(u->socket_server_unix, socket_server_on_connection_cb, u);
335
336 #endif
337
338 #if defined(USE_PROTOCOL_NATIVE)
339 # if defined(USE_TCP_SOCKETS)
340 if (u->socket_server_ipv4)
341 if (pa_socket_server_get_address(u->socket_server_ipv4, t, sizeof(t)))
342 pa_native_protocol_add_server_string(u->native_protocol, t);
343
344 # ifdef HAVE_IPV6
345 if (u->socket_server_ipv6)
346 if (pa_socket_server_get_address(u->socket_server_ipv6, t, sizeof(t)))
347 pa_native_protocol_add_server_string(u->native_protocol, t);
348 # endif
349 # else
350 if (pa_socket_server_get_address(u->socket_server_unix, t, sizeof(t)))
351 pa_native_protocol_add_server_string(u->native_protocol, t);
352
353 # endif
354 #endif
355
356 #if defined(USE_PROTOCOL_HTTP)
357 #if defined(USE_TCP_SOCKETS)
358 if (u->socket_server_ipv4)
359 if (pa_socket_server_get_address(u->socket_server_ipv4, t, sizeof(t)))
360 pa_http_protocol_add_server_string(u->http_protocol, t);
361
362 #ifdef HAVE_IPV6
363 if (u->socket_server_ipv6)
364 if (pa_socket_server_get_address(u->socket_server_ipv6, t, sizeof(t)))
365 pa_http_protocol_add_server_string(u->http_protocol, t);
366 #endif /* HAVE_IPV6 */
367 #else /* USE_TCP_SOCKETS */
368 if (pa_socket_server_get_address(u->socket_server_unix, t, sizeof(t)))
369 pa_http_protocol_add_server_string(u->http_protocol, t);
370
371 #endif /* USE_TCP_SOCKETS */
372 #endif /* USE_PROTOCOL_HTTP */
373
374 if (ma)
375 pa_modargs_free(ma);
376
377 return 0;
378
379 fail:
380
381 if (ma)
382 pa_modargs_free(ma);
383
384 pa__done(m);
385
386 return -1;
387 }
388
pa__done(pa_module * m)389 void pa__done(pa_module*m) {
390 struct userdata *u;
391
392 pa_assert(m);
393
394 if (!(u = m->userdata))
395 return;
396
397 #if defined(USE_PROTOCOL_SIMPLE)
398 if (u->simple_protocol) {
399 pa_simple_protocol_disconnect(u->simple_protocol, u->module);
400 pa_simple_protocol_unref(u->simple_protocol);
401 }
402 if (u->simple_options)
403 pa_simple_options_unref(u->simple_options);
404 #elif defined(USE_PROTOCOL_CLI)
405 if (u->cli_protocol) {
406 pa_cli_protocol_disconnect(u->cli_protocol, u->module);
407 pa_cli_protocol_unref(u->cli_protocol);
408 }
409 #elif defined(USE_PROTOCOL_HTTP)
410 if (u->http_protocol) {
411 char t[256];
412
413 #if defined(USE_TCP_SOCKETS)
414 if (u->socket_server_ipv4)
415 if (pa_socket_server_get_address(u->socket_server_ipv4, t, sizeof(t)))
416 pa_http_protocol_remove_server_string(u->http_protocol, t);
417
418 #ifdef HAVE_IPV6
419 if (u->socket_server_ipv6)
420 if (pa_socket_server_get_address(u->socket_server_ipv6, t, sizeof(t)))
421 pa_http_protocol_remove_server_string(u->http_protocol, t);
422 #endif /* HAVE_IPV6 */
423 #else /* USE_TCP_SOCKETS */
424 if (u->socket_server_unix)
425 if (pa_socket_server_get_address(u->socket_server_unix, t, sizeof(t)))
426 pa_http_protocol_remove_server_string(u->http_protocol, t);
427 #endif /* USE_PROTOCOL_HTTP */
428
429 pa_http_protocol_disconnect(u->http_protocol, u->module);
430 pa_http_protocol_unref(u->http_protocol);
431 }
432 #elif defined(USE_PROTOCOL_NATIVE)
433 if (u->native_protocol) {
434
435 char t[256];
436
437 # if defined(USE_TCP_SOCKETS)
438 if (u->socket_server_ipv4)
439 if (pa_socket_server_get_address(u->socket_server_ipv4, t, sizeof(t)))
440 pa_native_protocol_remove_server_string(u->native_protocol, t);
441
442 # ifdef HAVE_IPV6
443 if (u->socket_server_ipv6)
444 if (pa_socket_server_get_address(u->socket_server_ipv6, t, sizeof(t)))
445 pa_native_protocol_remove_server_string(u->native_protocol, t);
446 # endif
447 # else
448 if (u->socket_server_unix)
449 if (pa_socket_server_get_address(u->socket_server_unix, t, sizeof(t)))
450 pa_native_protocol_remove_server_string(u->native_protocol, t);
451 # endif
452
453 pa_native_protocol_disconnect(u->native_protocol, u->module);
454 pa_native_protocol_unref(u->native_protocol);
455 }
456 if (u->native_options)
457 pa_native_options_unref(u->native_options);
458 #else
459 if (u->esound_protocol) {
460 pa_esound_protocol_disconnect(u->esound_protocol, u->module);
461 pa_esound_protocol_unref(u->esound_protocol);
462 }
463 if (u->esound_options)
464 pa_esound_options_unref(u->esound_options);
465 #endif
466
467 #if defined(USE_TCP_SOCKETS)
468 if (u->socket_server_ipv4)
469 pa_socket_server_unref(u->socket_server_ipv4);
470 # ifdef HAVE_IPV6
471 if (u->socket_server_ipv6)
472 pa_socket_server_unref(u->socket_server_ipv6);
473 # endif
474 #else
475 if (u->socket_server_unix)
476 pa_socket_server_unref(u->socket_server_unix);
477
478 # if defined(USE_PROTOCOL_ESOUND) && !defined(USE_PER_USER_ESOUND_SOCKET)
479 if (u->socket_path) {
480 char *p = pa_parent_dir(u->socket_path);
481 rmdir(p);
482 pa_xfree(p);
483 }
484 # endif
485
486 pa_xfree(u->socket_path);
487 #endif
488
489 pa_xfree(u);
490 }
491