diff options
| author | Lennart Poettering <lennart@poettering.net> | 2008-06-11 14:28:35 +0000 | 
|---|---|---|
| committer | Lennart Poettering <lennart@poettering.net> | 2008-06-11 14:28:35 +0000 | 
| commit | 2cc95df8598c1bfab96c165b42bd74c0fe04d115 (patch) | |
| tree | 5dff64166771110e811504111fe52e32b1ee04c1 /src | |
| parent | 62dde3f1cd675e9c36ac3296912f106bf32be038 (diff) | |
add new module-console-kit which tracks ck sessions to avoid termination when there is still some session using the PA instance
git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2508 fefdeb5f-60dc-0310-8127-8f9354f1896f
Diffstat (limited to 'src')
| -rw-r--r-- | src/Makefile.am | 16 | ||||
| -rw-r--r-- | src/modules/module-console-kit.c | 334 | 
2 files changed, 348 insertions, 2 deletions
| diff --git a/src/Makefile.am b/src/Makefile.am index 895c928d..c1f62ab8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1138,6 +1138,12 @@ modlibexec_LTLIBRARIES += \  		module-hal-detect.la  endif +if HAVE_DBUS +modlibexec_LTLIBRARIES += \ +		libdbus-util.la \ +		module-console-kit.la +endif +  if HAVE_BLUEZ  modlibexec_LTLIBRARIES += \  		module-bt-proximity.la @@ -1199,7 +1205,8 @@ SYMDEF_FILES = \  		modules/module-hal-detect-symdef.h \  		modules/module-bt-proximity-symdef.h \  		modules/gconf/module-gconf-symdef.h \ -		modules/module-position-event-sounds-symdef.h +		modules/module-position-event-sounds-symdef.h \ +		modules/module-console-kit-symdef.h  EXTRA_DIST += $(SYMDEF_FILES)  BUILT_SOURCES += $(SYMDEF_FILES) @@ -1487,7 +1494,7 @@ module_jack_source_la_LDFLAGS = -module -avoid-version  module_jack_source_la_LIBADD = $(AM_LIBADD) libpulsecore.la $(JACK_LIBS)  module_jack_source_la_CFLAGS = $(AM_CFLAGS) $(JACK_CFLAGS) -# HAL +# HAL/D-Bus  libdbus_util_la_SOURCES = modules/dbus-util.c modules/dbus-util.h  libdbus_util_la_LDFLAGS = -avoid-version  libdbus_util_la_LIBADD = $(AM_LIBADD) $(DBUS_LIBS) libpulsecore.la @@ -1498,6 +1505,11 @@ module_hal_detect_la_LDFLAGS = -module -avoid-version  module_hal_detect_la_LIBADD = $(AM_LIBADD) $(HAL_LIBS) libpulsecore.la libdbus-util.la  module_hal_detect_la_CFLAGS = $(AM_CFLAGS) $(HAL_CFLAGS) +module_console_kit_la_SOURCES = modules/module-console-kit.c +module_console_kit_la_LDFLAGS = -module -avoid-version +module_console_kit_la_LIBADD = $(AM_LIBADD) $(HAL_LIBS) libpulsecore.la libdbus-util.la +module_console_kit_la_CFLAGS = $(AM_CFLAGS) $(HAL_CFLAGS) +  # GConf support  module_gconf_la_SOURCES = modules/gconf/module-gconf.c  module_gconf_la_LDFLAGS = -module -avoid-version diff --git a/src/modules/module-console-kit.c b/src/modules/module-console-kit.c new file mode 100644 index 00000000..c8dbc256 --- /dev/null +++ b/src/modules/module-console-kit.c @@ -0,0 +1,334 @@ +/* $Id$ */ + +/*** +    This file is part of PulseAudio. + +    Copyright 2008 Lennart Poettering + +    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 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 <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <pulse/xmalloc.h> +#include <pulse/timeval.h> + +#include <pulsecore/core-error.h> +#include <pulsecore/module.h> +#include <pulsecore/log.h> +#include <pulsecore/hashmap.h> +#include <pulsecore/idxset.h> +#include <pulsecore/core-util.h> +#include <pulsecore/namereg.h> +#include <pulsecore/core-scache.h> +#include <pulsecore/modargs.h> + +#include <hal/libhal.h> + +#include "dbus-util.h" +#include "module-console-kit-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_DESCRIPTION("Create a client for each ConsoleKit session of this user"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(TRUE); + +static const char* const valid_modargs[] = { +    NULL +}; + +struct session { +    char *id; +    pa_client *client; +}; + +struct userdata { +    pa_core *core; +    pa_dbus_connection *connection; +    pa_hashmap *sessions; +}; + +static void add_session(struct userdata *u, const char *id) { +    DBusError error; +    DBusMessage *m = NULL, *reply = NULL; +    int32_t uid; +    struct session *session; +    char *t; + +    dbus_error_init (&error); + +    if (pa_hashmap_get(u->sessions, id)) { +        pa_log_warn("Duplicate session %s, ignoring.", id); +        return; +    } + +    if (!(m = dbus_message_new_method_call("org.freedesktop.ConsoleKit", id, "org.freedesktop.ConsoleKit.Session", "GetUnixUser"))) { +        pa_log("Failed to allocate GetUnixUser() method call."); +        goto fail; +    } + +    if (!(reply = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(u->connection), m, -1, &error))) { +        pa_log("GetUnixUser() call failed: %s: %s", error.name, error.message); +        goto fail; +    } + +    /* FIXME: Why is this in int32? and not an uint32? */ +    if (!dbus_message_get_args(reply, &error, DBUS_TYPE_INT32, &uid, DBUS_TYPE_INVALID)) { +        pa_log("Failed to parse GetUnixUser() result: %s: %s", error.name, error.message); +        goto fail; +    } + +    /* We only care about our own sessions */ +    if ((uid_t) uid != getuid()) +        goto fail; + +    session = pa_xnew(struct session, 1); +    session->id = pa_xstrdup(id); + +    t = pa_sprintf_malloc("ConsoleKit Session %s", id); +    session->client = pa_client_new(u->core, __FILE__, t); +    pa_xfree(t); + +    pa_proplist_sets(session->client->proplist, "console-kit.session", id); + +    pa_hashmap_put(u->sessions, session->id, session); + +    pa_log_debug("Added new session %s", id); + +fail: + +    if (m) +        dbus_message_unref(m); + +    if (reply) +        dbus_message_unref(reply); + +    dbus_error_free(&error); +} + +static void free_session(struct session *session) { +    pa_assert(session); + +    pa_log_debug("Removing session %s", session->id); + +    pa_client_free(session->client); +    pa_xfree(session->id); +    pa_xfree(session); +} + +static void remove_session(struct userdata *u, const char *id) { +    struct session *session; + +    if (!(session = pa_hashmap_remove(u->sessions, id))) +        return; + +    free_session(session); +} + +static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *message, void *userdata) { +    struct userdata *u = userdata; +    DBusError error; +    const char *path; + +    pa_assert(bus); +    pa_assert(message); +    pa_assert(u); + +    dbus_error_init(&error); + +    pa_log_debug("dbus: interface=%s, path=%s, member=%s\n", +                 dbus_message_get_interface(message), +                 dbus_message_get_path(message), +                 dbus_message_get_member(message)); + +    if (dbus_message_is_signal(message, "org.freedesktop.ConsoleKit.Seat", "SessionAdded")) { + +        if (!dbus_message_get_args(message, &error, DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID) || dbus_error_is_set(&error)) { +            pa_log_error("Failed to parse SessionAdded message: %s: %s", error.name, error.message); +            goto finish; +        } + +        add_session(u, path); + +    } else if (dbus_message_is_signal(message, "org.freedesktop.ConsoleKit.Seat", "SessionRemoved")) { + +        if (!dbus_message_get_args(message, &error, DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID) || dbus_error_is_set(&error)) { +            pa_log_error("Failed to parse SessionRemoved message: %s: %s", error.name, error.message); +            goto finish; +        } + +        remove_session(u, path); +    } + +finish: +    dbus_error_free(&error); + +    return DBUS_HANDLER_RESULT_HANDLED; +} + +static int get_session_list(struct userdata *u) { +    DBusError error; +    DBusMessage *m = NULL, *reply = NULL; +    uint32_t uid; +    DBusMessageIter iter, sub; +    int ret = -1; + +    pa_assert(u); + +    dbus_error_init(&error); + +    if (!(m = dbus_message_new_method_call("org.freedesktop.ConsoleKit", "/org/freedesktop/ConsoleKit/Manager", "org.freedesktop.ConsoleKit.Manager", "GetSessionsForUnixUser"))) { +        pa_log("Failed to allocate GetSessionsForUnixUser() method call."); +        goto fail; +    } + +    uid = (uint32_t) getuid(); +    if (!(dbus_message_append_args(m, DBUS_TYPE_UINT32, &uid, DBUS_TYPE_INVALID))) { +        pa_log("Failed to append arguments to GetSessionsForUnixUser() method call."); +        goto fail; +    } + +    if (!(reply = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(u->connection), m, -1, &error))) { +        pa_log("GetSessionsForUnixUser() call failed: %s: %s", error.name, error.message); +        goto fail; +    } + +    dbus_message_iter_init(reply, &iter); + +    if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || +        dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_OBJECT_PATH) { +        pa_log("Failed to parse GetSessionsForUnixUser() result."); +        goto fail; +    } + +    dbus_message_iter_recurse(&iter, &sub); + +    for (;;) { +        int at; +        const char *id; + +        if ((at = dbus_message_iter_get_arg_type(&sub)) == DBUS_TYPE_INVALID) +            break; + +        assert(at == DBUS_TYPE_OBJECT_PATH); +        dbus_message_iter_get_basic(&sub, &id); + +        add_session(u, id); + +        dbus_message_iter_next(&sub); +    } + +    ret = 0; + +fail: + +    if (m) +        dbus_message_unref(m); + +    if (reply) +        dbus_message_unref(reply); + +    dbus_error_free(&error); + +    return ret; +} + +int pa__init(pa_module*m) { +    DBusError error; +    pa_dbus_connection *connection; +    struct userdata *u = NULL; +    pa_modargs *ma; + +    pa_assert(m); + +    dbus_error_init(&error); + +    if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { +        pa_log("Failed to parse module arguments"); +        goto fail; +    } + +    if (!(connection = pa_dbus_bus_get(m->core, DBUS_BUS_SYSTEM, &error)) || dbus_error_is_set(&error)) { + +        if (connection) +            pa_dbus_connection_unref(connection); + +        pa_log_error("Unable to contact D-Bus system bus: %s: %s", error.name, error.message); +        goto fail; +    } + +    m->userdata = u = pa_xnew(struct userdata, 1); +    u->core = m->core; +    u->connection = connection; +    u->sessions = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); + +    if (!dbus_connection_add_filter(pa_dbus_connection_get(connection), filter_cb, u, NULL)) { +        pa_log_error("Failed to add filter function"); +        goto fail; +    } + +    dbus_bus_add_match(pa_dbus_connection_get(connection), "type='signal',sender='org.freedesktop.ConsoleKit', interface='org.freedesktop.ConsoleKit.Seat'", &error); +    if (dbus_error_is_set(&error)) { +        pa_log_error("Unable to subscribe to ConsoleKit signals: %s: %s", error.name, error.message); +        goto fail; +    } + +    if (get_session_list(u) < 0) +        goto fail; + +    pa_modargs_free(ma); + +    return 0; + +fail: +    if (ma) +        pa_modargs_free(ma); + +    dbus_error_free(&error); +    pa__done(m); + +    return -1; +} + + +void pa__done(pa_module *m) { +    struct userdata *u; +    struct session *session; + +    pa_assert(m); + +    if (!(u = m->userdata)) +        return; + +    while ((session = pa_hashmap_steal_first(u->sessions))) +        free_session(session); + +    if (u->connection) +        pa_dbus_connection_unref(u->connection); + +    pa_xfree(u); +} | 
