daemon: Implement the DBus server lookup service.

This commit is contained in:
Tanu Kaskinen 2009-06-12 07:16:05 +03:00
parent c94e7421aa
commit 5babbaafb2
10 changed files with 490 additions and 37 deletions

View file

@ -135,13 +135,14 @@ BUILT_SOURCES = \
bin_PROGRAMS = pulseaudio bin_PROGRAMS = pulseaudio
pulseaudio_SOURCES = \ pulseaudio_SOURCES = \
daemon/caps.h daemon/caps.c \ daemon/caps.c daemon/caps.h \
daemon/cmdline.c daemon/cmdline.h \ daemon/cmdline.c daemon/cmdline.h \
daemon/cpulimit.c daemon/cpulimit.h \ daemon/cpulimit.c daemon/cpulimit.h \
daemon/daemon-conf.c daemon/daemon-conf.h \ daemon/daemon-conf.c daemon/daemon-conf.h \
daemon/dumpmodules.c daemon/dumpmodules.h \ daemon/dumpmodules.c daemon/dumpmodules.h \
daemon/ltdl-bind-now.c daemon/ltdl-bind-now.h \ daemon/ltdl-bind-now.c daemon/ltdl-bind-now.h \
daemon/main.c daemon/main.c \
daemon/server-lookup.c daemon/server-lookup.h
pulseaudio_CFLAGS = $(AM_CFLAGS) $(LIBOIL_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSPEEX_CFLAGS) $(LIBSNDFILE_CFLAGS) $(CAP_CFLAGS) $(LIBOIL_CFLAGS) $(DBUS_CFLAGS) pulseaudio_CFLAGS = $(AM_CFLAGS) $(LIBOIL_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSPEEX_CFLAGS) $(LIBSNDFILE_CFLAGS) $(CAP_CFLAGS) $(LIBOIL_CFLAGS) $(DBUS_CFLAGS)
pulseaudio_LDADD = $(AM_LDADD) libpulsecore-@PA_MAJORMINORMICRO@.la libpulsecommon-@PA_MAJORMINORMICRO@.la libpulse.la $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSPEEX_LIBS) $(LIBSNDFILE_LIBS) $(CAP_LIBS) $(LIBOIL_LIBS) $(DBUS_LIBS) pulseaudio_LDADD = $(AM_LDADD) libpulsecore-@PA_MAJORMINORMICRO@.la libpulsecommon-@PA_MAJORMINORMICRO@.la libpulse.la $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSPEEX_LIBS) $(LIBSNDFILE_LIBS) $(CAP_LIBS) $(LIBOIL_LIBS) $(DBUS_LIBS)

View file

