mirror of
				https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
				synced 2025-11-03 09:01:50 -05:00 
			
		
		
		
	daemon: Implement the DBus server lookup service.
This commit is contained in:
		
							parent
							
								
									c94e7421aa
								
							
						
					
					
						commit
						5babbaafb2
					
				
					 10 changed files with 490 additions and 37 deletions
				
			
		| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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));
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,6 +1052,10 @@ int main(int argc, char *argv[]) {
 | 
			
		|||
        pa_assert_se(pa_cpu_limit_init(pa_mainloop_get_api(mainloop)) == 0);
 | 
			
		||||
 | 
			
		||||
    buf = pa_strbuf_new();
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_DBUS
 | 
			
		||||
    if (start_server) {
 | 
			
		||||
#endif
 | 
			
		||||
        if (conf->load_default_script_file) {
 | 
			
		||||
            FILE *f;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1022,10 +1071,6 @@ int main(int argc, char *argv[]) {
 | 
			
		|||
        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;
 | 
			
		||||
| 
						 | 
				
			
			@ -1035,6 +1080,19 @@ int main(int argc, char *argv[]) {
 | 
			
		|||
            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
 | 
			
		||||
 | 
			
		||||
    /* 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) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										277
									
								
								src/daemon/server-lookup.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										277
									
								
								src/daemon/server-lookup.c
									
										
									
									
									
										Normal 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);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										42
									
								
								src/daemon/server-lookup.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/daemon/server-lookup.h
									
										
									
									
									
										Normal 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
 | 
			
		||||
| 
						 | 
				
			
			@ -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 },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,12 +22,13 @@
 | 
			
		|||
  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 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,6 +22,7 @@
 | 
			
		|||
; default-sink =
 | 
			
		||||
; default-source =
 | 
			
		||||
; default-server =
 | 
			
		||||
; default-dbus-server =
 | 
			
		||||
 | 
			
		||||
; autospawn = yes
 | 
			
		||||
; daemon-binary = @PA_BINARY@
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue