Blame src/lib/abrt_dbus.c

Packit Service 779887
/*
Packit Service 779887
    Copyright (C) 2010  ABRT team
Packit Service 779887
    Copyright (C) 2010  RedHat Inc
Packit Service 779887
Packit Service 779887
    This program is free software; you can redistribute it and/or modify
Packit Service 779887
    it under the terms of the GNU General Public License as published by
Packit Service 779887
    the Free Software Foundation; either version 2 of the License, or
Packit Service 779887
    (at your option) any later version.
Packit Service 779887
Packit Service 779887
    This program is distributed in the hope that it will be useful,
Packit Service 779887
    but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 779887
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 779887
    GNU General Public License for more details.
Packit Service 779887
Packit Service 779887
    You should have received a copy of the GNU General Public License along
Packit Service 779887
    with this program; if not, write to the Free Software Foundation, Inc.,
Packit Service 779887
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Packit Service 779887
*/
Packit Service 779887
#include <dbus/dbus.h>
Packit Service 779887
#include "internal_abrt_dbus.h"
Packit Service 779887
Packit Service 779887
DBusConnection* g_dbus_conn;
Packit Service 779887
Packit Service 779887
Packit Service 779887
/*
Packit Service 779887
 * Helpers for building DBus messages
Packit Service 779887
 */
Packit Service 779887
Packit Service 779887
//void store_bool(DBusMessageIter* iter, bool val)
Packit Service 779887
//{
Packit Service 779887
//    dbus_bool_t db = val;
Packit Service 779887
//    if (!dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &db))
Packit Service 779887
//        die_out_of_memory();
Packit Service 779887
//}
Packit Service 779887
void store_int32(DBusMessageIter* iter, int32_t val)
Packit Service 779887
{
Packit Service 779887
    if (!dbus_message_iter_append_basic(iter, DBUS_TYPE_INT32, &val))
Packit Service 779887
        die_out_of_memory();
Packit Service 779887
}
Packit Service 779887
void store_uint32(DBusMessageIter* iter, uint32_t val)
Packit Service 779887
{
Packit Service 779887
    if (!dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &val))
Packit Service 779887
        die_out_of_memory();
Packit Service 779887
}
Packit Service 779887
void store_int64(DBusMessageIter* iter, int64_t val)
Packit Service 779887
{
Packit Service 779887
    if (!dbus_message_iter_append_basic(iter, DBUS_TYPE_INT64, &val))
Packit Service 779887
        die_out_of_memory();
Packit Service 779887
}
Packit Service 779887
void store_uint64(DBusMessageIter* iter, uint64_t val)
Packit Service 779887
{
Packit Service 779887
    if (!dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT64, &val))
Packit Service 779887
        die_out_of_memory();
Packit Service 779887
}
Packit Service 779887
Packit Service 779887
void store_string(DBusMessageIter* iter, const char* val)
Packit Service 779887
{
Packit Service 779887
    /* dbus daemon will simply close our connection if we send broken utf8.
Packit Service 779887
     * Therefore we must never do that.
Packit Service 779887
     */
Packit Service 779887
    const char *sanitized = sanitize_utf8(val, /*ctrl:*/ 0);
Packit Service 779887
    if (!dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, sanitized ? &sanitized : &val))
Packit Service 779887
        die_out_of_memory();
Packit Service 779887
    free((char*)sanitized);
Packit Service 779887
}
Packit Service 779887
Packit Service 779887
Packit Service 779887
/*
Packit Service 779887
 * Helpers for parsing DBus messages
Packit Service 779887
 */
Packit Service 779887
Packit Service 779887
//int load_bool(DBusMessageIter* iter, bool& val)
Packit Service 779887
//{
Packit Service 779887
//    int type = dbus_message_iter_get_arg_type(iter);
Packit Service 779887
//    if (type != DBUS_TYPE_BOOLEAN)
Packit Service 779887
//        error_msg_and_die("%s expected in dbus message, but not found ('%c')", "bool", type);
Packit Service 779887
//    dbus_bool_t db;
Packit Service 779887
//    dbus_message_iter_get_basic(iter, &db);
Packit Service 779887
//    val = db;
Packit Service 779887
//    return dbus_message_iter_next(iter);
Packit Service 779887
//}
Packit Service 779887
int load_int32(DBusMessageIter* iter, int32_t *val)
Packit Service 779887
{
Packit Service 779887
    int type = dbus_message_iter_get_arg_type(iter);
Packit Service 779887
    if (type != DBUS_TYPE_INT32)
Packit Service 779887
    {
Packit Service 779887
        error_msg("%s expected in dbus message, but not found ('%c')", "int32", type);
Packit Service 779887
        return -1;
Packit Service 779887
    }
Packit Service 779887
    dbus_message_iter_get_basic(iter, val);
Packit Service 779887
    return dbus_message_iter_next(iter);
Packit Service 779887
}
Packit Service 779887
int load_uint32(DBusMessageIter* iter, uint32_t *val)
Packit Service 779887
{
Packit Service 779887
    int type = dbus_message_iter_get_arg_type(iter);
Packit Service 779887
    if (type != DBUS_TYPE_UINT32)
Packit Service 779887
    {
Packit Service 779887
        error_msg("%s expected in dbus message, but not found ('%c')", "uint32", type);
Packit Service 779887
        return -1;
Packit Service 779887
    }
Packit Service 779887
    dbus_message_iter_get_basic(iter, val);
Packit Service 779887
    return dbus_message_iter_next(iter);
Packit Service 779887
}
Packit Service 779887
int load_int64(DBusMessageIter* iter, int64_t *val)
Packit Service 779887
{
Packit Service 779887
    int type = dbus_message_iter_get_arg_type(iter);
Packit Service 779887
    if (type != DBUS_TYPE_INT64)
Packit Service 779887
    {
Packit Service 779887
        error_msg("%s expected in dbus message, but not found ('%c')", "int64", type);
Packit Service 779887
        return -1;
Packit Service 779887
    }
Packit Service 779887
    dbus_message_iter_get_basic(iter, val);
Packit Service 779887
    return dbus_message_iter_next(iter);
Packit Service 779887
}
Packit Service 779887
int load_uint64(DBusMessageIter* iter, uint64_t *val)
Packit Service 779887
{
Packit Service 779887
    int type = dbus_message_iter_get_arg_type(iter);
Packit Service 779887
    if (type != DBUS_TYPE_UINT64)
Packit Service 779887
    {
Packit Service 779887
        error_msg("%s expected in dbus message, but not found ('%c')", "uint64", type);
Packit Service 779887
        return -1;
Packit Service 779887
    }
Packit Service 779887
    dbus_message_iter_get_basic(iter, val);
Packit Service 779887
    return dbus_message_iter_next(iter);
Packit Service 779887
}
Packit Service 779887
int load_charp(DBusMessageIter* iter, const char** val)
Packit Service 779887
{
Packit Service 779887
    *val = NULL;
Packit Service 779887
Packit Service 779887
    int type = dbus_message_iter_get_arg_type(iter);
Packit Service 779887
    if (type != DBUS_TYPE_STRING)
Packit Service 779887
    {
Packit Service 779887
        error_msg("%s expected in dbus message, but not found ('%c')", "string", type);
Packit Service 779887
        return -1;
Packit Service 779887
    }
Packit Service 779887
    dbus_message_iter_get_basic(iter, val);
Packit Service 779887
//log_warning("load_charp:'%s'", *val);
Packit Service 779887
    return dbus_message_iter_next(iter);
Packit Service 779887
}
Packit Service 779887
Packit Service 779887
Packit Service 779887
/*
Packit Service 779887
 * Glib integration machinery
Packit Service 779887
 */
Packit Service 779887
Packit Service 779887
/* Callback: "glib says dbus fd is active" */
Packit Service 779887
static gboolean handle_dbus_fd(GIOChannel *gio, GIOCondition condition, gpointer data)
Packit Service 779887
{
Packit Service 779887
    DBusWatch *watch = (DBusWatch*)data;
Packit Service 779887
Packit Service 779887
    log_debug("%s(gio, condition:%x [bits:IN/PRI/OUT/ERR/HUP...], data)", __func__, (int)condition);
Packit Service 779887
Packit Service 779887
    /* Notify the D-Bus library when a previously-added watch
Packit Service 779887
     * is ready for reading or writing, or has an exception such as a hangup.
Packit Service 779887
     */
Packit Service 779887
    int glib_flags = (int)condition;
Packit Service 779887
    int dbus_flags = 0;
Packit Service 779887
    if (glib_flags & G_IO_IN)  dbus_flags |= DBUS_WATCH_READABLE;
Packit Service 779887
    if (glib_flags & G_IO_OUT) dbus_flags |= DBUS_WATCH_WRITABLE;
Packit Service 779887
    if (glib_flags & G_IO_ERR) dbus_flags |= DBUS_WATCH_ERROR;
Packit Service 779887
    if (glib_flags & G_IO_HUP) dbus_flags |= DBUS_WATCH_HANGUP;
Packit Service 779887
    /*
Packit Service 779887
     * TODO:
Packit Service 779887
     * If dbus_watch_handle returns FALSE, then the file descriptor
Packit Service 779887
     * may still be ready for reading or writing, but more memory
Packit Service 779887
     * is needed in order to do the reading or writing. If you ignore
Packit Service 779887
     * the FALSE return, your application may spin in a busy loop
Packit Service 779887
     * on the file descriptor until memory becomes available,
Packit Service 779887
     * but nothing more catastrophic should happen.
Packit Service 779887
     */
Packit Service 779887
    dbus_watch_handle(watch, dbus_flags);
Packit Service 779887
Packit Service 779887
    while (dbus_connection_dispatch(g_dbus_conn) == DBUS_DISPATCH_DATA_REMAINS)
Packit Service 779887
        log_debug("%s: more data to process, looping", __func__);
Packit Service 779887
    return TRUE; /* "glib, do not remove this event source!" */
Packit Service 779887
}
Packit Service 779887
Packit Service 779887
typedef struct watch_app_info_t
Packit Service 779887
{
Packit Service 779887
    GIOChannel *channel;
Packit Service 779887
    guint event_source_id;
Packit Service 779887
    bool watch_enabled;
Packit Service 779887
} watch_app_info_t;
Packit Service 779887
/* Callback: "dbus_watch_get_enabled() may return a different value than it did before" */
Packit Service 779887
static void toggled_watch(DBusWatch *watch, void* data)
Packit Service 779887
{
Packit Service 779887
    log_debug("%s(watch:%p, data)", __func__, watch);
Packit Service 779887
Packit Service 779887
    watch_app_info_t* app_info = (watch_app_info_t*)dbus_watch_get_data(watch);
Packit Service 779887
    if (dbus_watch_get_enabled(watch))
Packit Service 779887
    {
Packit Service 779887
        if (!app_info->watch_enabled)
Packit Service 779887
        {
Packit Service 779887
            app_info->watch_enabled = true;
Packit Service 779887
            int dbus_flags = dbus_watch_get_flags(watch);
Packit Service 779887
            int glib_flags = 0;
Packit Service 779887
            if (dbus_flags & DBUS_WATCH_READABLE) glib_flags |= G_IO_IN;
Packit Service 779887
            if (dbus_flags & DBUS_WATCH_WRITABLE) glib_flags |= G_IO_OUT;
Packit Service 779887
            log_debug(" adding watch to glib main loop. dbus_flags:%x glib_flags:%x", dbus_flags, glib_flags);
Packit Service 779887
            app_info->event_source_id = g_io_add_watch(app_info->channel, (GIOCondition)glib_flags, handle_dbus_fd, watch);
Packit Service 779887
        }
Packit Service 779887
        /* else: it was already enabled */
Packit Service 779887
    }
Packit Service 779887
    else
Packit Service 779887
    {
Packit Service 779887
        if (app_info->watch_enabled)
Packit Service 779887
        {
Packit Service 779887
            app_info->watch_enabled = false;
Packit Service 779887
            /* does it free the hidden GSource too? */
Packit Service 779887
            log_debug(" removing watch from glib main loop");
Packit Service 779887
            g_source_remove(app_info->event_source_id);
Packit Service 779887
        }
Packit Service 779887
        /* else: it was already disabled */
Packit Service 779887
    }
Packit Service 779887
}
Packit Service 779887
/* Callback: "libdbus needs a new watch to be monitored by the main loop" */
Packit Service 779887
static dbus_bool_t add_watch(DBusWatch *watch, void* data)
Packit Service 779887
{
Packit Service 779887
    log_debug("%s(watch:%p, data)", __func__, watch);
Packit Service 779887
Packit Service 779887
    watch_app_info_t* app_info = (watch_app_info_t*)xzalloc(sizeof(*app_info));
Packit Service 779887
    dbus_watch_set_data(watch, app_info, free);
Packit Service 779887
Packit Service 779887
    int fd = dbus_watch_get_unix_fd(watch);
Packit Service 779887
    log_debug(" dbus_watch_get_unix_fd():%d", fd);
Packit Service 779887
    app_info->channel = g_io_channel_unix_new(fd);
Packit Service 779887
    /* _unconditionally_ adding it to event loop would be an error */
Packit Service 779887
    toggled_watch(watch, data);
Packit Service 779887
    return TRUE;
Packit Service 779887
}
Packit Service 779887
/* Callback: "libdbus no longer needs a watch to be monitored by the main loop" */
Packit Service 779887
static void remove_watch(DBusWatch *watch, void* data)
Packit Service 779887
{
Packit Service 779887
    log_debug("%s()", __func__);
Packit Service 779887
    watch_app_info_t* app_info = (watch_app_info_t*)dbus_watch_get_data(watch);
Packit Service 779887
    if (app_info->watch_enabled)
Packit Service 779887
    {
Packit Service 779887
        app_info->watch_enabled = false;
Packit Service 779887
        g_source_remove(app_info->event_source_id);
Packit Service 779887
    }
Packit Service 779887
    g_io_channel_unref(app_info->channel);
Packit Service 779887
}
Packit Service 779887
Packit Service 779887
/* Callback: "libdbus needs a new timeout to be monitored by the main loop" */
Packit Service 779887
static dbus_bool_t add_timeout(DBusTimeout *timeout, void* data)
Packit Service 779887
{
Packit Service 779887
    log_debug("%s()", __func__);
Packit Service 779887
    return TRUE;
Packit Service 779887
}
Packit Service 779887
/* Callback: "libdbus no longer needs a timeout to be monitored by the main loop" */
Packit Service 779887
static void remove_timeout(DBusTimeout *timeout, void* data)
Packit Service 779887
{
Packit Service 779887
    log_debug("%s()", __func__);
Packit Service 779887
}
Packit Service 779887
/* Callback: "dbus_timeout_get_enabled() may return a different value than it did before" */
Packit Service 779887
static void timeout_toggled(DBusTimeout *timeout, void* data)
Packit Service 779887
{
Packit Service 779887
//seems to be never called, let's make it noisy
Packit Service 779887
    error_msg_and_die("%s(): FIXME: some dbus machinery is missing here", __func__);
Packit Service 779887
}
Packit Service 779887
Packit Service 779887
/* Callback: "DBusObjectPathVTable is unregistered (or its connection is freed)" */
Packit Service 779887
static void unregister_vtable(DBusConnection *conn, void* data)
Packit Service 779887
{
Packit Service 779887
    log_debug("%s()", __func__);
Packit Service 779887
}
Packit Service 779887
Packit Service 779887
Packit Service 779887
/*
Packit Service 779887
 * Initialization. Works as follows:
Packit Service 779887
 *
Packit Service 779887
 * we have a DBusConnection* (say, obtained with dbus_bus_get)
Packit Service 779887
 * we call dbus_connection_set_watch_functions
Packit Service 779887
 *  libdbus calls back add_watch(watch:0x2341090, data), this watch is for writing
Packit Service 779887
 *   we call toggled_watch, but it finds that watch is not to be enabled yet
Packit Service 779887
 *  libdbus calls back add_watch(watch:0x23410e0, data), this watch is for reading
Packit Service 779887
 *   we call toggled_watch, it adds watch's fd to glib main loop with POLLIN
Packit Service 779887
 *  (note: these watches are different objects, but they have the same fd)
Packit Service 779887
 * we call dbus_connection_set_timeout_functions
Packit Service 779887
 * we call dbus_connection_register_object_path
Packit Service 779887
 *
Packit Service 779887
 * Note: if user will later call dbus_bus_request_name(conn, ...):
Packit Service 779887
 *  libdbus calls back add_timeout()
Packit Service 779887
 *  libdbus calls back remove_timeout()
Packit Service 779887
 *  note - no callback to timeout_toggled()!
Packit Service 779887
 * (therefore there is no code yet in timeout_toggled (see above), it's not used)
Packit Service 779887
 */
