From 83a6ce9ad4b1828e163dc7172ef603201b748473 Mon Sep 17 00:00:00 2001 From: Nikola Pajkovsky Date: Tue, 10 Aug 2010 10:21:25 +0200 Subject: lower case direcotry(no code changed) Signed-off-by: Nikola Pajkovsky --- lib/utils/abrt_dbus.cpp | 430 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 430 insertions(+) create mode 100644 lib/utils/abrt_dbus.cpp (limited to 'lib/utils/abrt_dbus.cpp') diff --git a/lib/utils/abrt_dbus.cpp b/lib/utils/abrt_dbus.cpp new file mode 100644 index 00000000..4319d103 --- /dev/null +++ b/lib/utils/abrt_dbus.cpp @@ -0,0 +1,430 @@ +/* + Copyright (C) 2010 ABRT team + Copyright (C) 2010 RedHat Inc + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include +#include +#include "abrtlib.h" +#include "abrt_dbus.h" + +DBusConnection* g_dbus_conn; + + +/* + * Helpers for building DBus messages + */ + +//void store_bool(DBusMessageIter* iter, bool val) +//{ +// dbus_bool_t db = val; +// if (!dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &db)) +// die_out_of_memory(); +//} +void store_int32(DBusMessageIter* iter, int32_t val) +{ + if (!dbus_message_iter_append_basic(iter, DBUS_TYPE_INT32, &val)) + die_out_of_memory(); +} +void store_uint32(DBusMessageIter* iter, uint32_t val) +{ + if (!dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &val)) + die_out_of_memory(); +} +void store_int64(DBusMessageIter* iter, int64_t val) +{ + if (!dbus_message_iter_append_basic(iter, DBUS_TYPE_INT64, &val)) + die_out_of_memory(); +} +void store_uint64(DBusMessageIter* iter, uint64_t val) +{ + if (!dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT64, &val)) + die_out_of_memory(); +} + +/* dbus daemon will simply close our connection if we send broken utf8. + * Therefore we must never do that. + */ +static char *sanitize_utf8(const char *src) +{ + const char *initial_src = src; + char *sanitized = NULL; + unsigned sanitized_pos = 0; + + while (*src) + { + int bytes = 0; + + unsigned c = (unsigned char) *src; + if (c <= 0x7f) + { + bytes = 1; + goto good_byte; + } + + /* Unicode -> utf8: */ + /* 80-7FF -> 110yyyxx 10xxxxxx */ + /* 800-FFFF -> 1110yyyy 10yyyyxx 10xxxxxx */ + /* 10000-1FFFFF -> 11110zzz 10zzyyyy 10yyyyxx 10xxxxxx */ + /* 200000-3FFFFFF -> 111110tt 10zzzzzz 10zzyyyy 10yyyyxx 10xxxxxx */ + /* 4000000-FFFFFFFF -> 111111tt 10tttttt 10zzzzzz 10zzyyyy 10yyyyxx 10xxxxxx */ + do { + c <<= 1; + bytes++; + } while ((c & 0x80) && bytes < 6); + if (bytes == 1) + { + /* A bare "continuation" byte. Say, 80 */ + goto bad_byte; + } + + c = (uint8_t)(c) >> bytes; + { + const char *pp = src; + int cnt = bytes; + while (--cnt) + { + unsigned ch = (unsigned char) *++pp; + if ((ch & 0xc0) != 0x80) /* Missing "continuation" byte. Example: e0 80 */ + { + goto bad_byte; + } + c = (c << 6) + (ch & 0x3f); + } + } + /* TODO */ + /* Need to check that c isn't produced by overlong encoding */ + /* Example: 11000000 10000000 converts to NUL */ + /* 11110000 10000000 10000100 10000000 converts to 0x100 */ + /* correct encoding: 11000100 10000000 */ + if (c <= 0x7f) /* crude check: only catches bad encodings which map to chars <= 7f */ + { + goto bad_byte; + } + + good_byte: + while (--bytes >= 0) + { + c = (unsigned char) *src++; + if (sanitized) + { + sanitized = (char*) xrealloc(sanitized, sanitized_pos + 2); + sanitized[sanitized_pos++] = c; + sanitized[sanitized_pos] = '\0'; + } + } + continue; + + bad_byte: + if (!sanitized) + { + sanitized_pos = src - initial_src; + sanitized = xstrndup(initial_src, sanitized_pos); + } + sanitized = (char*) xrealloc(sanitized, sanitized_pos + 5); + sanitized[sanitized_pos++] = '['; + c = (unsigned char) *src++; + sanitized[sanitized_pos++] = "0123456789ABCDEF"[c >> 4]; + sanitized[sanitized_pos++] = "0123456789ABCDEF"[c & 0xf]; + sanitized[sanitized_pos++] = ']'; + sanitized[sanitized_pos] = '\0'; + } + + if (sanitized) + VERB2 log("note: bad utf8, converted '%s' -> '%s'", initial_src, sanitized); + + return sanitized; /* usually NULL: the whole string is ok */ +} +void store_string(DBusMessageIter* iter, const char* val) +{ + const char *sanitized = sanitize_utf8(val); + if (!dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, sanitized ? &sanitized : &val)) + die_out_of_memory(); + free((char*)sanitized); +} + + +/* + * Helpers for parsing DBus messages + */ + +//int load_bool(DBusMessageIter* iter, bool& val) +//{ +// int type = dbus_message_iter_get_arg_type(iter); +// if (type != DBUS_TYPE_BOOLEAN) +// error_msg_and_die("%s expected in dbus message, but not found ('%c')", "bool", type); +// dbus_bool_t db; +// dbus_message_iter_get_basic(iter, &db); +// val = db; +// return dbus_message_iter_next(iter); +//} +int load_int32(DBusMessageIter* iter, int32_t& val) +{ + int type = dbus_message_iter_get_arg_type(iter); + if (type != DBUS_TYPE_INT32) + { + error_msg("%s expected in dbus message, but not found ('%c')", "int32", type); + return -1; + } + dbus_message_iter_get_basic(iter, &val); + return dbus_message_iter_next(iter); +} +int load_uint32(DBusMessageIter* iter, uint32_t& val) +{ + int type = dbus_message_iter_get_arg_type(iter); + if (type != DBUS_TYPE_UINT32) + { + error_msg("%s expected in dbus message, but not found ('%c')", "uint32", type); + return -1; + } + dbus_message_iter_get_basic(iter, &val); + return dbus_message_iter_next(iter); +} +int load_int64(DBusMessageIter* iter, int64_t& val) +{ + int type = dbus_message_iter_get_arg_type(iter); + if (type != DBUS_TYPE_INT64) + { + error_msg("%s expected in dbus message, but not found ('%c')", "int64", type); + return -1; + } + dbus_message_iter_get_basic(iter, &val); + return dbus_message_iter_next(iter); +} +int load_uint64(DBusMessageIter* iter, uint64_t& val) +{ + int type = dbus_message_iter_get_arg_type(iter); + if (type != DBUS_TYPE_UINT64) + { + error_msg("%s expected in dbus message, but not found ('%c')", "uint64", type); + return -1; + } + dbus_message_iter_get_basic(iter, &val); + return dbus_message_iter_next(iter); +} +int load_charp(DBusMessageIter* iter, const char*& val) +{ + int type = dbus_message_iter_get_arg_type(iter); + if (type != DBUS_TYPE_STRING) + { + error_msg("%s expected in dbus message, but not found ('%c')", "string", type); + return -1; + } + dbus_message_iter_get_basic(iter, &val); +//log("load_charp:'%s'", val); + return dbus_message_iter_next(iter); +} + + +/* + * Glib integration machinery + */ + +/* Callback: "glib says dbus fd is active" */ +static gboolean handle_dbus_fd(GIOChannel *gio, GIOCondition condition, gpointer data) +{ + DBusWatch *watch = (DBusWatch*)data; + + VERB3 log("%s(gio, condition:%x [bits:IN/PRI/OUT/ERR/HUP...], data)", __func__, int(condition)); + + /* Notify the D-Bus library when a previously-added watch + * is ready for reading or writing, or has an exception such as a hangup. + */ + int glib_flags = int(condition); + int dbus_flags = 0; + if (glib_flags & G_IO_IN) dbus_flags |= DBUS_WATCH_READABLE; + if (glib_flags & G_IO_OUT) dbus_flags |= DBUS_WATCH_WRITABLE; + if (glib_flags & G_IO_ERR) dbus_flags |= DBUS_WATCH_ERROR; + if (glib_flags & G_IO_HUP) dbus_flags |= DBUS_WATCH_HANGUP; + /* + * TODO: + * If dbus_watch_handle returns FALSE, then the file descriptor + * may still be ready for reading or writing, but more memory + * is needed in order to do the reading or writing. If you ignore + * the FALSE return, your application may spin in a busy loop + * on the file descriptor until memory becomes available, + * but nothing more catastrophic should happen. + */ + dbus_watch_handle(watch, dbus_flags); + + while (dbus_connection_dispatch(g_dbus_conn) == DBUS_DISPATCH_DATA_REMAINS) + VERB3 log("%s: more data to process, looping", __func__); + return TRUE; /* "glib, do not remove this event source!" */ +} + +struct watch_app_info_t +{ + GIOChannel *channel; + guint event_source_id; + bool watch_enabled; +}; +/* Callback: "dbus_watch_get_enabled() may return a different value than it did before" */ +static void toggled_watch(DBusWatch *watch, void* data) +{ + VERB3 log("%s(watch:%p, data)", __func__, watch); + + watch_app_info_t* app_info = (watch_app_info_t*)dbus_watch_get_data(watch); + if (dbus_watch_get_enabled(watch)) + { + if (!app_info->watch_enabled) + { + app_info->watch_enabled = true; + int dbus_flags = dbus_watch_get_flags(watch); + int glib_flags = 0; + if (dbus_flags & DBUS_WATCH_READABLE) glib_flags |= G_IO_IN; + if (dbus_flags & DBUS_WATCH_WRITABLE) glib_flags |= G_IO_OUT; + VERB3 log(" adding watch to glib main loop. dbus_flags:%x glib_flags:%x", dbus_flags, glib_flags); + app_info->event_source_id = g_io_add_watch(app_info->channel, GIOCondition(glib_flags), handle_dbus_fd, watch); + } + /* else: it was already enabled */ + } else { + if (app_info->watch_enabled) + { + app_info->watch_enabled = false; + /* does it free the hidden GSource too? */ + VERB3 log(" removing watch from glib main loop"); + g_source_remove(app_info->event_source_id); + } + /* else: it was already disabled */ + } +} +/* Callback: "libdbus needs a new watch to be monitored by the main loop" */ +static dbus_bool_t add_watch(DBusWatch *watch, void* data) +{ + VERB3 log("%s(watch:%p, data)", __func__, watch); + + watch_app_info_t* app_info = (watch_app_info_t*)xzalloc(sizeof(*app_info)); + dbus_watch_set_data(watch, app_info, free); + + int fd = dbus_watch_get_unix_fd(watch); + VERB3 log(" dbus_watch_get_unix_fd():%d", fd); + app_info->channel = g_io_channel_unix_new(fd); + /* _unconditionally_ adding it to event loop would be an error */ + toggled_watch(watch, data); + return TRUE; +} +/* Callback: "libdbus no longer needs a watch to be monitored by the main loop" */ +static void remove_watch(DBusWatch *watch, void* data) +{ + VERB3 log("%s()", __func__); + watch_app_info_t* app_info = (watch_app_info_t*)dbus_watch_get_data(watch); + if (app_info->watch_enabled) + { + app_info->watch_enabled = false; + g_source_remove(app_info->event_source_id); + } + g_io_channel_unref(app_info->channel); +} + +/* Callback: "libdbus needs a new timeout to be monitored by the main loop" */ +static dbus_bool_t add_timeout(DBusTimeout *timeout, void* data) +{ + VERB3 log("%s()", __func__); + return TRUE; +} +/* Callback: "libdbus no longer needs a timeout to be monitored by the main loop" */ +static void remove_timeout(DBusTimeout *timeout, void* data) +{ + VERB3 log("%s()", __func__); +} +/* Callback: "dbus_timeout_get_enabled() may return a different value than it did before" */ +static void timeout_toggled(DBusTimeout *timeout, void* data) +{ +//seems to be never called, let's make it noisy + error_msg_and_die("%s(): FIXME: some dbus machinery is missing here", __func__); +} + +/* Callback: "DBusObjectPathVTable is unregistered (or its connection is freed)" */ +static void unregister_vtable(DBusConnection *conn, void* data) +{ + VERB3 log("%s()", __func__); +} + +/* + * Initialization works as follows: + * + * we have a DBusConnection* (say, obtained with dbus_bus_get) + * we call dbus_connection_set_watch_functions + * libdbus calls back add_watch(watch:0x2341090, data), this watch is for writing + * we call toggled_watch, but it finds that watch is not to be enabled yet + * libdbus calls back add_watch(watch:0x23410e0, data), this watch is for reading + * we call toggled_watch, it adds watch's fd to glib main loop with POLLIN + * (note: these watches are different objects, but they have the same fd) + * we call dbus_connection_set_timeout_functions + * we call dbus_connection_register_object_path + * + * Note: if user will later call dbus_bus_request_name(conn, ...): + * libdbus calls back add_timeout() + * libdbus calls back remove_timeout() + * note - no callback to timeout_toggled()! + * (therefore there is no code yet in timeout_toggled (see above), it's not used) + */ +void attach_dbus_conn_to_glib_main_loop(DBusConnection* conn, + const char* object_path, + DBusHandlerResult (*message_received_func)(DBusConnection *conn, DBusMessage *msg, void* data) +) { + if (g_dbus_conn) + error_msg_and_die("Internal bug: can't connect to more than one dbus"); + g_dbus_conn = conn; + +//do we need this? why? +//log("dbus_connection_set_dispatch_status_function"); +// dbus_connection_set_dispatch_status_function(conn, +// dispatch, /* void dispatch(DBusConnection *conn, DBusDispatchStatus new_status, void* data) */ +// NULL, /* data */ +// NULL /* free_data_function */ +// ) + VERB3 log("dbus_connection_set_watch_functions"); + if (!dbus_connection_set_watch_functions(conn, + add_watch, + remove_watch, + toggled_watch, + NULL, /* data */ + NULL /* free_data_function */ + ) + ) { + die_out_of_memory(); + } + VERB3 log("dbus_connection_set_timeout_functions"); + if (!dbus_connection_set_timeout_functions(conn, + add_timeout, + remove_timeout, + timeout_toggled, + NULL, /* data */ + NULL /* free_data_function */ + ) + ) { + die_out_of_memory(); + } + + if (object_path && message_received_func) + { + /* Table */ + const DBusObjectPathVTable vtable = { + /* .unregister_function = */ unregister_vtable, + /* .message_function = */ message_received_func, + }; + VERB3 log("dbus_connection_register_object_path"); + if (!dbus_connection_register_object_path(conn, + object_path, + &vtable, + NULL /* data */ + ) + ) { + die_out_of_memory(); + } + } +} -- cgit