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