]> code.delx.au - pulseaudio/commitdiff
daemon: Implement the DBus server lookup service.
authorTanu Kaskinen <tanuk@iki.fi>
Fri, 12 Jun 2009 04:16:05 +0000 (07:16 +0300)
committerTanu Kaskinen <tanuk@iki.fi>
Fri, 12 Jun 2009 04:22:33 +0000 (07:22 +0300)
src/Makefile.am
src/daemon/daemon-conf.c
src/daemon/daemon-conf.h
src/daemon/daemon.conf.in
src/daemon/main.c
src/daemon/server-lookup.c [new file with mode: 0644]
src/daemon/server-lookup.h [new file with mode: 0644]
src/pulse/client-conf.c
src/pulse/client-conf.h
src/pulse/client.conf.in

index 70b16be307b162063ff895ec2f823f67f8a0937f..c56f76086a3ac1bd458f3f50b8c4b56d70f9e74d 100644 (file)
@@ -135,13 +135,14 @@ BUILT_SOURCES = \
 bin_PROGRAMS = pulseaudio
 
 pulseaudio_SOURCES = \
-               daemon/caps.h daemon/caps.c \
+               daemon/caps.c daemon/caps.h \
                daemon/cmdline.c daemon/cmdline.h \
                daemon/cpulimit.c daemon/cpulimit.h \
                daemon/daemon-conf.c daemon/daemon-conf.h \
                daemon/dumpmodules.c daemon/dumpmodules.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_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)
index ac6cc8aad54622515ed5180745bc7a18d72e1ec9..e6fa8c64643f3843096c317a6c5401a50abc5655 100644 (file)
@@ -83,6 +83,9 @@ static const pa_daemon_conf default_conf = {
     .config_file = NULL,
     .use_pid_file = TRUE,
     .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,
     .disable_shm = FALSE,
     .default_n_fragments = 4,
@@ -203,6 +206,22 @@ int pa_daemon_conf_set_resample_method(pa_daemon_conf *c, const char *string) {
     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) {
     pa_daemon_conf *c = data;
 
@@ -430,6 +449,22 @@ static int parse_rtprio(const char *filename, unsigned line, const char *section
     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 r = -1;
     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 },
         { "use-pid-file",               pa_config_parse_bool,     &c->use_pid_file, 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 },
         { "disable-shm",                pa_config_parse_bool,     &c->disable_shm, 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"
 };
 
+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) {
     pa_strbuf *s;
     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, "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));
+#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, "disable-shm = %s\n", pa_yes_no(c->disable_shm));
     pa_strbuf_printf(s, "flat-volumes = %s\n", pa_yes_no(c->flat_volumes));
index 9cec189f82cbd86c285e423b82e5796db645b204..98db8641ad8f9fd82d450e212bcf0bfdb8d90128 100644 (file)
@@ -48,6 +48,13 @@ typedef enum pa_daemon_conf_cmd {
     PA_CMD_CLEANUP_SHM
 } 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
 typedef struct pa_rlimit {
     rlim_t value;
@@ -74,6 +81,7 @@ typedef struct pa_daemon_conf {
         log_meta,
         log_time,
         flat_volumes;
+    pa_daemon_conf_server_type_t local_server_type;
     int exit_idle_time,
         scache_idle_time,
         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_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_local_server_type(pa_daemon_conf *c, const char *string);
 
 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);
index fcd2513a6c8bfb96df1cf6d8ffc73279a2ad5885..ecdb3a642a9ebbb1fd090e39839edc6f6ec751dc 100644 (file)
@@ -25,6 +25,7 @@
 ; disallow-exit = no
 ; use-pid-file = yes
 ; system-instance = no
+; local-server-type = user
 ; disable-shm = no
 ; shm-size-bytes = 0 # setting this 0 will use the system-default, usually 64 MiB
 
index 3e50baadefd85afc0b5f6e3084cfca3a0d4e0726..1b6ed793a32a4284d5da6e3018d573842e17ad47 100644 (file)
@@ -99,6 +99,7 @@
 #include "caps.h"
 #include "ltdl-bind-now.h"
 #include "polkit.h"
+#include "server-lookup.h"
 
 #ifdef HAVE_LIBWRAP
 /* Only one instance of these variables */
@@ -335,33 +336,31 @@ static void set_all_rlimits(const pa_daemon_conf *conf) {
 #endif
 
 #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;
     pa_dbus_connection *conn;
 
     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);
         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) {
-        pa_log_debug("Got org.pulseaudio.Server!");
+    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 %s!", name);
         return conn;
     }
 
     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
-        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
-     * ignore mostly the case that org.pulseaudio.Server is already
-     * taken. */
+     * ignore mostly the case that a name is already taken. */
 
 fail:
-
     if (conn)
         pa_dbus_connection_unref(conn);
 
@@ -393,7 +392,10 @@ int main(int argc, char *argv[]) {
     int autospawn_fd = -1;
     pa_bool_t autospawn_locked = FALSE;
 #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
 
     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_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));
 
+#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()) {
 #ifdef HAVE_SYS_RESOURCE_H
         struct rlimit rl;
@@ -628,6 +667,10 @@ int main(int argc, char *argv[]) {
         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()));
 
     LTDL_SET_PRELOADED_SYMBOLS();