Packit Service 779887
void attach_dbus_conn_to_glib_main_loop(DBusConnection* conn,
Packit Service 779887
        const char* object_path,
Packit Service 779887
        DBusHandlerResult (*message_received_func)(DBusConnection *conn, DBusMessage *msg, void* data)
Packit Service 779887
) {
Packit Service 779887
    if (g_dbus_conn)
Packit Service 779887
        error_msg_and_die("Internal bug: can't connect to more than one dbus");
Packit Service 779887
    g_dbus_conn = conn;
Packit Service 779887
Packit Service 779887
//do we need this? why?
Packit Service 779887
//log_warning("dbus_connection_set_dispatch_status_function");
Packit Service 779887
//    dbus_connection_set_dispatch_status_function(conn,
Packit Service 779887
//                dispatch, /* void dispatch(DBusConnection *conn, DBusDispatchStatus new_status, void* data) */
Packit Service 779887
//                NULL, /* data */
Packit Service 779887
//                NULL /* free_data_function */
Packit Service 779887
//    )
Packit Service 779887
    log_debug("dbus_connection_set_watch_functions");
Packit Service 779887
    if (!dbus_connection_set_watch_functions(conn,
Packit Service 779887
                add_watch,
Packit Service 779887
                remove_watch,
Packit Service 779887
                toggled_watch,
Packit Service 779887
                NULL, /* data */
Packit Service 779887
                NULL /* free_data_function */
Packit Service 779887
                )
Packit Service 779887
    ) {
Packit Service 779887
        die_out_of_memory();
Packit Service 779887
    }
Packit Service 779887
    log_debug("dbus_connection_set_timeout_functions");
Packit Service 779887
    if (!dbus_connection_set_timeout_functions(conn,
Packit Service 779887
                add_timeout,
Packit Service 779887
                remove_timeout,
Packit Service 779887
                timeout_toggled,
Packit Service 779887
                NULL, /* data */
Packit Service 779887
                NULL /* free_data_function */
Packit Service 779887
                )
Packit Service 779887
    ) {
Packit Service 779887
        die_out_of_memory();
Packit Service 779887
    }
Packit Service 779887
Packit Service 779887
    if (object_path && message_received_func)
Packit Service 779887
    {
Packit Service 779887
        /* Table */
Packit Service 779887
        const DBusObjectPathVTable vtable = {
Packit Service 779887
            /* .unregister_function = */ unregister_vtable,
Packit Service 779887
            /* .message_function    = */ message_received_func,
Packit Service 779887
        };
Packit Service 779887
        log_debug("dbus_connection_register_object_path");
Packit Service 779887
        if (!dbus_connection_register_object_path(conn,
Packit Service 779887
                    object_path,
Packit Service 779887
                    &vtable,
Packit Service 779887
                    NULL /* data */
Packit Service 779887
                    )
Packit Service 779887
        ) {
Packit Service 779887
            die_out_of_memory();
Packit Service 779887
        }
Packit Service 779887
    }
Packit Service 779887
}