| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531 |
- // SPDX-License-Identifier: GPL-2.0-or-later
- /*
- *
- * D-Bus helper library
- *
- * Copyright (C) 2004-2011 Marcel Holtmann <marcel@holtmann.org>
- *
- *
- */
- #ifdef HAVE_CONFIG_H
- #include <config.h>
- #endif
- #define _GNU_SOURCE
- #include <stdio.h>
- #include <string.h>
- #include <glib.h>
- #include <dbus/dbus.h>
- #include "gdbus.h"
- #define METHOD_CALL_TIMEOUT (300 * 1000)
- #ifndef DBUS_INTERFACE_OBJECT_MANAGER
- #define DBUS_INTERFACE_OBJECT_MANAGER DBUS_INTERFACE_DBUS ".ObjectManager"
- #endif
- struct GDBusClient {
- int ref_count;
- DBusConnection *dbus_conn;
- char *service_name;
- char *base_path;
- char *root_path;
- guint watch;
- guint added_watch;
- guint removed_watch;
- GPtrArray *match_rules;
- DBusPendingCall *pending_call;
- DBusPendingCall *get_objects_call;
- GDBusWatchFunction connect_func;
- void *connect_data;
- GDBusWatchFunction disconn_func;
- gboolean connected;
- void *disconn_data;
- GDBusMessageFunction signal_func;
- void *signal_data;
- GDBusProxyFunction proxy_added;
- GDBusProxyFunction proxy_removed;
- GDBusClientFunction ready;
- void *ready_data;
- GDBusPropertyFunction property_changed;
- void *user_data;
- GList *proxy_list;
- };
- struct GDBusProxy {
- int ref_count;
- GDBusClient *client;
- char *obj_path;
- char *interface;
- GHashTable *prop_list;
- guint watch;
- GDBusPropertyFunction prop_func;
- void *prop_data;
- GDBusProxyFunction removed_func;
- void *removed_data;
- DBusPendingCall *get_all_call;
- gboolean pending;
- };
- struct prop_entry {
- char *name;
- int type;
- DBusMessage *msg;
- };
- static void modify_match_reply(DBusPendingCall *call, void *user_data)
- {
- DBusMessage *reply = dbus_pending_call_steal_reply(call);
- DBusError error;
- dbus_error_init(&error);
- if (dbus_set_error_from_message(&error, reply) == TRUE)
- dbus_error_free(&error);
- dbus_message_unref(reply);
- }
- static gboolean modify_match(DBusConnection *conn, const char *member,
- const char *rule)
- {
- DBusMessage *msg;
- DBusPendingCall *call;
- msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
- DBUS_INTERFACE_DBUS, member);
- if (msg == NULL)
- return FALSE;
- dbus_message_append_args(msg, DBUS_TYPE_STRING, &rule,
- DBUS_TYPE_INVALID);
- if (g_dbus_send_message_with_reply(conn, msg, &call, -1) == FALSE) {
- dbus_message_unref(msg);
- return FALSE;
- }
- dbus_pending_call_set_notify(call, modify_match_reply, NULL, NULL);
- dbus_pending_call_unref(call);
- dbus_message_unref(msg);
- return TRUE;
- }
- static void append_variant(DBusMessageIter *iter, int type, const void *val)
- {
- DBusMessageIter value;
- char sig[2] = { type, '\0' };
- dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, sig, &value);
- dbus_message_iter_append_basic(&value, type, val);
- dbus_message_iter_close_container(iter, &value);
- }
- static void append_array_variant(DBusMessageIter *iter, int type, void *val,
- int n_elements)
- {
- DBusMessageIter variant, array;
- char type_sig[2] = { type, '\0' };
- char array_sig[3] = { DBUS_TYPE_ARRAY, type, '\0' };
- dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
- array_sig, &variant);
- dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
- type_sig, &array);
- if (dbus_type_is_fixed(type) == TRUE) {
- dbus_message_iter_append_fixed_array(&array, type, val,
- n_elements);
- } else if (type == DBUS_TYPE_STRING || type == DBUS_TYPE_OBJECT_PATH) {
- const char ***str_array = val;
- int i;
- for (i = 0; i < n_elements; i++)
- dbus_message_iter_append_basic(&array, type,
- &((*str_array)[i]));
- }
- dbus_message_iter_close_container(&variant, &array);
- dbus_message_iter_close_container(iter, &variant);
- }
- static void dict_append_basic(DBusMessageIter *dict, int key_type,
- const void *key, int type, void *val)
- {
- DBusMessageIter entry;
- if (type == DBUS_TYPE_STRING) {
- const char *str = *((const char **) val);
- if (str == NULL)
- return;
- }
- dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
- NULL, &entry);
- dbus_message_iter_append_basic(&entry, key_type, key);
- append_variant(&entry, type, val);
- dbus_message_iter_close_container(dict, &entry);
- }
- void g_dbus_dict_append_entry(DBusMessageIter *dict,
- const char *key, int type, void *val)
- {
- dict_append_basic(dict, DBUS_TYPE_STRING, &key, type, val);
- }
- void g_dbus_dict_append_basic_array(DBusMessageIter *dict, int key_type,
- const void *key, int type, void *val,
- int n_elements)
- {
- DBusMessageIter entry;
- dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
- NULL, &entry);
- dbus_message_iter_append_basic(&entry, key_type, key);
- append_array_variant(&entry, type, val, n_elements);
- dbus_message_iter_close_container(dict, &entry);
- }
- void g_dbus_dict_append_array(DBusMessageIter *dict,
- const char *key, int type, void *val,
- int n_elements)
- {
- g_dbus_dict_append_basic_array(dict, DBUS_TYPE_STRING, &key, type, val,
- n_elements);
- }
- static void iter_append_iter(DBusMessageIter *base, DBusMessageIter *iter)
- {
- int type;
- type = dbus_message_iter_get_arg_type(iter);
- if (dbus_type_is_basic(type)) {
- const void *value;
- dbus_message_iter_get_basic(iter, &value);
- dbus_message_iter_append_basic(base, type, &value);
- } else if (dbus_type_is_container(type)) {
- DBusMessageIter iter_sub, base_sub;
- char *sig;
- dbus_message_iter_recurse(iter, &iter_sub);
- switch (type) {
- case DBUS_TYPE_ARRAY:
- case DBUS_TYPE_VARIANT:
- sig = dbus_message_iter_get_signature(&iter_sub);
- break;
- default:
- sig = NULL;
- break;
- }
- dbus_message_iter_open_container(base, type, sig, &base_sub);
- if (sig != NULL)
- dbus_free(sig);
- while (dbus_message_iter_get_arg_type(&iter_sub) !=
- DBUS_TYPE_INVALID) {
- iter_append_iter(&base_sub, &iter_sub);
- dbus_message_iter_next(&iter_sub);
- }
- dbus_message_iter_close_container(base, &base_sub);
- }
- }
- static void prop_entry_update(struct prop_entry *prop, DBusMessageIter *iter)
- {
- DBusMessage *msg;
- DBusMessageIter base;
- msg = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN);
- if (msg == NULL)
- return;
- dbus_message_iter_init_append(msg, &base);
- iter_append_iter(&base, iter);
- if (prop->msg != NULL)
- dbus_message_unref(prop->msg);
- prop->msg = dbus_message_copy(msg);
- dbus_message_unref(msg);
- }
- static struct prop_entry *prop_entry_new(const char *name,
- DBusMessageIter *iter)
- {
- struct prop_entry *prop;
- prop = g_try_new0(struct prop_entry, 1);
- if (prop == NULL)
- return NULL;
- prop->name = g_strdup(name);
- prop->type = dbus_message_iter_get_arg_type(iter);
- prop_entry_update(prop, iter);
- return prop;
- }
- static void prop_entry_free(gpointer data)
- {
- struct prop_entry *prop = data;
- if (prop->msg != NULL)
- dbus_message_unref(prop->msg);
- g_free(prop->name);
- g_free(prop);
- }
- static void add_property(GDBusProxy *proxy, const char *name,
- DBusMessageIter *iter, gboolean send_changed)
- {
- GDBusClient *client = proxy->client;
- DBusMessageIter value;
- struct prop_entry *prop;
- if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT)
- return;
- dbus_message_iter_recurse(iter, &value);
- prop = g_hash_table_lookup(proxy->prop_list, name);
- if (prop != NULL) {
- prop_entry_update(prop, &value);
- goto done;
- }
- prop = prop_entry_new(name, &value);
- if (prop == NULL)
- return;
- g_hash_table_replace(proxy->prop_list, prop->name, prop);
- done:
- if (proxy->prop_func)
- proxy->prop_func(proxy, name, &value, proxy->prop_data);
- if (client == NULL || send_changed == FALSE)
- return;
- if (client->property_changed)
- client->property_changed(proxy, name, &value,
- client->user_data);
- }
- static void update_properties(GDBusProxy *proxy, DBusMessageIter *iter,
- gboolean send_changed)
- {
- DBusMessageIter dict;
- if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
- return;
- dbus_message_iter_recurse(iter, &dict);
- while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
- DBusMessageIter entry;
- const char *name;
- dbus_message_iter_recurse(&dict, &entry);
- if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
- break;
- dbus_message_iter_get_basic(&entry, &name);
- dbus_message_iter_next(&entry);
- add_property(proxy, name, &entry, send_changed);
- dbus_message_iter_next(&dict);
- }
- }
- static void proxy_added(GDBusClient *client, GDBusProxy *proxy)
- {
- if (!proxy->pending)
- return;
- if (client->proxy_added)
- client->proxy_added(proxy, client->user_data);
- proxy->pending = FALSE;
- }
- static void get_all_properties_reply(DBusPendingCall *call, void *user_data)
- {
- GDBusProxy *proxy = user_data;
- GDBusClient *client = proxy->client;
- DBusMessage *reply = dbus_pending_call_steal_reply(call);
- DBusMessageIter iter;
- DBusError error;
- g_dbus_client_ref(client);
- dbus_error_init(&error);
- if (dbus_set_error_from_message(&error, reply) == TRUE) {
- dbus_error_free(&error);
- goto done;
- }
- dbus_message_iter_init(reply, &iter);
- update_properties(proxy, &iter, FALSE);
- done:
- proxy_added(client, proxy);
- dbus_message_unref(reply);
- dbus_pending_call_unref(proxy->get_all_call);
- proxy->get_all_call = NULL;
- g_dbus_client_unref(client);
- }
- static void get_all_properties(GDBusProxy *proxy)
- {
- GDBusClient *client = proxy->client;
- const char *service_name = client->service_name;
- DBusMessage *msg;
- if (proxy->get_all_call)
- return;
- msg = dbus_message_new_method_call(service_name, proxy->obj_path,
- DBUS_INTERFACE_PROPERTIES, "GetAll");
- if (msg == NULL)
- return;
- dbus_message_append_args(msg, DBUS_TYPE_STRING, &proxy->interface,
- DBUS_TYPE_INVALID);
- if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
- &proxy->get_all_call, -1) == FALSE) {
- dbus_message_unref(msg);
- return;
- }
- dbus_pending_call_set_notify(proxy->get_all_call,
- get_all_properties_reply, proxy, NULL);
- dbus_message_unref(msg);
- }
- GDBusProxy *g_dbus_proxy_lookup(GList *list, int *index, const char *path,
- const char *interface)
- {
- GList *l;
- if (!interface)
- return NULL;
- for (l = g_list_nth(list, index ? *index : 0); l; l = g_list_next(l)) {
- GDBusProxy *proxy = l->data;
- const char *proxy_iface = g_dbus_proxy_get_interface(proxy);
- const char *proxy_path = g_dbus_proxy_get_path(proxy);
- if (index)
- (*index)++;
- if (g_str_equal(proxy_iface, interface) == TRUE &&
- g_str_equal(proxy_path, path) == TRUE)
- return proxy;
- }
- return NULL;
- }
- char *g_dbus_proxy_path_lookup(GList *list, int *index, const char *path)
- {
- int len = strlen(path);
- GList *l;
- for (l = g_list_nth(list, index ? *index : 0); l; l = g_list_next(l)) {
- GDBusProxy *proxy = l->data;
- const char *proxy_path = g_dbus_proxy_get_path(proxy);
- if (index)
- (*index)++;
- if (!strncasecmp(proxy_path, path, len))
- return strdup(proxy_path);
- }
- return NULL;
- }
- static gboolean properties_changed(DBusConnection *conn, DBusMessage *msg,
- void *user_data)
- {
- GDBusProxy *proxy = user_data;
- GDBusClient *client = proxy->client;
- DBusMessageIter iter, entry;
- const char *interface;
- if (dbus_message_iter_init(msg, &iter) == FALSE)
- return TRUE;
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
- return TRUE;
- dbus_message_iter_get_basic(&iter, &interface);
- dbus_message_iter_next(&iter);
- update_properties(proxy, &iter, TRUE);
- dbus_message_iter_next(&iter);
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
- return TRUE;
- dbus_message_iter_recurse(&iter, &entry);
- while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
- const char *name;
- dbus_message_iter_get_basic(&entry, &name);
- g_hash_table_remove(proxy->prop_list, name);
- if (proxy->prop_func)
- proxy->prop_func(proxy, name, NULL, proxy->prop_data);
- if (client->property_changed)
- client->property_changed(proxy, name, NULL,
- client->user_data);
- dbus_message_iter_next(&entry);
- }
- return TRUE;
- }
- static GDBusProxy *proxy_new(GDBusClient *client, const char *path,
- const char *interface)
- {
- GDBusProxy *proxy;
- proxy = g_try_new0(GDBusProxy, 1);
- if (proxy == NULL)
- return NULL;
- proxy->client = client;
- proxy->obj_path = g_strdup(path);
- proxy->interface = g_strdup(interface);
- proxy->prop_list = g_hash_table_new_full(g_str_hash, g_str_equal,
- NULL, prop_entry_free);
- proxy->watch = g_dbus_add_properties_watch(client->dbus_conn,
- client->service_name,
- proxy->obj_path,
- proxy->interface,
- properties_changed,
- proxy, NULL);
- proxy->pending = TRUE;
- client->proxy_list = g_list_append(client->proxy_list, proxy);
- return g_dbus_proxy_ref(proxy);
- }
- static void proxy_free(gpointer data)
- {
- GDBusProxy *proxy = data;
- if (proxy->client) {
- GDBusClient *client = proxy->client;
- if (proxy->get_all_call != NULL) {
- dbus_pending_call_cancel(proxy->get_all_call);
- dbus_pending_call_unref(proxy->get_all_call);
- proxy->get_all_call = NULL;
- }
- if (client->proxy_removed)
- client->proxy_removed(proxy, client->user_data);
- g_dbus_remove_watch(client->dbus_conn, proxy->watch);
- g_hash_table_remove_all(proxy->prop_list);
- proxy->client = NULL;
- }
- if (proxy->removed_func)
- proxy->removed_func(proxy, proxy->removed_data);
- g_dbus_proxy_unref(proxy);
- }
- static void proxy_remove(GDBusClient *client, const char *path,
- const char *interface)
- {
- GList *list;
- for (list = g_list_first(client->proxy_list); list;
- list = g_list_next(list)) {
- GDBusProxy *proxy = list->data;
- if (g_str_equal(proxy->interface, interface) == TRUE &&
- g_str_equal(proxy->obj_path, path) == TRUE) {
- client->proxy_list =
- g_list_delete_link(client->proxy_list, list);
- proxy_free(proxy);
- break;
- }
- }
- }
- static void start_service(GDBusProxy *proxy)
- {
- GDBusClient *client = proxy->client;
- const char *service_name = client->service_name;
- dbus_uint32_t flags = 0;
- DBusMessage *msg;
- msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
- DBUS_INTERFACE_DBUS,
- "StartServiceByName");
- if (msg == NULL)
- return;
- dbus_message_append_args(msg, DBUS_TYPE_STRING, &service_name,
- DBUS_TYPE_UINT32, &flags,
- DBUS_TYPE_INVALID);
- g_dbus_send_message(client->dbus_conn, msg);
- return;
- }
- GDBusProxy *g_dbus_proxy_new(GDBusClient *client, const char *path,
- const char *interface)
- {
- GDBusProxy *proxy;
- if (client == NULL)
- return NULL;
- proxy = g_dbus_proxy_lookup(client->proxy_list, NULL,
- path, interface);
- if (proxy)
- return g_dbus_proxy_ref(proxy);
- proxy = proxy_new(client, path, interface);
- if (proxy == NULL)
- return NULL;
- if (!client->connected) {
- /* Force service to start */
- start_service(proxy);
- return g_dbus_proxy_ref(proxy);
- }
- if (!client->get_objects_call)
- get_all_properties(proxy);
- return g_dbus_proxy_ref(proxy);
- }
- GDBusProxy *g_dbus_proxy_ref(GDBusProxy *proxy)
- {
- if (proxy == NULL)
- return NULL;
- __sync_fetch_and_add(&proxy->ref_count, 1);
- return proxy;
- }
- void g_dbus_proxy_unref(GDBusProxy *proxy)
- {
- if (proxy == NULL)
- return;
- if (__sync_sub_and_fetch(&proxy->ref_count, 1) > 0)
- return;
- if (proxy->get_all_call != NULL) {
- dbus_pending_call_cancel(proxy->get_all_call);
- dbus_pending_call_unref(proxy->get_all_call);
- }
- g_hash_table_destroy(proxy->prop_list);
- g_free(proxy->obj_path);
- g_free(proxy->interface);
- g_free(proxy);
- }
- const char *g_dbus_proxy_get_path(const GDBusProxy *proxy)
- {
- if (proxy == NULL)
- return NULL;
- return proxy->obj_path;
- }
- const char *g_dbus_proxy_get_interface(GDBusProxy *proxy)
- {
- if (proxy == NULL)
- return NULL;
- return proxy->interface;
- }
- gboolean g_dbus_proxy_get_property(GDBusProxy *proxy, const char *name,
- DBusMessageIter *iter)
- {
- struct prop_entry *prop;
- if (proxy == NULL || name == NULL)
- return FALSE;
- prop = g_hash_table_lookup(proxy->prop_list, name);
- if (prop == NULL)
- return FALSE;
- if (prop->msg == NULL)
- return FALSE;
- if (dbus_message_iter_init(prop->msg, iter) == FALSE)
- return FALSE;
- return TRUE;
- }
- struct refresh_property_data {
- GDBusProxy *proxy;
- char *name;
- };
- static void refresh_property_free(gpointer user_data)
- {
- struct refresh_property_data *data = user_data;
- g_free(data->name);
- g_free(data);
- }
- static void refresh_property_reply(DBusPendingCall *call, void *user_data)
- {
- struct refresh_property_data *data = user_data;
- DBusMessage *reply = dbus_pending_call_steal_reply(call);
- DBusError error;
- dbus_error_init(&error);
- if (dbus_set_error_from_message(&error, reply) == FALSE) {
- DBusMessageIter iter;
- dbus_message_iter_init(reply, &iter);
- add_property(data->proxy, data->name, &iter, TRUE);
- } else
- dbus_error_free(&error);
- dbus_message_unref(reply);
- }
- gboolean g_dbus_proxy_refresh_property(GDBusProxy *proxy, const char *name)
- {
- struct refresh_property_data *data;
- GDBusClient *client;
- DBusMessage *msg;
- DBusMessageIter iter;
- DBusPendingCall *call;
- if (proxy == NULL || name == NULL)
- return FALSE;
- client = proxy->client;
- if (client == NULL)
- return FALSE;
- data = g_try_new0(struct refresh_property_data, 1);
- if (data == NULL)
- return FALSE;
- data->proxy = proxy;
- data->name = g_strdup(name);
- msg = dbus_message_new_method_call(client->service_name,
- proxy->obj_path, DBUS_INTERFACE_PROPERTIES, "Get");
- if (msg == NULL) {
- refresh_property_free(data);
- return FALSE;
- }
- dbus_message_iter_init_append(msg, &iter);
- dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
- &proxy->interface);
- dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
- if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
- &call, -1) == FALSE) {
- dbus_message_unref(msg);
- refresh_property_free(data);
- return FALSE;
- }
- dbus_pending_call_set_notify(call, refresh_property_reply,
- data, refresh_property_free);
- dbus_pending_call_unref(call);
- dbus_message_unref(msg);
- return TRUE;
- }
- struct set_property_data {
- GDBusResultFunction function;
- void *user_data;
- GDBusDestroyFunction destroy;
- };
- static void set_property_reply(DBusPendingCall *call, void *user_data)
- {
- struct set_property_data *data = user_data;
- DBusMessage *reply = dbus_pending_call_steal_reply(call);
- DBusError error;
- dbus_error_init(&error);
- dbus_set_error_from_message(&error, reply);
- if (data->function)
- data->function(&error, data->user_data);
- if (data->destroy)
- data->destroy(data->user_data);
- dbus_error_free(&error);
- dbus_message_unref(reply);
- }
- gboolean g_dbus_proxy_set_property_basic(GDBusProxy *proxy,
- const char *name, int type, const void *value,
- GDBusResultFunction function, void *user_data,
- GDBusDestroyFunction destroy)
- {
- struct set_property_data *data;
- GDBusClient *client;
- DBusMessage *msg;
- DBusMessageIter iter;
- DBusPendingCall *call;
- if (proxy == NULL || name == NULL || value == NULL)
- return FALSE;
- if (dbus_type_is_basic(type) == FALSE)
- return FALSE;
- client = proxy->client;
- if (client == NULL)
- return FALSE;
- data = g_try_new0(struct set_property_data, 1);
- if (data == NULL)
- return FALSE;
- data->function = function;
- data->user_data = user_data;
- data->destroy = destroy;
- msg = dbus_message_new_method_call(client->service_name,
- proxy->obj_path, DBUS_INTERFACE_PROPERTIES, "Set");
- if (msg == NULL) {
- g_free(data);
- return FALSE;
- }
- dbus_message_iter_init_append(msg, &iter);
- dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
- &proxy->interface);
- dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
- append_variant(&iter, type, value);
- if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
- &call, -1) == FALSE) {
- dbus_message_unref(msg);
- g_free(data);
- return FALSE;
- }
- dbus_pending_call_set_notify(call, set_property_reply, data, g_free);
- dbus_pending_call_unref(call);
- dbus_message_unref(msg);
- return TRUE;
- }
- gboolean g_dbus_proxy_set_property_array(GDBusProxy *proxy,
- const char *name, int type, const void *value,
- size_t size, GDBusResultFunction function,
- void *user_data, GDBusDestroyFunction destroy)
- {
- struct set_property_data *data;
- GDBusClient *client;
- DBusMessage *msg;
- DBusMessageIter iter;
- DBusPendingCall *call;
- if (!proxy || !name || !value)
- return FALSE;
- if (!dbus_type_is_basic(type))
- return FALSE;
- client = proxy->client;
- if (!client)
- return FALSE;
- data = g_try_new0(struct set_property_data, 1);
- if (!data)
- return FALSE;
- data->function = function;
- data->user_data = user_data;
- data->destroy = destroy;
- msg = dbus_message_new_method_call(client->service_name,
- proxy->obj_path,
- DBUS_INTERFACE_PROPERTIES,
- "Set");
- if (!msg) {
- g_free(data);
- return FALSE;
- }
- dbus_message_iter_init_append(msg, &iter);
- dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
- &proxy->interface);
- dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
- append_array_variant(&iter, type, &value, size);
- if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
- &call, -1) == FALSE) {
- dbus_message_unref(msg);
- g_free(data);
- return FALSE;
- }
- dbus_pending_call_set_notify(call, set_property_reply, data, g_free);
- dbus_pending_call_unref(call);
- dbus_message_unref(msg);
- return TRUE;
- }
- struct method_call_data {
- GDBusReturnFunction function;
- void *user_data;
- GDBusDestroyFunction destroy;
- };
- static void method_call_reply(DBusPendingCall *call, void *user_data)
- {
- struct method_call_data *data = user_data;
- DBusMessage *reply = dbus_pending_call_steal_reply(call);
- if (data->function)
- data->function(reply, data->user_data);
- if (data->destroy)
- data->destroy(data->user_data);
- dbus_message_unref(reply);
- }
- gboolean g_dbus_proxy_method_call(GDBusProxy *proxy, const char *method,
- GDBusSetupFunction setup,
- GDBusReturnFunction function, void *user_data,
- GDBusDestroyFunction destroy)
- {
- struct method_call_data *data;
- GDBusClient *client;
- DBusMessage *msg;
- DBusPendingCall *call;
- if (proxy == NULL || method == NULL)
- return FALSE;
- client = proxy->client;
- if (client == NULL)
- return FALSE;
- msg = dbus_message_new_method_call(client->service_name,
- proxy->obj_path, proxy->interface, method);
- if (msg == NULL)
- return FALSE;
- if (setup) {
- DBusMessageIter iter;
- dbus_message_iter_init_append(msg, &iter);
- setup(&iter, user_data);
- }
- if (!function)
- return g_dbus_send_message(client->dbus_conn, msg);
- data = g_try_new0(struct method_call_data, 1);
- if (data == NULL)
- return FALSE;
- data->function = function;
- data->user_data = user_data;
- data->destroy = destroy;
- if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
- &call, METHOD_CALL_TIMEOUT) == FALSE) {
- dbus_message_unref(msg);
- g_free(data);
- return FALSE;
- }
- dbus_pending_call_set_notify(call, method_call_reply, data, g_free);
- dbus_pending_call_unref(call);
- dbus_message_unref(msg);
- return TRUE;
- }
- gboolean g_dbus_proxy_set_property_watch(GDBusProxy *proxy,
- GDBusPropertyFunction function, void *user_data)
- {
- if (proxy == NULL)
- return FALSE;
- proxy->prop_func = function;
- proxy->prop_data = user_data;
- return TRUE;
- }
- gboolean g_dbus_proxy_set_removed_watch(GDBusProxy *proxy,
- GDBusProxyFunction function, void *user_data)
- {
- if (proxy == NULL)
- return FALSE;
- proxy->removed_func = function;
- proxy->removed_data = user_data;
- return TRUE;
- }
- static void refresh_properties(GList *list)
- {
- GList *l;
- for (l = g_list_first(list); l; l = g_list_next(l)) {
- GDBusProxy *proxy = list->data;
- if (proxy->pending)
- get_all_properties(proxy);
- }
- }
- static void parse_properties(GDBusClient *client, const char *path,
- const char *interface, DBusMessageIter *iter)
- {
- GDBusProxy *proxy;
- if (g_str_equal(interface, DBUS_INTERFACE_INTROSPECTABLE) == TRUE)
- return;
- if (g_str_equal(interface, DBUS_INTERFACE_PROPERTIES) == TRUE)
- return;
- proxy = g_dbus_proxy_lookup(client->proxy_list, NULL,
- path, interface);
- if (proxy && !proxy->pending) {
- update_properties(proxy, iter, FALSE);
- return;
- }
- if (!proxy) {
- proxy = proxy_new(client, path, interface);
- if (proxy == NULL)
- return;
- }
- update_properties(proxy, iter, FALSE);
- proxy_added(client, proxy);
- }
- static void parse_interfaces(GDBusClient *client, const char *path,
- DBusMessageIter *iter)
- {
- DBusMessageIter dict;
- if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
- return;
- dbus_message_iter_recurse(iter, &dict);
- while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
- DBusMessageIter entry;
- const char *interface;
- dbus_message_iter_recurse(&dict, &entry);
- if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
- break;
- dbus_message_iter_get_basic(&entry, &interface);
- dbus_message_iter_next(&entry);
- parse_properties(client, path, interface, &entry);
- dbus_message_iter_next(&dict);
- }
- }
- static gboolean interfaces_added(DBusConnection *conn, DBusMessage *msg,
- void *user_data)
- {
- GDBusClient *client = user_data;
- DBusMessageIter iter;
- const char *path;
- if (dbus_message_iter_init(msg, &iter) == FALSE)
- return TRUE;
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH)
- return TRUE;
- dbus_message_iter_get_basic(&iter, &path);
- dbus_message_iter_next(&iter);
- g_dbus_client_ref(client);
- parse_interfaces(client, path, &iter);
- g_dbus_client_unref(client);
- return TRUE;
- }
- static gboolean interfaces_removed(DBusConnection *conn, DBusMessage *msg,
- void *user_data)
- {
- GDBusClient *client = user_data;
- DBusMessageIter iter, entry;
- const char *path;
- if (dbus_message_iter_init(msg, &iter) == FALSE)
- return TRUE;
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH)
- return TRUE;
- dbus_message_iter_get_basic(&iter, &path);
- dbus_message_iter_next(&iter);
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
- return TRUE;
- dbus_message_iter_recurse(&iter, &entry);
- g_dbus_client_ref(client);
- while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
- const char *interface;
- dbus_message_iter_get_basic(&entry, &interface);
- proxy_remove(client, path, interface);
- dbus_message_iter_next(&entry);
- }
- g_dbus_client_unref(client);
- return TRUE;
- }
- static void parse_managed_objects(GDBusClient *client, DBusMessage *msg)
- {
- DBusMessageIter iter, dict;
- if (dbus_message_iter_init(msg, &iter) == FALSE)
- return;
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
- return;
- dbus_message_iter_recurse(&iter, &dict);
- while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
- DBusMessageIter entry;
- const char *path;
- dbus_message_iter_recurse(&dict, &entry);
- if (dbus_message_iter_get_arg_type(&entry) !=
- DBUS_TYPE_OBJECT_PATH)
- break;
- dbus_message_iter_get_basic(&entry, &path);
- dbus_message_iter_next(&entry);
- parse_interfaces(client, path, &entry);
- dbus_message_iter_next(&dict);
- }
- }
- static void get_managed_objects_reply(DBusPendingCall *call, void *user_data)
- {
- GDBusClient *client = user_data;
- DBusMessage *reply = dbus_pending_call_steal_reply(call);
- DBusError error;
- g_dbus_client_ref(client);
- dbus_error_init(&error);
- if (dbus_set_error_from_message(&error, reply) == TRUE) {
- dbus_error_free(&error);
- goto done;
- }
- parse_managed_objects(client, reply);
- done:
- if (client->ready)
- client->ready(client, client->ready_data);
- dbus_message_unref(reply);
- dbus_pending_call_unref(client->get_objects_call);
- client->get_objects_call = NULL;
- refresh_properties(client->proxy_list);
- g_dbus_client_unref(client);
- }
- static void get_managed_objects(GDBusClient *client)
- {
- DBusMessage *msg;
- if (!client->connected)
- return;
- if ((!client->proxy_added && !client->proxy_removed) ||
- !client->root_path) {
- refresh_properties(client->proxy_list);
- return;
- }
- if (client->get_objects_call != NULL)
- return;
- msg = dbus_message_new_method_call(client->service_name,
- client->root_path,
- DBUS_INTERFACE_OBJECT_MANAGER,
- "GetManagedObjects");
- if (msg == NULL)
- return;
- dbus_message_append_args(msg, DBUS_TYPE_INVALID);
- if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
- &client->get_objects_call, -1) == FALSE) {
- dbus_message_unref(msg);
- return;
- }
- dbus_pending_call_set_notify(client->get_objects_call,
- get_managed_objects_reply,
- client, NULL);
- dbus_message_unref(msg);
- }
- static void service_connect(DBusConnection *conn, void *user_data)
- {
- GDBusClient *client = user_data;
- g_dbus_client_ref(client);
- client->connected = TRUE;
- get_managed_objects(client);
- if (client->connect_func)
- client->connect_func(conn, client->connect_data);
- g_dbus_client_unref(client);
- }
- static void service_disconnect(DBusConnection *conn, void *user_data)
- {
- GDBusClient *client = user_data;
- client->connected = FALSE;
- g_list_free_full(client->proxy_list, proxy_free);
- client->proxy_list = NULL;
- if (client->disconn_func)
- client->disconn_func(conn, client->disconn_data);
- }
- static DBusHandlerResult message_filter(DBusConnection *connection,
- DBusMessage *message, void *user_data)
- {
- GDBusClient *client = user_data;
- const char *sender, *path, *interface;
- if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL)
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- sender = dbus_message_get_sender(message);
- if (sender == NULL)
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- path = dbus_message_get_path(message);
- interface = dbus_message_get_interface(message);
- if (g_str_has_prefix(path, client->base_path) == FALSE)
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- if (g_str_equal(interface, DBUS_INTERFACE_PROPERTIES) == TRUE)
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- if (client->signal_func)
- client->signal_func(connection, message, client->signal_data);
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- }
- GDBusClient *g_dbus_client_new(DBusConnection *connection,
- const char *service, const char *path)
- {
- return g_dbus_client_new_full(connection, service, path, "/");
- }
- GDBusClient *g_dbus_client_new_full(DBusConnection *connection,
- const char *service,
- const char *path,
- const char *root_path)
- {
- GDBusClient *client;
- unsigned int i;
- if (!connection || !service)
- return NULL;
- client = g_try_new0(GDBusClient, 1);
- if (client == NULL)
- return NULL;
- if (dbus_connection_add_filter(connection, message_filter,
- client, NULL) == FALSE) {
- g_free(client);
- return NULL;
- }
- client->dbus_conn = dbus_connection_ref(connection);
- client->service_name = g_strdup(service);
- client->base_path = g_strdup(path);
- client->root_path = g_strdup(root_path);
- client->connected = FALSE;
- client->match_rules = g_ptr_array_sized_new(1);
- g_ptr_array_set_free_func(client->match_rules, g_free);
- client->watch = g_dbus_add_service_watch(connection, service,
- service_connect,
- service_disconnect,
- client, NULL);
- if (!root_path)
- return g_dbus_client_ref(client);
- client->added_watch = g_dbus_add_signal_watch(connection, service,
- client->root_path,
- DBUS_INTERFACE_OBJECT_MANAGER,
- "InterfacesAdded",
- interfaces_added,
- client, NULL);
- client->removed_watch = g_dbus_add_signal_watch(connection, service,
- client->root_path,
- DBUS_INTERFACE_OBJECT_MANAGER,
- "InterfacesRemoved",
- interfaces_removed,
- client, NULL);
- g_ptr_array_add(client->match_rules, g_strdup_printf("type='signal',"
- "sender='%s',path_namespace='%s'",
- client->service_name, client->base_path));
- for (i = 0; i < client->match_rules->len; i++) {
- modify_match(client->dbus_conn, "AddMatch",
- g_ptr_array_index(client->match_rules, i));
- }
- return g_dbus_client_ref(client);
- }
- GDBusClient *g_dbus_client_ref(GDBusClient *client)
- {
- if (client == NULL)
- return NULL;
- __sync_fetch_and_add(&client->ref_count, 1);
- return client;
- }
- void g_dbus_client_unref(GDBusClient *client)
- {
- unsigned int i;
- if (client == NULL)
- return;
- if (__sync_sub_and_fetch(&client->ref_count, 1) > 0)
- return;
- if (client->pending_call != NULL) {
- dbus_pending_call_cancel(client->pending_call);
- dbus_pending_call_unref(client->pending_call);
- }
- if (client->get_objects_call != NULL) {
- dbus_pending_call_cancel(client->get_objects_call);
- dbus_pending_call_unref(client->get_objects_call);
- }
- for (i = 0; i < client->match_rules->len; i++) {
- modify_match(client->dbus_conn, "RemoveMatch",
- g_ptr_array_index(client->match_rules, i));
- }
- g_ptr_array_free(client->match_rules, TRUE);
- dbus_connection_remove_filter(client->dbus_conn,
- message_filter, client);
- g_list_free_full(client->proxy_list, proxy_free);
- /*
- * Don't call disconn_func twice if disconnection
- * was previously reported.
- */
- if (client->disconn_func && client->connected)
- client->disconn_func(client->dbus_conn, client->disconn_data);
- g_dbus_remove_watch(client->dbus_conn, client->watch);
- g_dbus_remove_watch(client->dbus_conn, client->added_watch);
- g_dbus_remove_watch(client->dbus_conn, client->removed_watch);
- dbus_connection_unref(client->dbus_conn);
- g_free(client->service_name);
- g_free(client->base_path);
- g_free(client->root_path);
- g_free(client);
- }
- gboolean g_dbus_client_set_connect_watch(GDBusClient *client,
- GDBusWatchFunction function, void *user_data)
- {
- if (client == NULL)
- return FALSE;
- client->connect_func = function;
- client->connect_data = user_data;
- return TRUE;
- }
- gboolean g_dbus_client_set_disconnect_watch(GDBusClient *client,
- GDBusWatchFunction function, void *user_data)
- {
- if (client == NULL)
- return FALSE;
- client->disconn_func = function;
- client->disconn_data = user_data;
- return TRUE;
- }
- gboolean g_dbus_client_set_signal_watch(GDBusClient *client,
- GDBusMessageFunction function, void *user_data)
- {
- if (client == NULL)
- return FALSE;
- client->signal_func = function;
- client->signal_data = user_data;
- return TRUE;
- }
- gboolean g_dbus_client_set_ready_watch(GDBusClient *client,
- GDBusClientFunction ready, void *user_data)
- {
- if (client == NULL)
- return FALSE;
- client->ready = ready;
- client->ready_data = user_data;
- return TRUE;
- }
- gboolean g_dbus_client_set_proxy_handlers(GDBusClient *client,
- GDBusProxyFunction proxy_added,
- GDBusProxyFunction proxy_removed,
- GDBusPropertyFunction property_changed,
- void *user_data)
- {
- if (client == NULL)
- return FALSE;
- client->proxy_added = proxy_added;
- client->proxy_removed = proxy_removed;
- client->property_changed = property_changed;
- client->user_data = user_data;
- if (proxy_added || proxy_removed || property_changed)
- get_managed_objects(client);
- return TRUE;
- }
|