@@ -716,10 +759,12 @@ int main(int argc, char *argv[]) {
 
     if (real_root && !conf->system_instance)
         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) {
         pa_log(_("Root privileges required."));
         goto finish;
     }
+#endif
 
     if (conf->cmd == PA_CMD_START && conf->system_instance) {
         pa_log(_("--start not supported for system instances."));
@@ -1007,34 +1052,47 @@ int main(int argc, char *argv[]) {
         pa_assert_se(pa_cpu_limit_init(pa_mainloop_get_api(mainloop)) == 0);
 
     buf = pa_strbuf_new();
-    if (conf->load_default_script_file) {
-        FILE *f;
 
-        if ((f = pa_daemon_conf_open_default_script_file(conf))) {
-            r = pa_cli_command_execute_file_stream(c, f, buf, &conf->fail);
-            fclose(f);
+#ifdef HAVE_DBUS
+    if (start_server) {
+#endif
+        if (conf->load_default_script_file) {
+            FILE *f;
+
+            if ((f = pa_daemon_conf_open_default_script_file(conf))) {
+                r = pa_cli_command_execute_file_stream(c, f, buf, &conf->fail);
+                fclose(f);
+            }
         }
-    }
 
-    if (r >= 0)
-        r = pa_cli_command_execute(c, conf->script_commands, buf, &conf->fail);
+        if (r >= 0)
+            r = pa_cli_command_execute(c, conf->script_commands, buf, &conf->fail);
 
-    pa_log_error("%s", s = pa_strbuf_tostring_free(buf));
-    pa_xfree(s);
+        pa_log_error("%s", s = pa_strbuf_tostring_free(buf));
+        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) {
+            pa_log(_("Failed to initialize daemon."));
+            goto finish;
+        }
 
-    if (r < 0 && conf->fail) {
-        pa_log(_("Failed to initialize daemon."));
-        goto finish;
+        if (!c->modules || pa_idxset_size(c->modules) == 0) {
+            pa_log(_("Daemon startup without any loaded modules, refusing to work."));
+            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
 
-    if (!c->modules || pa_idxset_size(c->modules) == 0) {
-        pa_log(_("Daemon startup without any loaded modules, refusing to work."));
-        goto finish;
-    }
+    /* 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
     if (daemon_pipe[1] >= 0) {
@@ -1046,7 +1104,15 @@ int main(int argc, char *argv[]) {
 #endif
 
 #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
 
     pa_log_info(_("Daemon startup complete."));
@@ -1059,8 +1125,12 @@ int main(int argc, char *argv[]) {
 
 finish:
 #ifdef HAVE_DBUS
-    if (dbus)
-        pa_dbus_connection_unref(dbus);
+    if (server_bus)
+        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
 
     if (autospawn_fd >= 0) {
diff --git a/src/daemon/server-lookup.c b/src/daemon/server-lookup.c
new file mode 100644 (file)
index 0000000..867c3a1
--- /dev/null
@@ -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);
+}
\ No newline at end of file
diff --git a/src/daemon/server-lookup.h b/src/daemon/server-lookup.h
new file mode 100644 (file)
index 0000000..69fdacd
--- /dev/null
@@ -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
\ No newline at end of file
index 940d0b673286bbba4f3e42cdafa1c69d3cec6254..8eab1094d817135905dee9c434e78b88987588a9 100644 (file)
@@ -57,6 +57,7 @@ static const pa_client_conf default_conf = {
     .default_sink = NULL,
     .default_source = NULL,
     .default_server = NULL,
+    .default_dbus_server = NULL,
     .autospawn = TRUE,
     .disable_shm = FALSE,
     .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_source);
     pa_xfree(c->default_server);
+    pa_xfree(c->default_dbus_server);
     pa_xfree(c->cookie_file);
     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-source",         pa_config_parse_string,  &c->default_source, 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 },
         { "cookie-file",            pa_config_parse_string,  &c->cookie_file, NULL },
         { "disable-shm",            pa_config_parse_bool,    &c->disable_shm, NULL },
index ab97dc6a43bd6f54fba9992b45e2c6e6d0964efe..618216f4ff5e622f72cf66531997d42c6691a52b 100644 (file)
   USA.
 ***/
 
+#include <pulsecore/macro.h>
 #include <pulsecore/native-common.h>
 
 /* A structure containing configuration data for PulseAudio clients. */
 
 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;
     uint8_t cookie[PA_NATIVE_COOKIE_LENGTH];
     pa_bool_t cookie_valid; /* non-zero, when cookie is valid */
index 579bcc2046fc16665df5130498bb4d43ac1ac4a9..3340b0b2d5221f21c997c2ff5c47ab0a605d7b16 100644 (file)
@@ -22,6 +22,7 @@
 ; default-sink =
 ; default-source =
 ; default-server =
+; default-dbus-server =
 
 ; autospawn = yes
 ; daemon-binary = @PA_BINARY@