Main Page | Data Structures | File List | Data Fields | Globals

rpc-dbus.c

Go to the documentation of this file.
00001 /**
00002  * This file is part of alarmd
00003  *
00004  * Contact Person: David Weinehall <david.weinehall@nokia.com>
00005  *
00006  * Copyright (C) 2006 Nokia Corporation
00007  * alarmd and libalarm are free software; you can redistribute them
00008  * and/or modify them under the terms of the GNU Lesser General Public
00009  * License version 2.1 as published by the Free Software Foundation.
00010  *
00011  * alarmd and libalarm are distributed in the hope that they will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with this software; if not, write to the Free
00018  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
00019  * 02110-1301 USA
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(&notify_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(&notify_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(&notify_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(&notify_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(&notify_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(&notify_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 }

Generated on Thu Dec 21 18:23:30 2006 for Alarmd by  doxygen 1.4.2