00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <glib/gslist.h>
00023 #include <glib/gthread.h>
00024 #include <glib/gmessages.h>
00025 #include <glib/gstrfuncs.h>
00026 #include <string.h>
00027 #include <libosso.h>
00028 #include <osso-log.h>
00029 #include "rpc-dbus.h"
00030
00031 #define SERVICE_STARTED_SIGNAL "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',arg0='%s'"
00032
00033 static DBusHandlerResult _service_started(DBusConnection *connection, DBusMessage *message, void *user_data);
00034 static osso_context_t *_osso = NULL;
00035
00036 typedef struct _DBusNameNotify {
00037 gchar *name;
00038 gchar *match;
00039 DBusNameNotifyCb cb;
00040 gpointer user_data;
00041 } DBusNameNotify;
00042
00043 static GSList *service_notifies = NULL;
00044 static DBusConnection *system_bus = NULL;
00045 static GStaticMutex notify_mutex = G_STATIC_MUTEX_INIT;
00046
00047 void dbus_do_call(DBusConnection *bus, DBusMessage **reply, gboolean activation, const gchar *service, const gchar *path, const gchar *interface, const gchar *name, int first_arg_type, ...)
00048 {
00049 DBusMessage *msg = NULL;
00050 va_list arg_list;
00051 DBusError error;
00052
00053 if (!bus || !path || !interface) {
00054 DLOG_WARN("dbus_do_call called with NULL arguments.");
00055 return;
00056 }
00057
00058 if (service) {
00059 msg = dbus_message_new_method_call(service,
00060 path,
00061 interface,
00062 name);
00063 if (reply == NULL) {
00064 dbus_message_set_no_reply(msg, TRUE);
00065 }
00066 dbus_message_set_auto_start(msg, activation);
00067 } else {
00068 msg = dbus_message_new_signal(path,
00069 interface,
00070 name);
00071 }
00072
00073 if (!msg) {
00074 DLOG_WARN("DBus message creation failed.");
00075 return;
00076 }
00077
00078 va_start(arg_list, first_arg_type);
00079
00080 dbus_message_append_args_valist(msg, first_arg_type, arg_list);
00081
00082 va_end(arg_list);
00083
00084 dbus_error_init(&error);
00085 if (reply != NULL) {
00086 *reply = dbus_connection_send_with_reply_and_block(bus, msg, -1, &error);
00087 } else {
00088 dbus_connection_send(bus, msg, NULL);
00089 }
00090 if (dbus_error_is_set(&error)) {
00091 DLOG_WARN("DBus error: %s", error.message);
00092 dbus_message_unref(msg);
00093 dbus_error_free(&error);
00094 return;
00095 }
00096 dbus_message_unref(msg);
00097 }
00098
00099 void dbus_watch_name(const gchar *name, DBusNameNotifyCb cb, gpointer user_data)
00100 {
00101 g_static_mutex_lock(¬ify_mutex);
00102 gboolean has_owner;
00103
00104 if (system_bus == NULL) {
00105 system_bus = get_dbus_connection(DBUS_BUS_SYSTEM);
00106 dbus_connection_add_filter(system_bus, _service_started, NULL, NULL);
00107 }
00108
00109 has_owner = dbus_bus_name_has_owner(system_bus, name, NULL);
00110 if (!has_owner) {
00111 DBusNameNotify *notify = g_new0(DBusNameNotify, 1);
00112 notify->cb = cb;
00113 notify->user_data = user_data;
00114 notify->name = g_strdup(name);
00115 notify->match = g_strdup_printf(SERVICE_STARTED_SIGNAL,
00116 name);
00117 service_notifies = g_slist_prepend(service_notifies, notify);
00118 dbus_bus_add_match(system_bus, notify->match, NULL);
00119 }
00120
00121 if (service_notifies == NULL) {
00122 dbus_connection_remove_filter(system_bus, _service_started, NULL);
00123 dbus_connection_unref(system_bus);
00124 system_bus = NULL;
00125 }
00126 g_static_mutex_unlock(¬ify_mutex);
00127
00128 if (has_owner) {
00129 cb(user_data);
00130 }
00131 }
00132
00133 void dbus_unwatch_name(const gchar *name, DBusNameNotifyCb cb, gpointer user_data)
00134 {
00135 GSList *iter;
00136 g_static_mutex_lock(¬ify_mutex);
00137 for (iter = service_notifies; iter != NULL; iter = iter->next) {
00138 DBusNameNotify *notify = (DBusNameNotify *)iter->data;
00139
00140 if (notify->cb == cb &&
00141 notify->user_data == user_data &&
00142 strcmp(notify->name, name) == 0) {
00143 dbus_bus_remove_match(system_bus,
00144 notify->match, NULL);
00145 g_free(notify->match);
00146 g_free(notify->name);
00147 g_free(notify);
00148 service_notifies = g_slist_delete_link(service_notifies, iter);
00149 break;
00150 }
00151 }
00152 if (service_notifies == NULL && system_bus != NULL) {
00153 dbus_connection_remove_filter(system_bus, _service_started, NULL);
00154 dbus_connection_unref(system_bus);
00155 system_bus = NULL;
00156 }
00157 g_static_mutex_unlock(¬ify_mutex);
00158 }
00159
00160 static DBusHandlerResult _service_started(DBusConnection *connection, DBusMessage *message, void *user_data)
00161 {
00162 (void)connection;
00163 (void)user_data;
00164
00165 if (dbus_message_is_signal(message, DBUS_SERVICE_DBUS, "NameOwnerChanged")) {
00166 GSList *iter;
00167 GSList *found = NULL;
00168 const gchar *name = NULL;
00169 dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID);
00170 g_static_mutex_lock(¬ify_mutex);
00171 iter = service_notifies;
00172 while (iter != NULL) {
00173 DBusNameNotify *notify = (DBusNameNotify *)iter->data;
00174 GSList *this = iter;
00175
00176 iter = iter->next;
00177
00178 if (strcmp(notify->name, name) == 0) {
00179 service_notifies = g_slist_remove_link(service_notifies, this);
00180 found = g_slist_concat(found, this);
00181 dbus_bus_remove_match(system_bus,
00182 notify->match, NULL);
00183 g_free(notify->match);
00184 }
00185
00186 if (service_notifies == NULL) {
00187 dbus_connection_remove_filter(system_bus, _service_started, NULL);
00188 dbus_connection_unref(system_bus);
00189 system_bus = NULL;
00190 }
00191 }
00192 g_static_mutex_unlock(¬ify_mutex);
00193 while (found) {
00194 DBusNameNotify *notify = (DBusNameNotify *)found->data;
00195
00196 notify->cb(notify->user_data);
00197 g_free(notify->name);
00198 g_free(notify);
00199
00200 found = g_slist_delete_link(found, found);
00201 }
00202 }
00203 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00204 }
00205
00206 void dbus_set_osso(osso_context_t *osso) {
00207 _osso = osso;
00208 }
00209
00210 DBusConnection *get_dbus_connection(DBusBusType type) {
00211 DBusConnection *conn;
00212 switch (type) {
00213 case DBUS_BUS_SYSTEM:
00214 conn = osso_get_sys_dbus_connection(_osso);
00215 break;
00216 default:
00217 conn = osso_get_dbus_connection(_osso);
00218 break;
00219 }
00220 dbus_connection_ref(conn);
00221 return conn;
00222 }