@ -83,6 +83,9 @@ static const pa_daemon_conf default_conf = {
.config_file = NULL, .config_file = NULL,
.use_pid_file = TRUE, .use_pid_file = TRUE,
.system_instance = FALSE, .system_instance = FALSE,
#ifdef HAVE_DBUS
.local_server_type = PA_SERVER_TYPE_UNSET, /* The actual default is _USER, but we have to detect when the user doesn't specify this option. */
#endif
.no_cpu_limit = FALSE, .no_cpu_limit = FALSE,
.disable_shm = FALSE, .disable_shm = FALSE,
.default_n_fragments = 4, .default_n_fragments = 4,
@ -203,6 +206,22 @@ int pa_daemon_conf_set_resample_method(pa_daemon_conf *c, const char *string) {
return 0; return 0;
} }
int pa_daemon_conf_set_local_server_type(pa_daemon_conf *c, const char *string) {
pa_assert(c);
pa_assert(string);
if (!strcmp(string, "user"))
c->local_server_type = PA_SERVER_TYPE_USER;
else if (!strcmp(string, "system")) {
c->local_server_type = PA_SERVER_TYPE_SYSTEM;
} else if (!strcmp(string, "none")) {
c->local_server_type = PA_SERVER_TYPE_NONE;
} else
return -1;
return 0;
}
static int parse_log_target(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) { static int parse_log_target(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) {
pa_daemon_conf *c = data; pa_daemon_conf *c = data;
@ -430,6 +449,22 @@ static int parse_rtprio(const char *filename, unsigned line, const char *section
return 0; return 0;
} }
static int parse_server_type(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) {
pa_daemon_conf *c = data;
pa_assert(filename);
pa_assert(lvalue);
pa_assert(rvalue);
pa_assert(data);
if (pa_daemon_conf_set_local_server_type(c, rvalue) < 0) {
pa_log(_("[%s:%u] Invalid server type '%s'."), filename, line, rvalue);
return -1;
}
return 0;
}
int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) {
int r = -1; int r = -1;
FILE *f = NULL; FILE *f = NULL;
@ -443,6 +478,9 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) {
{ "disallow-exit", pa_config_parse_bool, &c->disallow_exit, NULL }, { "disallow-exit", pa_config_parse_bool, &c->disallow_exit, NULL },
{ "use-pid-file", pa_config_parse_bool, &c->use_pid_file, NULL }, { "use-pid-file", pa_config_parse_bool, &c->use_pid_file, NULL },
{ "system-instance", pa_config_parse_bool, &c->system_instance, NULL }, { "system-instance", pa_config_parse_bool, &c->system_instance, NULL },
#ifdef HAVE_DBUS
{ "local-server-type", parse_server_type, c, NULL },
#endif
{ "no-cpu-limit", pa_config_parse_bool, &c->no_cpu_limit, NULL }, { "no-cpu-limit", pa_config_parse_bool, &c->no_cpu_limit, NULL },
{ "disable-shm", pa_config_parse_bool, &c->disable_shm, NULL }, { "disable-shm", pa_config_parse_bool, &c->disable_shm, NULL },
{ "flat-volumes", pa_config_parse_bool, &c->flat_volumes, NULL }, { "flat-volumes", pa_config_parse_bool, &c->flat_volumes, NULL },
@ -604,6 +642,13 @@ static const char* const log_level_to_string[] = {
[PA_LOG_ERROR] = "error" [PA_LOG_ERROR] = "error"
}; };
static const char* const server_type_to_string[] = {
[PA_SERVER_TYPE_UNSET] = "!!UNSET!!",
[PA_SERVER_TYPE_USER] = "user",
[PA_SERVER_TYPE_SYSTEM] = "system",
[PA_SERVER_TYPE_NONE] = "none"
};
char *pa_daemon_conf_dump(pa_daemon_conf *c) { char *pa_daemon_conf_dump(pa_daemon_conf *c) {
pa_strbuf *s; pa_strbuf *s;
char cm[PA_CHANNEL_MAP_SNPRINT_MAX]; char cm[PA_CHANNEL_MAP_SNPRINT_MAX];
@ -627,6 +672,9 @@ char *pa_daemon_conf_dump(pa_daemon_conf *c) {
pa_strbuf_printf(s, "disallow-exit = %s\n", pa_yes_no(c->disallow_exit)); pa_strbuf_printf(s, "disallow-exit = %s\n", pa_yes_no(c->disallow_exit));
pa_strbuf_printf(s, "use-pid-file = %s\n", pa_yes_no(c->use_pid_file)); pa_strbuf_printf(s, "use-pid-file = %s\n", pa_yes_no(c->use_pid_file));
pa_strbuf_printf(s, "system-instance = %s\n", pa_yes_no(c->system_instance)); pa_strbuf_printf(s, "system-instance = %s\n", pa_yes_no(c->system_instance));
#ifdef HAVE_DBUS
pa_strbuf_printf(s, "local-server-type = %s\n", server_type_to_string[c->local_server_type]);
#endif
pa_strbuf_printf(s, "no-cpu-limit = %s\n", pa_yes_no(c->no_cpu_limit)); pa_strbuf_printf(s, "no-cpu-limit = %s\n", pa_yes_no(c->no_cpu_limit));
pa_strbuf_printf(s, "disable-shm = %s\n", pa_yes_no(c->disable_shm)); pa_strbuf_printf(s, "disable-shm = %s\n", pa_yes_no(c->disable_shm));
pa_strbuf_printf(s, "flat-volumes = %s\n", pa_yes_no(c->flat_volumes)); pa_strbuf_printf(s, "flat-volumes = %s\n", pa_yes_no(c->flat_volumes));

View file

@ -48,6 +48,13 @@ typedef enum pa_daemon_conf_cmd {
PA_CMD_CLEANUP_SHM PA_CMD_CLEANUP_SHM
} pa_daemon_conf_cmd_t; } pa_daemon_conf_cmd_t;
typedef enum pa_daemon_conf_server_type {
PA_SERVER_TYPE_UNSET,
PA_SERVER_TYPE_USER,
PA_SERVER_TYPE_SYSTEM,
PA_SERVER_TYPE_NONE
} pa_daemon_conf_server_type_t;
#ifdef HAVE_SYS_RESOURCE_H #ifdef HAVE_SYS_RESOURCE_H
typedef struct pa_rlimit { typedef struct pa_rlimit {
rlim_t value; rlim_t value;
@ -74,6 +81,7 @@ typedef struct pa_daemon_conf {
log_meta, log_meta,
log_time, log_time,
flat_volumes; flat_volumes;
pa_daemon_conf_server_type_t local_server_type;
int exit_idle_time, int exit_idle_time,
scache_idle_time, scache_idle_time,
auto_log_target, auto_log_target,
@ -151,6 +159,7 @@ int pa_daemon_conf_env(pa_daemon_conf *c);
int pa_daemon_conf_set_log_target(pa_daemon_conf *c, const char *string); int pa_daemon_conf_set_log_target(pa_daemon_conf *c, const char *string);
int pa_daemon_conf_set_log_level(pa_daemon_conf *c, const char *string); int pa_daemon_conf_set_log_level(pa_daemon_conf *c, const char *string);
int pa_daemon_conf_set_resample_method(pa_daemon_conf *c, const char *string); int pa_daemon_conf_set_resample_method(pa_daemon_conf *c, const char *string);
int pa_daemon_conf_set_local_server_type(pa_daemon_conf *c, const char *string);
const char *pa_daemon_conf_get_default_script_file(pa_daemon_conf *c); const char *pa_daemon_conf_get_default_script_file(pa_daemon_conf *c);
FILE *pa_daemon_conf_open_default_script_file(pa_daemon_conf *c); FILE *pa_daemon_conf_open_default_script_file(pa_daemon_conf *c);

View file

@ -25,6 +25,7 @@
; disallow-exit = no ; disallow-exit = no
; use-pid-file = yes ; use-pid-file = yes
; system-instance = no ; system-instance = no
; local-server-type = user
; disable-shm = no ; disable-shm = no
; shm-size-bytes = 0 # setting this 0 will use the system-default, usually 64 MiB ; shm-size-bytes = 0 # setting this 0 will use the system-default, usually 64 MiB

View file

@ -99,6 +99,7 @@
#include "caps.h" #include "caps.h"
#include "ltdl-bind-now.h" #include "ltdl-bind-now.h"
#include "polkit.h" #include "polkit.h"
#include "server-lookup.h"
#ifdef HAVE_LIBWRAP #ifdef HAVE_LIBWRAP
/* Only one instance of these variables */ /* Only one instance of these variables */
@ -335,33 +336,31 @@ static void set_all_rlimits(const pa_daemon_conf *conf) {
#endif #endif
#ifdef HAVE_DBUS #ifdef HAVE_DBUS
static pa_dbus_connection *register_dbus(pa_core *c) { static pa_dbus_connection *register_dbus_name(pa_core *c, DBusBusType bus, const char* name) {
DBusError error; DBusError error;
pa_dbus_connection *conn; pa_dbus_connection *conn;
dbus_error_init(&error); dbus_error_init(&error);
if (!(conn = pa_dbus_bus_get(c, pa_in_system_mode() ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, &error)) || dbus_error_is_set(&error)) { if (!(conn = pa_dbus_bus_get(c, bus, &error)) || dbus_error_is_set(&error)) {
pa_log_warn("Unable to contact D-Bus: %s: %s", error.name, error.message); pa_log_warn("Unable to contact D-Bus: %s: %s", error.name, error.message);
goto fail; goto fail;
} }
if (dbus_bus_request_name(pa_dbus_connection_get(conn), "org.pulseaudio.Server", DBUS_NAME_FLAG_DO_NOT_QUEUE, &error) == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { if (dbus_bus_request_name(pa_dbus_connection_get(conn), name, DBUS_NAME_FLAG_DO_NOT_QUEUE, &error) == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
pa_log_debug("Got org.pulseaudio.Server!"); pa_log_debug("Got %s!", name);
return conn; return conn;
} }
if (dbus_error_is_set(&error)) if (dbus_error_is_set(&error))
pa_log_warn("Failed to acquire org.pulseaudio.Server: %s: %s", error.name, error.message); pa_log_error("Failed to acquire %s: %s: %s", name, error.name, error.message);
else else
pa_log_warn("D-Bus name org.pulseaudio.Server already taken. Weird shit!"); pa_log_error("D-Bus name %s already taken. Weird shit!", name);
/* PA cannot be started twice by the same user and hence we can /* PA cannot be started twice by the same user and hence we can
* ignore mostly the case that org.pulseaudio.Server is already * ignore mostly the case that a name is already taken. */
* taken. */
fail: fail:
if (conn) if (conn)
pa_dbus_connection_unref(conn); pa_dbus_connection_unref(conn);
@ -393,7 +392,10 @@ int main(int argc, char *argv[]) {
int autospawn_fd = -1; int autospawn_fd = -1;
pa_bool_t autospawn_locked = FALSE; pa_bool_t autospawn_locked = FALSE;
#ifdef HAVE_DBUS #ifdef HAVE_DBUS
pa_dbus_connection *dbus = NULL; pa_dbusobj_server_lookup *server_lookup = NULL; /* /org/pulseaudio/server_lookup */
pa_dbus_connection *lookup_service_bus = NULL; /* Always the user bus. */
pa_dbus_connection *server_bus = NULL; /* The bus where we reserve org.pulseaudio.Server, either the user or the system bus. */
pa_bool_t start_server;
#endif #endif
pa_log_set_ident("pulseaudio"); pa_log_set_ident("pulseaudio");
@ -486,8 +488,45 @@ int main(int argc, char *argv[]) {
pa_log_set_flags(PA_LOG_PRINT_TIME, PA_LOG_SET); pa_log_set_flags(PA_LOG_PRINT_TIME, PA_LOG_SET);
pa_log_set_show_backtrace(conf->log_backtrace); pa_log_set_show_backtrace(conf->log_backtrace);
#ifdef HAVE_DBUS
/* conf->system_instance and conf->local_server_type control almost the
* same thing; make them agree about what is requested. */
switch (conf->local_server_type) {
case PA_SERVER_TYPE_UNSET:
conf->local_server_type = conf->system_instance ? PA_SERVER_TYPE_SYSTEM : PA_SERVER_TYPE_USER;
break;
case PA_SERVER_TYPE_USER:
case PA_SERVER_TYPE_NONE:
conf->system_instance = FALSE;
break;
case PA_SERVER_TYPE_SYSTEM:
conf->system_instance = TRUE;
break;
default:
pa_assert_not_reached();
}
start_server = conf->local_server_type == PA_SERVER_TYPE_USER || (real_root && conf->local_server_type == PA_SERVER_TYPE_SYSTEM);
if (!start_server && conf->local_server_type == PA_SERVER_TYPE_SYSTEM) {
pa_log_notice(_("System mode refused for non-root user. Only starting the D-Bus server lookup service."));
conf->system_instance = FALSE;
}
#endif
pa_log_debug("Started as real root: %s, suid root: %s", pa_yes_no(real_root), pa_yes_no(suid_root)); pa_log_debug("Started as real root: %s, suid root: %s", pa_yes_no(real_root), pa_yes_no(suid_root));
#ifdef HAVE_DBUS
/* XXX: Uhh, goto programming... as if this wasn't hard enough to follow
* already. But if we won't start the full server, we want to just skip all
* the capability stuff. */
if (!start_server) {
if (!real_root && pa_have_caps())
pa_drop_caps();
goto after_caps_setup;
}
#endif
if (!real_root && pa_have_caps()) { if (!real_root && pa_have_caps()) {
#ifdef HAVE_SYS_RESOURCE_H #ifdef HAVE_SYS_RESOURCE_H
struct rlimit rl; struct rlimit rl;
@ -628,6 +667,10 @@ int main(int argc, char *argv[]) {
conf->realtime_scheduling = FALSE; conf->realtime_scheduling = FALSE;
} }
#ifdef HAVE_DBUS
after_caps_setup:
#endif
pa_log_debug("Can realtime: %s, can high-priority: %s", pa_yes_no(pa_can_realtime()), pa_yes_no(pa_can_high_priority())); pa_log_debug("Can realtime: %s, can high-priority: %s", pa_yes_no(pa_can_realtime()), pa_yes_no(pa_can_high_priority()));
LTDL_SET_PRELOADED_SYMBOLS(); LTDL_SET_PRELOADED_SYMBOLS();
@ -716,10 +759,12 @@ int main(int argc, char *argv[]) {
if (real_root && !conf->system_instance) if (real_root && !conf->system_instance)
pa_log_warn(_("This program is not intended to be run as root (unless --system is specified).")); pa_log_warn(_("This program is not intended to be run as root (unless --system is specified)."));
#ifndef HAVE_DBUS /* A similar, only a notice worthy check was done earlier, if D-Bus is enabled. */
else if (!real_root && conf->system_instance) { else if (!real_root && conf->system_instance) {
pa_log(_("Root privileges required.")); pa_log(_("Root privileges required."));
goto finish; goto finish;
} }
#endif
if (conf->cmd == PA_CMD_START && conf->system_instance) { if (conf->cmd == PA_CMD_START && conf->system_instance) {
pa_log(_("--start not supported for system instances.")); pa_log(_("--start not supported for system instances."));
@ -1007,6 +1052,10 @@ int main(int argc, char *argv[]) {
pa_assert_se(pa_cpu_limit_init(pa_mainloop_get_api(mainloop)) == 0); pa_assert_se(pa_cpu_limit_init(pa_mainloop_get_api(mainloop)) == 0);
buf = pa_strbuf_new(); buf = pa_strbuf_new();
#ifdef HAVE_DBUS
if (start_server) {
#endif
if (conf->load_default_script_file) { if (conf->load_default_script_file) {
FILE *f; FILE *f;
@ -1022,10 +1071,6 @@ int main(int argc, char *argv[]) {
pa_log_error("%s", s = pa_strbuf_tostring_free(buf)); pa_log_error("%s", s = pa_strbuf_tostring_free(buf));
pa_xfree(s); pa_xfree(s);
/* We completed the initial module loading, so let's disable it
* from now on, if requested */
c->disallow_module_loading = !!conf->disallow_module_loading;
if (r < 0 && conf->fail) { if (r < 0 && conf->fail) {
pa_log(_("Failed to initialize daemon.")); pa_log(_("Failed to initialize daemon."));
goto finish; goto finish;
@ -1035,6 +1080,19 @@ int main(int argc, char *argv[]) {
pa_log(_("Daemon startup without any loaded modules, refusing to work.")); pa_log(_("Daemon startup without any loaded modules, refusing to work."));
goto finish; goto finish;
} }
#ifdef HAVE_DBUS
} else {
/* When we just provide the D-Bus server lookup service, we don't want
* any modules to be loaded. We haven't loaded any so far, so one might
* think there's no way to contact the server, but receiving certain
* signals could still cause modules to load. */
conf->disallow_module_loading = TRUE;
}
#endif
/* We completed the initial module loading, so let's disable it
* from now on, if requested */
c->disallow_module_loading = !!conf->disallow_module_loading;
#ifdef HAVE_FORK #ifdef HAVE_FORK
if (daemon_pipe[1] >= 0) { if (daemon_pipe[1] >= 0) {
@ -1046,7 +1104,15 @@ int main(int argc, char *argv[]) {
#endif #endif
#ifdef HAVE_DBUS #ifdef HAVE_DBUS
dbus = register_dbus(c); if (!conf->system_instance) {
if (!(server_lookup = pa_dbusobj_server_lookup_new(c, conf->local_server_type)))
goto finish;
if (!(lookup_service_bus = register_dbus_name(c, DBUS_BUS_SESSION, "org.pulseaudio.PulseAudio")))
goto finish;
}
if (start_server && !(server_bus = register_dbus_name(c, conf->system_instance ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, "org.pulseaudio.Server")))
goto finish;
#endif #endif
pa_log_info(_("Daemon startup complete.")); pa_log_info(_("Daemon startup complete."));
@ -1059,8 +1125,12 @@ int main(int argc, char *argv[]) {
finish: finish:
#ifdef HAVE_DBUS #ifdef HAVE_DBUS
if (dbus) if (server_bus)
pa_dbus_connection_unref(dbus); pa_dbus_connection_unref(server_bus);
if (lookup_service_bus)
pa_dbus_connection_unref(lookup_service_bus);
if (server_lookup)
pa_dbusobj_server_lookup_free(server_lookup);
#endif #endif
if (autospawn_fd >= 0) { if (autospawn_fd >= 0) {

277
src/daemon/server-lookup.c Normal file
View file

@ -0,0 +1,277 @@
/***
This file is part of PulseAudio.
Copyright 2009 Tanu Kaskinen
PulseAudio is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of the License,
or (at your option) any later version.
PulseAudio is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with PulseAudio; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <dbus/dbus.h>
#include <pulse/client-conf.h>
#include <pulse/xmalloc.h>
#include <pulsecore/core-util.h>
#include <pulsecore/dbus-shared.h>
#include <pulsecore/macro.h>
#include "server-lookup.h"
struct pa_dbusobj_server_lookup {
pa_dbus_connection *conn;
pa_bool_t path_registered;
pa_daemon_conf_server_type_t server_type;
};
static const char introspection[] =
DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
"<node>"
" <!-- If you are looking for documentation make sure to check out\n"
" http://pulseaudio.org/wiki/DBusInterface -->\n"
" <interface name=\"org.pulseaudio.ServerLookup\">"
" <method name=\"GetDBusServers\">"
" <arg name=\"result\" type=\"s\" direction=\"out\"/>"
" </method>"
" </interface>"
" <interface name=\"org.freedesktop.DBus.Introspectable\">"
" <method name=\"Introspect\">"
" <arg name=\"data\" type=\"s\" direction=\"out\"/>"
" </method>"
" </interface>"
"</node>";
static void unregister_cb(DBusConnection *conn, void *user_data) {
pa_dbusobj_server_lookup *sl = user_data;
pa_assert(sl);
pa_assert(sl->path_registered);
sl->path_registered = FALSE;
}
static DBusHandlerResult handle_introspect(DBusConnection *conn, DBusMessage *msg, pa_dbusobj_server_lookup *sl) {
const char *i = introspection;
DBusMessage *reply = NULL;
pa_assert(conn);
pa_assert(msg);
if (!(reply = dbus_message_new_method_return(msg)))
goto fail;
if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &i, DBUS_TYPE_INVALID))
goto fail;
if (!dbus_connection_send(conn, reply, NULL))
goto oom;
dbus_message_unref(reply);
return DBUS_HANDLER_RESULT_HANDLED;
fail:
if (reply)
dbus_message_unref(reply);
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
oom:
if (reply)
dbus_message_unref(reply);
return DBUS_HANDLER_RESULT_NEED_MEMORY;
}
/* Caller frees the string. */
static char *get_dbus_server_from_type(pa_daemon_conf_server_type_t server_type) {
char *server_string = NULL;
char *runtime_dir = NULL;
switch (server_type) {
case PA_SERVER_TYPE_USER:
runtime_dir = pa_get_runtime_dir();
if (!runtime_dir)
return NULL;
server_string = pa_sprintf_malloc("unix:path=%s/dbus_socket", runtime_dir);
break;
case PA_SERVER_TYPE_SYSTEM:
server_string = pa_xstrdup("unix:path=/var/run/pulse/dbus_socket");
break;
case PA_SERVER_TYPE_NONE:
server_string = pa_xnew0(char, 1);
break;
default:
pa_assert_not_reached();
}
return server_string;
}
static DBusHandlerResult handle_get_dbus_servers(DBusConnection *conn, DBusMessage *msg, pa_dbusobj_server_lookup *sl) {
DBusMessage *reply = NULL;
pa_client_conf *conf = NULL;
char *server_string = NULL;
pa_assert(conn);
pa_assert(msg);
pa_assert(sl);
conf = pa_client_conf_new();
if (pa_client_conf_load(conf, NULL) < 0) {
if (!(reply = dbus_message_new_error(msg, "org.pulseaudio.ClientConfLoadError", "Failed to load client.conf.")))
goto fail;
if (!dbus_connection_send(conn, reply, NULL))
goto oom;
return DBUS_HANDLER_RESULT_HANDLED;
}
server_string = pa_xstrdup(conf->default_dbus_server);
pa_client_conf_free(conf);
if (!server_string) {
if (!(server_string = get_dbus_server_from_type(sl->server_type))) {
if (!(reply = dbus_message_new_error(msg, DBUS_ERROR_FAILED, "get_dbus_server_from_type() failed.")))
goto fail;
if (!dbus_connection_send(conn, reply, NULL))
goto oom;
return DBUS_HANDLER_RESULT_HANDLED;
}
}
if (!(reply = dbus_message_new_method_return(msg)))
goto oom;
if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &server_string, DBUS_TYPE_INVALID))
goto fail;
if (!dbus_connection_send(conn, reply, NULL))
goto oom;
pa_log("Sent reply with server_string '%s'.", server_string);
pa_xfree(server_string);
dbus_message_unref(reply);
return DBUS_HANDLER_RESULT_HANDLED;
fail:
if (conf)
pa_client_conf_free(conf);
pa_xfree(server_string);
if (reply)
dbus_message_unref(reply);
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
oom:
if (conf)
pa_client_conf_free(conf);
pa_xfree(server_string);
if (reply)
dbus_message_unref(reply);
return DBUS_HANDLER_RESULT_NEED_MEMORY;
}
static DBusHandlerResult message_cb(DBusConnection *conn, DBusMessage *msg, void *user_data) {
pa_dbusobj_server_lookup *sl = user_data;
pa_assert(conn);
pa_assert(msg);
pa_assert(sl);
/* pa_log("Got message! type = %s path = %s iface = %s member = %s dest = %s", dbus_message_type_to_string(dbus_message_get_type(msg)), dbus_message_get_path(msg), dbus_message_get_interface(msg), dbus_message_get_member(msg), dbus_message_get_destination(msg)); */
if (dbus_message_is_method_call(msg, "org.freedesktop.DBus.Introspectable", "Introspect"))
return handle_introspect(conn, msg, sl);
if (dbus_message_is_method_call(msg, "org.pulseaudio.ServerLookup", "GetDBusServers"))
return handle_get_dbus_servers(conn, msg, sl);
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
static DBusObjectPathVTable vtable = {
.unregister_function = unregister_cb,
.message_function = message_cb,
.dbus_internal_pad1 = NULL,
.dbus_internal_pad2 = NULL,
.dbus_internal_pad3 = NULL,
.dbus_internal_pad4 = NULL
};
pa_dbusobj_server_lookup *pa_dbusobj_server_lookup_new(pa_core *c, pa_daemon_conf_server_type_t server_type) {
pa_dbusobj_server_lookup *sl;
DBusError error;
dbus_error_init(&error);
sl = pa_xnew(pa_dbusobj_server_lookup, 1);
sl->path_registered = FALSE;
sl->server_type = server_type;
if (!(sl->conn = pa_dbus_bus_get(c, DBUS_BUS_SESSION, &error)) || dbus_error_is_set(&error)) {
pa_log("Unable to contact D-Bus: %s: %s", error.name, error.message);
goto fail;
}
if (!dbus_connection_register_object_path(pa_dbus_connection_get(sl->conn), "/org/pulseaudio/server_lookup", &vtable, sl)) {
pa_log("dbus_connection_register_object_path() failed for /org/pulseaudio/server_lookup.");
goto fail;
}
sl->path_registered = TRUE;
return sl;
fail:
dbus_error_free(&error);
pa_dbusobj_server_lookup_free(sl);
return NULL;
}
void pa_dbusobj_server_lookup_free(pa_dbusobj_server_lookup *sl) {
pa_assert(sl);
if (sl->path_registered) {
pa_assert(sl->conn);
if (!dbus_connection_unregister_object_path(pa_dbus_connection_get(sl->conn), "/org/pulseaudio/server_lookup"))
pa_log_debug("dbus_connection_unregister_object_path() failed for /org/pulseaudio/server_lookup.");
}
if (sl->conn)
pa_dbus_connection_unref(sl->conn);
pa_xfree(sl);
}

View file

@ -0,0 +1,42 @@
#ifndef fooserverlookuphfoo
#define fooserverlookuphfoo
/***
This file is part of PulseAudio.
Copyright 2009 Tanu Kaskinen
PulseAudio is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of the License,
or (at your option) any later version.
PulseAudio is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with PulseAudio; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA.
***/
/* This object implements the D-Bus object at path
* /org/pulseaudio/server_lookup. Implemented interfaces
* are org.pulseaudio.ServerLookup and org.freedesktop.DBus.Introspectable.
*
* See http://pulseaudio.org/wiki/DBusInterface for the ServerLookup interface
* documentation.
*/
#include <pulsecore/core.h>
#include "daemon-conf.h"
typedef struct pa_dbusobj_server_lookup pa_dbusobj_server_lookup;
pa_dbusobj_server_lookup *pa_dbusobj_server_lookup_new(pa_core *c, pa_daemon_conf_server_type_t server_type);
void pa_dbusobj_server_lookup_free(pa_dbusobj_server_lookup *sl);
#endif

View file

@ -57,6 +57,7 @@ static const pa_client_conf default_conf = {
.default_sink = NULL, .default_sink = NULL,
.default_source = NULL, .default_source = NULL,
.default_server = NULL, .default_server = NULL,
.default_dbus_server = NULL,
.autospawn = TRUE, .autospawn = TRUE,
.disable_shm = FALSE, .disable_shm = FALSE,
.cookie_file = NULL, .cookie_file = NULL,
@ -81,6 +82,7 @@ void pa_client_conf_free(pa_client_conf *c) {
pa_xfree(c->default_sink); pa_xfree(c->default_sink);
pa_xfree(c->default_source); pa_xfree(c->default_source);
pa_xfree(c->default_server); pa_xfree(c->default_server);
pa_xfree(c->default_dbus_server);
pa_xfree(c->cookie_file); pa_xfree(c->cookie_file);
pa_xfree(c); pa_xfree(c);
} }
@ -97,6 +99,7 @@ int pa_client_conf_load(pa_client_conf *c, const char *filename) {
{ "default-sink", pa_config_parse_string, &c->default_sink, NULL }, { "default-sink", pa_config_parse_string, &c->default_sink, NULL },
{ "default-source", pa_config_parse_string, &c->default_source, NULL }, { "default-source", pa_config_parse_string, &c->default_source, NULL },
{ "default-server", pa_config_parse_string, &c->default_server, NULL }, { "default-server", pa_config_parse_string, &c->default_server, NULL },
{ "default-dbus-server", pa_config_parse_string, &c->default_dbus_server, NULL },
{ "autospawn", pa_config_parse_bool, &c->autospawn, NULL }, { "autospawn", pa_config_parse_bool, &c->autospawn, NULL },
{ "cookie-file", pa_config_parse_string, &c->cookie_file, NULL }, { "cookie-file", pa_config_parse_string, &c->cookie_file, NULL },
{ "disable-shm", pa_config_parse_bool, &c->disable_shm, NULL }, { "disable-shm", pa_config_parse_bool, &c->disable_shm, NULL },

View file

@ -22,12 +22,13 @@
USA. USA.
***/ ***/
#include <pulsecore/macro.h>
#include <pulsecore/native-common.h> #include <pulsecore/native-common.h>
/* A structure containing configuration data for PulseAudio clients. */ /* A structure containing configuration data for PulseAudio clients. */
typedef struct pa_client_conf { typedef struct pa_client_conf {
char *daemon_binary, *extra_arguments, *default_sink, *default_source, *default_server, *cookie_file; char *daemon_binary, *extra_arguments, *default_sink, *default_source, *default_server, *default_dbus_server, *cookie_file;
pa_bool_t autospawn, disable_shm; pa_bool_t autospawn, disable_shm;
uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; uint8_t cookie[PA_NATIVE_COOKIE_LENGTH];
pa_bool_t cookie_valid; /* non-zero, when cookie is valid */ pa_bool_t cookie_valid; /* non-zero, when cookie is valid */

View file

@ -22,6 +22,7 @@
; default-sink = ; default-sink =
; default-source = ; default-source =
; default-server = ; default-server =
; default-dbus-server =
; autospawn = yes ; autospawn = yes
; daemon-binary = @PA_BINARY@ ; daemon-binary = @PA_BINARY@