| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149 |
- /*
- *
- * Embedded Linux library
- *
- * Copyright (C) 2011-2014 Intel Corporation. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
- #ifdef HAVE_CONFIG_H
- #include <config.h>
- #endif
- #define _GNU_SOURCE
- #include <string.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include "useful.h"
- #include "queue.h"
- #include "string.h"
- #include "hashmap.h"
- #include "dbus.h"
- #include "dbus-service.h"
- #include "dbus-private.h"
- #include "private.h"
- #include "idle.h"
- #define XML_ID "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
- #define XML_DTD "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"
- #define XML_HEAD "<!DOCTYPE node PUBLIC \""XML_ID"\"\n\""XML_DTD"\">\n"
- static const char *static_introspectable =
- "\t<interface name=\"org.freedesktop.DBus.Introspectable\">\n"
- "\t\t<method name=\"Introspect\">\n"
- "\t\t\t<arg name=\"xml\" type=\"s\" direction=\"out\"/>\n"
- "\t\t</method>\n\t</interface>\n";
- struct _dbus_method {
- l_dbus_interface_method_cb_t cb;
- uint32_t flags;
- unsigned char name_len;
- char metainfo[];
- };
- struct _dbus_signal {
- uint32_t flags;
- unsigned char name_len;
- char metainfo[];
- };
- struct _dbus_property {
- l_dbus_property_get_cb_t getter;
- l_dbus_property_set_cb_t setter;
- uint32_t flags;
- unsigned char name_len;
- char metainfo[];
- };
- struct l_dbus_interface {
- struct l_queue *methods;
- struct l_queue *signals;
- struct l_queue *properties;
- bool handle_old_style_properties;
- void (*instance_destroy)(void *);
- char name[];
- };
- struct child_node {
- struct object_node *node;
- struct child_node *next;
- char subpath[];
- };
- struct interface_instance {
- struct l_dbus_interface *interface;
- void *user_data;
- };
- struct object_node {
- struct object_node *parent;
- struct l_queue *instances;
- struct child_node *children;
- void *user_data;
- void (*destroy) (void *);
- };
- struct object_manager {
- char *path;
- struct l_dbus *dbus;
- struct l_queue *announce_added;
- struct l_queue *announce_removed;
- };
- struct interface_add_record {
- char *path;
- struct object_node *object;
- struct l_queue *instances;
- };
- struct interface_remove_record {
- char *path;
- struct object_node *object;
- struct l_queue *interface_names;
- };
- struct property_change_record {
- char *path;
- struct object_node *object;
- struct interface_instance *instance;
- struct l_queue *properties;
- };
- struct _dbus_object_tree {
- struct l_hashmap *interfaces;
- struct l_hashmap *objects;
- struct object_node *root;
- struct l_queue *object_managers;
- struct l_queue *property_changes;
- struct l_idle *emit_signals_work;
- bool flushing;
- };
- void _dbus_method_introspection(struct _dbus_method *info,
- struct l_string *buf)
- {
- const char *sig;
- const char *end;
- const char *pname;
- unsigned int offset = info->name_len + 1;
- l_string_append_printf(buf, "\t\t<method name=\"%s\">\n",
- info->metainfo);
- sig = info->metainfo + offset;
- offset += strlen(sig) + 1;
- for (; *sig; sig++) {
- end = _dbus_signature_end(sig);
- pname = info->metainfo + offset;
- l_string_append_printf(buf, "\t\t\t<arg name=\"%s\" "
- "type=\"%.*s\" direction=\"in\"/>\n",
- pname, (int) (end - sig + 1), sig);
- sig = end;
- offset += strlen(pname) + 1;
- }
- sig = info->metainfo + offset;
- offset += strlen(sig) + 1;
- for (; *sig; sig++) {
- end = _dbus_signature_end(sig);
- pname = info->metainfo + offset;
- l_string_append_printf(buf, "\t\t\t<arg name=\"%s\" "
- "type=\"%.*s\" direction=\"out\"/>\n",
- pname, (int) (end - sig + 1), sig);
- sig = end;
- offset += strlen(pname) + 1;
- }
- if (info->flags & L_DBUS_METHOD_FLAG_DEPRECATED)
- l_string_append(buf, "\t\t\t<annotation name=\""
- "org.freedesktop.DBus.Deprecated\" "
- "value=\"true\"/>\n");
- if (info->flags & L_DBUS_METHOD_FLAG_NOREPLY)
- l_string_append(buf, "\t\t\t<annotation name=\""
- "org.freedesktop.DBus.Method.NoReply\" "
- "value=\"true\"/>\n");
- l_string_append(buf, "\t\t</method>\n");
- }
- void _dbus_signal_introspection(struct _dbus_signal *info,
- struct l_string *buf)
- {
- const char *sig;
- const char *end;
- const char *pname;
- unsigned int offset = info->name_len + 1;
- l_string_append_printf(buf, "\t\t<signal name=\"%s\">\n",
- info->metainfo);
- sig = info->metainfo + offset;
- offset += strlen(sig) + 1;
- for (; *sig; sig++) {
- end = _dbus_signature_end(sig);
- pname = info->metainfo + offset;
- l_string_append_printf(buf, "\t\t\t<arg name=\"%s\" "
- "type=\"%.*s\"/>\n",
- pname, (int) (end - sig + 1), sig);
- sig = end;
- offset += strlen(pname) + 1;
- }
- if (info->flags & L_DBUS_SIGNAL_FLAG_DEPRECATED)
- l_string_append(buf, "\t\t\t<annotation name=\""
- "org.freedesktop.DBus.Deprecated\" "
- "value=\"true\"/>\n");
- l_string_append(buf, "\t\t</signal>\n");
- }
- void _dbus_property_introspection(struct _dbus_property *info,
- struct l_string *buf)
- {
- unsigned int offset = info->name_len + 1;
- const char *signature = info->metainfo + offset;
- l_string_append_printf(buf, "\t\t<property name=\"%s\" type=\"%s\" ",
- info->metainfo, signature);
- if (info->setter)
- l_string_append(buf, "access=\"readwrite\"");
- else
- l_string_append(buf, "access=\"read\"");
- if (info->flags & L_DBUS_METHOD_FLAG_DEPRECATED) {
- l_string_append(buf, ">\n");
- l_string_append(buf, "\t\t\t<annotation name=\""
- "org.freedesktop.DBus.Deprecated\" "
- "value=\"true\"/>\n");
- l_string_append(buf, "\t\t</property>\n");
- } else
- l_string_append(buf, "/>\n");
- }
- void _dbus_interface_introspection(struct l_dbus_interface *interface,
- struct l_string *buf)
- {
- l_string_append_printf(buf, "\t<interface name=\"%s\">\n",
- interface->name);
- l_queue_foreach(interface->methods,
- (l_queue_foreach_func_t) _dbus_method_introspection, buf);
- l_queue_foreach(interface->signals,
- (l_queue_foreach_func_t) _dbus_signal_introspection, buf);
- l_queue_foreach(interface->properties,
- (l_queue_foreach_func_t) _dbus_property_introspection, buf);
- l_string_append(buf, "\t</interface>\n");
- }
- #define COPY_PARAMS(dest, signature, args) \
- do { \
- const char *pname; \
- const char *sig; \
- dest = stpcpy(dest, signature) + 1; \
- for (sig = signature; *sig; sig++) { \
- sig = _dbus_signature_end(sig); \
- pname = va_arg(args, const char *); \
- dest = stpcpy(dest, pname) + 1; \
- } \
- } while(0)
- #define SIZE_PARAMS(signature, args) \
- ({ \
- unsigned int len = strlen(signature) + 1; \
- const char *pname; \
- const char *sig; \
- for (sig = signature; *sig; sig++) { \
- sig = _dbus_signature_end(sig); \
- if (!sig) { \
- len = 0; \
- break; \
- } \
- pname = va_arg(args, const char *); \
- len += strlen(pname) + 1; \
- } \
- len; \
- })
- LIB_EXPORT bool l_dbus_interface_method(struct l_dbus_interface *interface,
- const char *name, uint32_t flags,
- l_dbus_interface_method_cb_t cb,
- const char *return_sig,
- const char *param_sig, ...)
- {
- va_list args;
- unsigned int return_info_len;
- unsigned int param_info_len;
- struct _dbus_method *info;
- char *p;
- if (!_dbus_valid_method(name))
- return false;
- if (unlikely(!return_sig || !param_sig))
- return false;
- if (return_sig[0] && !_dbus_valid_signature(return_sig))
- return false;
- if (param_sig[0] && !_dbus_valid_signature(param_sig))
- return false;
- /* Pre-calculate the needed meta-info length */
- va_start(args, param_sig);
- return_info_len = SIZE_PARAMS(return_sig, args);
- param_info_len = SIZE_PARAMS(param_sig, args);
- va_end(args);
- if (!return_info_len || !param_info_len)
- return false;
- info = l_malloc(sizeof(*info) + return_info_len +
- param_info_len + strlen(name) + 1);
- info->cb = cb;
- info->flags = flags;
- info->name_len = strlen(name);
- strcpy(info->metainfo, name);
- va_start(args, param_sig);
- /*
- * We store param signature + parameter names first, to speed up
- * lookups during the message dispatch procedures.
- */
- p = info->metainfo + info->name_len + param_info_len + 1;
- COPY_PARAMS(p, return_sig, args);
- p = info->metainfo + info->name_len + 1;
- COPY_PARAMS(p, param_sig, args);
- va_end(args);
- l_queue_push_tail(interface->methods, info);
- return true;
- }
- LIB_EXPORT bool l_dbus_interface_signal(struct l_dbus_interface *interface,
- const char *name, uint32_t flags,
- const char *signature, ...)
- {
- va_list args;
- unsigned int metainfo_len;
- struct _dbus_signal *info;
- char *p;
- if (!_dbus_valid_method(name))
- return false;
- if (unlikely(!signature))
- return false;
- if (signature[0] && !_dbus_valid_signature(signature))
- return false;
- /* Pre-calculate the needed meta-info length */
- va_start(args, signature);
- metainfo_len = SIZE_PARAMS(signature, args);
- va_end(args);
- if (!metainfo_len)
- return false;
- metainfo_len += strlen(name) + 1;
- info = l_malloc(sizeof(*info) + metainfo_len);
- info->flags = flags;
- info->name_len = strlen(name);
- p = stpcpy(info->metainfo, name) + 1;
- va_start(args, signature);
- COPY_PARAMS(p, signature, args);
- va_end(args);
- l_queue_push_tail(interface->signals, info);
- return true;
- }
- LIB_EXPORT bool l_dbus_interface_property(struct l_dbus_interface *interface,
- const char *name, uint32_t flags,
- const char *signature,
- l_dbus_property_get_cb_t getter,
- l_dbus_property_set_cb_t setter)
- {
- unsigned int metainfo_len;
- struct _dbus_property *info;
- char *p;
- if (!_dbus_valid_method(name))
- return false;
- if (unlikely(!signature || !getter))
- return false;
- if (_dbus_num_children(signature) != 1)
- return false;
- /* Pre-calculate the needed meta-info length */
- metainfo_len = strlen(name) + 1;
- metainfo_len += strlen(signature) + 1;
- info = l_malloc(sizeof(*info) + metainfo_len);
- info->flags = flags;
- info->name_len = strlen(name);
- info->getter = getter;
- info->setter = setter;
- p = stpcpy(info->metainfo, name) + 1;
- strcpy(p, signature);
- l_queue_push_tail(interface->properties, info);
- return true;
- }
- struct l_dbus_interface *_dbus_interface_new(const char *name)
- {
- struct l_dbus_interface *interface;
- interface = l_malloc(sizeof(*interface) + strlen(name) + 1);
- interface->methods = l_queue_new();
- interface->signals = l_queue_new();
- interface->properties = l_queue_new();
- strcpy(interface->name, name);
- return interface;
- }
- void _dbus_interface_free(struct l_dbus_interface *interface)
- {
- l_queue_destroy(interface->methods, l_free);
- l_queue_destroy(interface->signals, l_free);
- l_queue_destroy(interface->properties, l_free);
- l_free(interface);
- }
- static bool match_method(const void *a, const void *b)
- {
- const struct _dbus_method *method = a;
- const char *name = b;
- if (!strcmp(method->metainfo, name))
- return true;
- return false;
- }
- struct _dbus_method *_dbus_interface_find_method(struct l_dbus_interface *i,
- const char *method)
- {
- return l_queue_find(i->methods, match_method, (char *) method);
- }
- static bool match_signal(const void *a, const void *b)
- {
- const struct _dbus_signal *signal = a;
- const char *name = b;
- if (!strcmp(signal->metainfo, name))
- return true;
- return false;
- }
- struct _dbus_signal *_dbus_interface_find_signal(struct l_dbus_interface *i,
- const char *signal)
- {
- return l_queue_find(i->signals, match_signal, (char *) signal);
- }
- static bool match_property(const void *a, const void *b)
- {
- const struct _dbus_property *property = a;
- const char *name = b;
- if (!strcmp(property->metainfo, name))
- return true;
- return false;
- }
- struct _dbus_property *_dbus_interface_find_property(struct l_dbus_interface *i,
- const char *property)
- {
- return l_queue_find(i->properties, match_property, (char *) property);
- }
- static void interface_instance_free(struct interface_instance *instance)
- {
- if (instance->interface->instance_destroy)
- instance->interface->instance_destroy(instance->user_data);
- l_free(instance);
- }
- static bool match_interface_instance(const void *a, const void *b)
- {
- const struct interface_instance *instance = a;
- const char *name = b;
- if (!strcmp(instance->interface->name, name))
- return true;
- return false;
- }
- static bool match_interface_instance_ptr(const void *a, const void *b)
- {
- const struct interface_instance *instance = a;
- return instance->interface == b;
- }
- static void interface_add_record_free(void *data)
- {
- struct interface_add_record *rec = data;
- l_free(rec->path);
- l_queue_destroy(rec->instances, NULL);
- l_free(rec);
- }
- static void interface_removed_record_free(void *data)
- {
- struct interface_remove_record *rec = data;
- l_free(rec->path);
- l_queue_destroy(rec->interface_names, l_free);
- l_free(rec);
- }
- static void property_change_record_free(void *data)
- {
- struct property_change_record *rec = data;
- l_free(rec->path);
- l_queue_destroy(rec->properties, NULL);
- l_free(rec);
- }
- static void properties_setup_func(struct l_dbus_interface *);
- static void object_manager_setup_func(struct l_dbus_interface *);
- struct _dbus_object_tree *_dbus_object_tree_new()
- {
- struct _dbus_object_tree *tree;
- tree = l_new(struct _dbus_object_tree, 1);
- tree->interfaces = l_hashmap_new();
- l_hashmap_set_hash_function(tree->interfaces, l_str_hash);
- l_hashmap_set_compare_function(tree->interfaces,
- (l_hashmap_compare_func_t)strcmp);
- tree->objects = l_hashmap_string_new();
- tree->root = l_new(struct object_node, 1);
- tree->property_changes = l_queue_new();
- _dbus_object_tree_register_interface(tree, L_DBUS_INTERFACE_PROPERTIES,
- properties_setup_func, NULL,
- false);
- tree->object_managers = l_queue_new();
- _dbus_object_tree_register_interface(tree,
- L_DBUS_INTERFACE_OBJECT_MANAGER,
- object_manager_setup_func, NULL,
- false);
- return tree;
- }
- static void subtree_free(struct object_node *node)
- {
- struct child_node *child;
- while (node->children) {
- child = node->children;
- node->children = child->next;
- subtree_free(child->node);
- l_free(child);
- }
- l_queue_destroy(node->instances,
- (l_queue_destroy_func_t) interface_instance_free);
- if (node->destroy)
- node->destroy(node->user_data);
- l_free(node);
- }
- static void object_manager_free(void *data)
- {
- struct object_manager *manager = data;
- l_free(manager->path);
- l_queue_destroy(manager->announce_added, interface_add_record_free);
- l_queue_destroy(manager->announce_removed,
- interface_removed_record_free);
- l_free(manager);
- }
- void _dbus_object_tree_free(struct _dbus_object_tree *tree)
- {
- subtree_free(tree->root);
- l_hashmap_destroy(tree->interfaces,
- (l_hashmap_destroy_func_t) _dbus_interface_free);
- l_hashmap_destroy(tree->objects, NULL);
- l_queue_destroy(tree->object_managers, object_manager_free);
- l_queue_destroy(tree->property_changes, property_change_record_free);
- if (tree->emit_signals_work)
- l_idle_remove(tree->emit_signals_work);
- l_free(tree);
- }
- static struct object_node *makepath_recurse(struct object_node *node,
- const char *path)
- {
- const char *end;
- struct child_node *child;
- if (*path == '\0')
- return node;
- path += 1;
- end = strchrnul(path, '/');
- child = node->children;
- while (child) {
- if (!strncmp(child->subpath, path, end - path) &&
- child->subpath[end - path] == '\0')
- goto done;
- child = child->next;
- }
- child = l_malloc(sizeof(*child) + end - path + 1);
- child->node = l_new(struct object_node, 1);
- child->node->parent = node;
- memcpy(child->subpath, path, end - path);
- child->subpath[end-path] = '\0';
- child->next = node->children;
- node->children = child;
- done:
- return makepath_recurse(child->node, end);
- }
- struct object_node *_dbus_object_tree_makepath(struct _dbus_object_tree *tree,
- const char *path)
- {
- if (path[0] == '/' && path[1] == '\0')
- return tree->root;
- return makepath_recurse(tree->root, path);
- }
- static struct object_node *lookup_recurse(struct object_node *node,
- const char *path)
- {
- const char *end;
- struct child_node *child;
- if (*path == '\0')
- return node;
- path += 1;
- end = strchrnul(path, '/');
- child = node->children;
- while (child) {
- if (!strncmp(child->subpath, path, end - path) &&
- child->subpath[end - path] == '\0')
- return lookup_recurse(child->node, end);
- child = child->next;
- }
- return NULL;
- }
- struct object_node *_dbus_object_tree_lookup(struct _dbus_object_tree *tree,
- const char *path)
- {
- if (path[0] == '/' && path[1] == '\0')
- return tree->root;
- return lookup_recurse(tree->root, path);
- }
- void _dbus_object_tree_prune_node(struct object_node *node)
- {
- struct object_node *parent = node->parent;
- struct child_node *p = NULL, *c;
- while (parent) {
- for (c = parent->children, p = NULL; c; p = c, c = c->next) {
- if (c->node != node)
- continue;
- if (p)
- p->next = c->next;
- else
- parent->children = c->next;
- subtree_free(c->node);
- l_free(c);
- break;
- }
- if (parent->children != NULL)
- return;
- if (parent->instances)
- return;
- node = parent;
- parent = node->parent;
- }
- }
- struct object_node *_dbus_object_tree_new_object(struct _dbus_object_tree *tree,
- const char *path,
- void *user_data,
- void (*destroy) (void *))
- {
- struct object_node *node;
- if (!_dbus_valid_object_path(path))
- return NULL;
- if (l_hashmap_lookup(tree->objects, path))
- return NULL;
- node = _dbus_object_tree_makepath(tree, path);
- node->user_data = user_data;
- node->destroy = destroy;
- /*
- * Registered objects in the tree are marked by being present in the
- * tree->objects hash and having non-null node->instances. Remaining
- * nodes are intermediate path elements added and removed
- * automatically.
- */
- node->instances = l_queue_new();
- l_hashmap_insert(tree->objects, path, node);
- return node;
- }
- bool _dbus_object_tree_object_destroy(struct _dbus_object_tree *tree,
- const char *path)
- {
- struct object_node *node;
- const struct l_queue_entry *entry;
- const struct interface_instance *instance;
- node = l_hashmap_lookup(tree->objects, path);
- if (!node)
- return false;
- while ((entry = l_queue_get_entries(node->instances))) {
- instance = entry->data;
- if (!_dbus_object_tree_remove_interface(tree, path,
- instance->interface->name))
- return false;
- }
- l_hashmap_remove(tree->objects, path);
- l_queue_destroy(node->instances, NULL);
- node->instances = NULL;
- if (node->destroy) {
- node->destroy(node->user_data);
- node->destroy = NULL;
- }
- if (!node->children)
- _dbus_object_tree_prune_node(node);
- return true;
- }
- static bool get_properties_dict(struct l_dbus *dbus,
- struct l_dbus_message *message,
- struct l_dbus_message_builder *builder,
- const struct l_dbus_interface *interface,
- void *user_data)
- {
- const struct l_queue_entry *entry;
- const struct _dbus_property *property;
- const char *signature;
- l_dbus_message_builder_enter_array(builder, "{sv}");
- _dbus_message_builder_mark(builder);
- for (entry = l_queue_get_entries(interface->properties); entry;
- entry = entry->next) {
- property = entry->data;
- signature = property->metainfo + strlen(property->metainfo) + 1;
- l_dbus_message_builder_enter_dict(builder, "sv");
- l_dbus_message_builder_append_basic(builder, 's',
- property->metainfo);
- l_dbus_message_builder_enter_variant(builder, signature);
- if (!property->getter(dbus, message, builder, user_data)) {
- if (!_dbus_message_builder_rewind(builder))
- return false;
- continue;
- }
- l_dbus_message_builder_leave_variant(builder);
- l_dbus_message_builder_leave_dict(builder);
- _dbus_message_builder_mark(builder);
- }
- l_dbus_message_builder_leave_array(builder);
- return true;
- }
- static struct l_dbus_message *build_interfaces_removed_signal(
- const struct object_manager *manager,
- const struct interface_remove_record *rec)
- {
- struct l_dbus_message *signal;
- struct l_dbus_message_builder *builder;
- const struct l_queue_entry *entry;
- signal = l_dbus_message_new_signal(manager->dbus, manager->path,
- L_DBUS_INTERFACE_OBJECT_MANAGER,
- "InterfacesRemoved");
- builder = l_dbus_message_builder_new(signal);
- l_dbus_message_builder_append_basic(builder, 'o', rec->path);
- l_dbus_message_builder_enter_array(builder, "s");
- for (entry = l_queue_get_entries(rec->interface_names); entry;
- entry = entry->next)
- l_dbus_message_builder_append_basic(builder, 's', entry->data);
- l_dbus_message_builder_leave_array(builder);
- l_dbus_message_builder_finalize(builder);
- l_dbus_message_builder_destroy(builder);
- return signal;
- }
- static struct l_dbus_message *build_interfaces_added_signal(
- const struct object_manager *manager,
- const struct interface_add_record *rec)
- {
- struct l_dbus_message *signal;
- struct l_dbus_message_builder *builder;
- const struct l_queue_entry *entry;
- const struct interface_instance *instance;
- signal = l_dbus_message_new_signal(manager->dbus, manager->path,
- L_DBUS_INTERFACE_OBJECT_MANAGER,
- "InterfacesAdded");
- builder = l_dbus_message_builder_new(signal);
- l_dbus_message_builder_append_basic(builder, 'o', rec->path);
- l_dbus_message_builder_enter_array(builder, "{sa{sv}}");
- for (entry = l_queue_get_entries(rec->instances); entry;
- entry = entry->next) {
- instance = entry->data;
- l_dbus_message_builder_enter_dict(builder, "sa{sv}");
- l_dbus_message_builder_append_basic(builder, 's',
- instance->interface->name);
- if (!get_properties_dict(manager->dbus, signal, builder,
- instance->interface,
- instance->user_data)) {
- l_dbus_message_builder_destroy(builder);
- l_dbus_message_unref(signal);
- return NULL;
- }
- l_dbus_message_builder_leave_dict(builder);
- }
- l_dbus_message_builder_leave_array(builder);
- l_dbus_message_builder_finalize(builder);
- l_dbus_message_builder_destroy(builder);
- return signal;
- }
- static struct l_dbus_message *build_old_property_changed_signal(
- struct l_dbus *dbus,
- const struct property_change_record *rec,
- const struct _dbus_property *property)
- {
- struct l_dbus_message *signal;
- struct l_dbus_message_builder *builder;
- const char *signature;
- signature = property->metainfo + strlen(property->metainfo) + 1;
- signal = l_dbus_message_new_signal(dbus, rec->path,
- rec->instance->interface->name,
- "PropertyChanged");
- builder = l_dbus_message_builder_new(signal);
- l_dbus_message_builder_append_basic(builder, 's', property->metainfo);
- l_dbus_message_builder_enter_variant(builder, signature);
- if (!property->getter(dbus, signal, builder,
- rec->instance->user_data)) {
- l_dbus_message_builder_destroy(builder);
- l_dbus_message_unref(signal);
- return NULL;
- }
- l_dbus_message_builder_leave_variant(builder);
- l_dbus_message_builder_finalize(builder);
- l_dbus_message_builder_destroy(builder);
- return signal;
- }
- static struct l_dbus_message *build_properties_changed_signal(
- struct l_dbus *dbus,
- const struct property_change_record *rec)
- {
- struct l_dbus_message *signal;
- struct l_dbus_message_builder *builder;
- const struct l_queue_entry *entry;
- const struct _dbus_property *property;
- const char *signature;
- struct l_queue *invalidated;
- signal = l_dbus_message_new_signal(dbus, rec->path,
- L_DBUS_INTERFACE_PROPERTIES,
- "PropertiesChanged");
- builder = l_dbus_message_builder_new(signal);
- invalidated = l_queue_new();
- l_dbus_message_builder_append_basic(builder, 's',
- rec->instance->interface->name);
- l_dbus_message_builder_enter_array(builder, "{sv}");
- for (entry = l_queue_get_entries(rec->properties); entry;
- entry = entry->next) {
- property = entry->data;
- signature = property->metainfo + strlen(property->metainfo) + 1;
- _dbus_message_builder_mark(builder);
- l_dbus_message_builder_enter_dict(builder, "sv");
- l_dbus_message_builder_append_basic(builder, 's',
- property->metainfo);
- l_dbus_message_builder_enter_variant(builder, signature);
- if (!property->getter(dbus, signal, builder,
- rec->instance->user_data)) {
- if (!_dbus_message_builder_rewind(builder)) {
- l_dbus_message_unref(signal);
- signal = NULL;
- goto done;
- }
- l_queue_push_tail(invalidated, (void *) property);
- continue;
- }
- l_dbus_message_builder_leave_variant(builder);
- l_dbus_message_builder_leave_dict(builder);
- }
- l_dbus_message_builder_leave_array(builder);
- l_dbus_message_builder_enter_array(builder, "s");
- while ((property = l_queue_pop_head(invalidated)))
- l_dbus_message_builder_append_basic(builder, 's',
- property->metainfo);
- l_dbus_message_builder_leave_array(builder);
- l_dbus_message_builder_finalize(builder);
- done:
- l_dbus_message_builder_destroy(builder);
- l_queue_destroy(invalidated, NULL);
- return signal;
- }
- struct emit_signals_data {
- struct l_dbus *dbus;
- struct object_manager *manager;
- struct object_node *node;
- };
- static bool emit_interfaces_removed(void *data, void *user_data)
- {
- struct interface_remove_record *rec = data;
- struct emit_signals_data *es = user_data;
- struct l_dbus_message *signal;
- if (es->node && rec->object != es->node)
- return false;
- signal = build_interfaces_removed_signal(es->manager, rec);
- interface_removed_record_free(rec);
- if (signal)
- l_dbus_send(es->manager->dbus, signal);
- return true;
- }
- static bool emit_interfaces_added(void *data, void *user_data)
- {
- struct interface_add_record *rec = data;
- struct emit_signals_data *es = user_data;
- struct l_dbus_message *signal;
- if (es->node && rec->object != es->node)
- return false;
- signal = build_interfaces_added_signal(es->manager, rec);
- interface_add_record_free(rec);
- if (signal)
- l_dbus_send(es->manager->dbus, signal);
- return true;
- }
- static bool emit_properties_changed(void *data, void *user_data)
- {
- struct property_change_record *rec = data;
- struct emit_signals_data *es = user_data;
- struct l_dbus_message *signal;
- const struct l_queue_entry *entry;
- if (es->node && rec->object != es->node)
- return false;
- if (rec->instance->interface->handle_old_style_properties)
- for (entry = l_queue_get_entries(rec->properties);
- entry; entry = entry->next) {
- signal = build_old_property_changed_signal(es->dbus,
- rec, entry->data);
- if (signal)
- l_dbus_send(es->dbus, signal);
- }
- if (l_queue_find(rec->object->instances, match_interface_instance,
- L_DBUS_INTERFACE_PROPERTIES)) {
- signal = build_properties_changed_signal(es->dbus, rec);
- if (signal)
- l_dbus_send(es->dbus, signal);
- }
- property_change_record_free(rec);
- return true;
- }
- void _dbus_object_tree_signals_flush(struct l_dbus *dbus, const char *path)
- {
- struct _dbus_object_tree *tree = _dbus_get_tree(dbus);
- const struct l_queue_entry *entry;
- struct emit_signals_data data;
- bool all_done = true;
- if (!tree->emit_signals_work || tree->flushing)
- return;
- tree->flushing = true;
- data.dbus = dbus;
- data.node = path ? _dbus_object_tree_lookup(tree, path) : NULL;
- for (entry = l_queue_get_entries(tree->object_managers); entry;
- entry = entry->next) {
- data.manager = entry->data;
- l_queue_foreach_remove(data.manager->announce_removed,
- emit_interfaces_removed, &data);
- if (!l_queue_isempty(data.manager->announce_removed))
- all_done = false;
- l_queue_foreach_remove(data.manager->announce_added,
- emit_interfaces_added, &data);
- if (!l_queue_isempty(data.manager->announce_added))
- all_done = false;
- }
- l_queue_foreach_remove(tree->property_changes,
- emit_properties_changed, &data);
- if (!l_queue_isempty(tree->property_changes))
- all_done = false;
- if (all_done) {
- l_idle_remove(tree->emit_signals_work);
- tree->emit_signals_work = NULL;
- }
- tree->flushing = false;
- }
- static void emit_signals(struct l_idle *idle, void *user_data)
- {
- struct l_dbus *dbus = user_data;
- _dbus_object_tree_signals_flush(dbus, NULL);
- }
- static void schedule_emit_signals(struct l_dbus *dbus)
- {
- struct _dbus_object_tree *tree = _dbus_get_tree(dbus);
- if (tree->emit_signals_work)
- return;
- tree->emit_signals_work = l_idle_create(emit_signals, dbus, NULL);
- }
- static bool match_property_changes_instance(const void *a, const void *b)
- {
- const struct property_change_record *rec = a;
- return rec->instance == b;
- }
- static bool match_pointer(const void *a, const void *b)
- {
- return a == b;
- }
- bool _dbus_object_tree_property_changed(struct l_dbus *dbus,
- const char *path,
- const char *interface_name,
- const char *property_name)
- {
- struct property_change_record *rec;
- struct object_node *object;
- struct interface_instance *instance;
- struct _dbus_property *property;
- struct _dbus_object_tree *tree = _dbus_get_tree(dbus);
- object = l_hashmap_lookup(tree->objects, path);
- if (!object)
- return false;
- instance = l_queue_find(object->instances, match_interface_instance,
- interface_name);
- if (!instance)
- return false;
- property = _dbus_interface_find_property(instance->interface,
- property_name);
- if (!property)
- return false;
- rec = l_queue_find(tree->property_changes,
- match_property_changes_instance, instance);
- if (rec) {
- if (l_queue_find(rec->properties, match_pointer, property))
- return true;
- } else {
- rec = l_new(struct property_change_record, 1);
- rec->path = l_strdup(path);
- rec->object = object;
- rec->instance = instance;
- rec->properties = l_queue_new();
- l_queue_push_tail(tree->property_changes, rec);
- }
- l_queue_push_tail(rec->properties, property);
- schedule_emit_signals(dbus);
- return true;
- }
- static void pending_property_set_done_common(struct l_dbus *dbus,
- struct l_dbus_message *message,
- struct l_dbus_message *reply,
- bool auto_emit)
- {
- const char *member;
- const char *interface_name;
- const char *property_name;
- struct l_dbus_message_iter variant;
- if (!reply) {
- reply = l_dbus_message_new_method_return(message);
- l_dbus_message_set_arguments(reply, "");
- }
- l_dbus_send(dbus, l_dbus_message_ref(reply));
- member = l_dbus_message_get_member(message);
- if (!strcmp(member, "SetProperty")) {
- if (!l_dbus_message_get_arguments(message, "sv",
- &property_name, &variant))
- goto done;
- interface_name = l_dbus_message_get_interface(message);
- } else if (strcmp(member, "Set") ||
- !l_dbus_message_get_arguments(message, "ssv",
- &interface_name,
- &property_name,
- &variant))
- goto done;
- if (auto_emit)
- _dbus_object_tree_property_changed(dbus,
- l_dbus_message_get_path(message),
- interface_name, property_name);
- done:
- l_dbus_message_unref(message);
- l_dbus_message_unref(reply);
- }
- static void pending_property_set_done_emit(struct l_dbus *dbus,
- struct l_dbus_message *message,
- struct l_dbus_message *reply)
- {
- pending_property_set_done_common(dbus, message, reply, true);
- }
- static void pending_property_set_done(struct l_dbus *dbus,
- struct l_dbus_message *message,
- struct l_dbus_message *reply)
- {
- pending_property_set_done_common(dbus, message, reply, false);
- }
- static struct l_dbus_message *old_set_property(struct l_dbus *dbus,
- struct l_dbus_message *message,
- void *user_data)
- {
- struct l_dbus_interface *interface;
- const char *property_name;
- const struct _dbus_property *property;
- struct l_dbus_message_iter variant;
- struct _dbus_object_tree *tree = _dbus_get_tree(dbus);
- struct l_dbus_message *reply;
- l_dbus_property_complete_cb_t complete_cb;
- interface = l_hashmap_lookup(tree->interfaces,
- l_dbus_message_get_interface(message));
- /* If we got here the interface must exist */
- if (!l_dbus_message_get_arguments(message, "sv", &property_name,
- &variant))
- return l_dbus_message_new_error(message,
- "org.freedesktop.DBus.Error."
- "InvalidArgs",
- "Invalid arguments");
- property = _dbus_interface_find_property(interface, property_name);
- if (!property)
- return l_dbus_message_new_error(message,
- "org.freedesktop.DBus.Error."
- "InvalidArgs",
- "Unknown Property %s",
- property_name);
- if (!property->setter)
- return l_dbus_message_new_error(message,
- "org.freedesktop.DBus.Error."
- "InvalidArgs",
- "Property %s is read-only",
- property_name);
- if (property->flags & L_DBUS_PROPERTY_FLAG_AUTO_EMIT)
- complete_cb = pending_property_set_done_emit;
- else
- complete_cb = pending_property_set_done;
- reply = property->setter(dbus, l_dbus_message_ref(message), &variant,
- complete_cb, user_data);
- if (reply)
- complete_cb(dbus, message, reply);
- return NULL;
- }
- static struct l_dbus_message *old_get_properties(struct l_dbus *dbus,
- struct l_dbus_message *message,
- void *user_data)
- {
- const struct l_dbus_interface *interface;
- struct l_dbus_message *reply;
- struct l_dbus_message_builder *builder;
- struct _dbus_object_tree *tree = _dbus_get_tree(dbus);
- interface = l_hashmap_lookup(tree->interfaces,
- l_dbus_message_get_interface(message));
- /* If we got here the interface must exist */
- reply = l_dbus_message_new_method_return(message);
- builder = l_dbus_message_builder_new(reply);
- if (!get_properties_dict(dbus, message, builder, interface,
- user_data)) {
- l_dbus_message_unref(reply);
- reply = l_dbus_message_new_error(message,
- "org.freedesktop.DBus.Error."
- "Failed",
- "Getting properties failed");
- } else
- l_dbus_message_builder_finalize(builder);
- l_dbus_message_builder_destroy(builder);
- return reply;
- }
- bool _dbus_object_tree_register_interface(struct _dbus_object_tree *tree,
- const char *interface,
- void (*setup_func)(struct l_dbus_interface *),
- void (*destroy) (void *),
- bool old_style_properties)
- {
- struct l_dbus_interface *dbi;
- if (!_dbus_valid_interface(interface))
- return false;
- /*
- * Check to make sure we do not have this interface already
- * registered
- */
- dbi = l_hashmap_lookup(tree->interfaces, interface);
- if (dbi)
- return false;
- dbi = _dbus_interface_new(interface);
- dbi->instance_destroy = destroy;
- dbi->handle_old_style_properties = old_style_properties;
- /* Add our methods first so we don't have to check for conflicts. */
- if (old_style_properties) {
- l_dbus_interface_method(dbi, "SetProperty", 0,
- old_set_property, "", "sv",
- "name", "value");
- l_dbus_interface_method(dbi, "GetProperties", 0,
- old_get_properties, "a{sv}", "",
- "properties");
- l_dbus_interface_signal(dbi, "PropertyChanged", 0, "sv",
- "name", "value");
- }
- setup_func(dbi);
- l_hashmap_insert(tree->interfaces, dbi->name, dbi);
- return true;
- }
- struct interface_check {
- struct _dbus_object_tree *tree;
- const char *interface;
- };
- static void check_interface_used(const void *key, void *value, void *user_data)
- {
- const char *path = key;
- struct object_node *node = value;
- struct interface_check *state = user_data;
- if (!l_queue_find(node->instances, match_interface_instance,
- (char *) state->interface))
- return;
- _dbus_object_tree_remove_interface(state->tree, path, state->interface);
- }
- bool _dbus_object_tree_unregister_interface(struct _dbus_object_tree *tree,
- const char *interface_name)
- {
- struct l_dbus_interface *interface;
- struct interface_check state = { tree, interface_name };
- interface = l_hashmap_lookup(tree->interfaces, interface_name);
- if (!interface)
- return false;
- /* Check that the interface is not in use */
- l_hashmap_foreach(tree->objects, check_interface_used, &state);
- l_hashmap_remove(tree->interfaces, interface_name);
- _dbus_interface_free(interface);
- return true;
- }
- static void collect_instances(struct object_node *node,
- const char *path,
- struct l_queue *announce)
- {
- const struct l_queue_entry *entry;
- struct interface_add_record *change_rec;
- const struct child_node *child;
- if (!node->instances)
- goto recurse;
- change_rec = l_new(struct interface_add_record, 1);
- change_rec->path = l_strdup(path);
- change_rec->object = node;
- change_rec->instances = l_queue_new();
- for (entry = l_queue_get_entries(node->instances); entry;
- entry = entry->next)
- l_queue_push_tail(change_rec->instances, entry->data);
- l_queue_push_tail(announce, change_rec);
- recurse:
- if (!strcmp(path, "/"))
- path = "";
- for (child = node->children; child; child = child->next) {
- char *child_path;
- child_path = l_strdup_printf("%s/%s", path, child->subpath);
- collect_instances(child->node, child_path, announce);
- l_free(child_path);
- }
- }
- static bool match_interfaces_added_object(const void *a, const void *b)
- {
- const struct interface_add_record *rec = a;
- return rec->object == b;
- }
- static bool match_interfaces_removed_object(const void *a, const void *b)
- {
- const struct interface_remove_record *rec = a;
- return rec->object == b;
- }
- bool _dbus_object_tree_add_interface(struct _dbus_object_tree *tree,
- const char *path, const char *interface,
- void *user_data)
- {
- struct object_node *object;
- struct l_dbus_interface *dbi;
- struct interface_instance *instance;
- const struct l_queue_entry *entry;
- struct object_manager *manager;
- size_t path_len;
- struct interface_add_record *change_rec;
- dbi = l_hashmap_lookup(tree->interfaces, interface);
- if (!dbi)
- return false;
- object = l_hashmap_lookup(tree->objects, path);
- if (!object) {
- object = _dbus_object_tree_new_object(tree, path, NULL, NULL);
- if (!object)
- return false;
- }
- /*
- * Check to make sure we do not have this interface already
- * registered for this object
- */
- if (l_queue_find(object->instances, match_interface_instance_ptr, dbi))
- return false;
- instance = l_new(struct interface_instance, 1);
- instance->interface = dbi;
- instance->user_data = user_data;
- l_queue_push_tail(object->instances, instance);
- for (entry = l_queue_get_entries(tree->object_managers); entry;
- entry = entry->next) {
- manager = entry->data;
- path_len = strlen(manager->path);
- if (strncmp(path, manager->path, path_len) ||
- (path[path_len] != '\0' &&
- path[path_len] != '/' && path_len > 1))
- continue;
- change_rec = l_queue_find(manager->announce_added,
- match_interfaces_added_object,
- object);
- if (!change_rec) {
- change_rec = l_new(struct interface_add_record, 1);
- change_rec->path = l_strdup(path);
- change_rec->object = object;
- change_rec->instances = l_queue_new();
- l_queue_push_tail(manager->announce_added, change_rec);
- }
- /* No need to check for duplicates here */
- l_queue_push_tail(change_rec->instances, instance);
- schedule_emit_signals(manager->dbus);
- }
- if (!strcmp(interface, L_DBUS_INTERFACE_OBJECT_MANAGER)) {
- manager = l_new(struct object_manager, 1);
- manager->path = l_strdup(path);
- manager->dbus = instance->user_data;
- manager->announce_added = l_queue_new();
- manager->announce_removed = l_queue_new();
- l_queue_push_tail(tree->object_managers, manager);
- /* Emit InterfacesAdded for interfaces added before OM */
- collect_instances(object, path, manager->announce_added);
- if (manager->dbus && !l_queue_isempty(manager->announce_added))
- schedule_emit_signals(manager->dbus);
- }
- return true;
- }
- void *_dbus_object_tree_get_interface_data(struct _dbus_object_tree *tree,
- const char *path,
- const char *interface)
- {
- struct object_node *object;
- struct interface_instance *instance;
- object = l_hashmap_lookup(tree->objects, path);
- if (!object)
- return NULL;
- instance = l_queue_find(object->instances, match_interface_instance,
- (char *) interface);
- if (!instance)
- return NULL;
- return instance->user_data;
- }
- static bool match_object_manager_path(const void *a, const void *b)
- {
- const struct object_manager *manager = a;
- return !strcmp(manager->path, b);
- }
- bool _dbus_object_tree_remove_interface(struct _dbus_object_tree *tree,
- const char *path, const char *interface)
- {
- struct object_node *node;
- struct interface_instance *instance;
- const struct l_queue_entry *entry;
- struct object_manager *manager;
- size_t path_len;
- struct interface_add_record *interfaces_added_rec;
- struct interface_remove_record *interfaces_removed_rec;
- struct property_change_record *property_change_rec;
- node = l_hashmap_lookup(tree->objects, path);
- if (!node)
- return false;
- instance = l_queue_remove_if(node->instances,
- match_interface_instance, (char *) interface);
- if (!instance)
- return false;
- if (!strcmp(interface, L_DBUS_INTERFACE_OBJECT_MANAGER)) {
- manager = l_queue_remove_if(tree->object_managers,
- match_object_manager_path,
- (char *) path);
- if (manager)
- object_manager_free(manager);
- }
- for (entry = l_queue_get_entries(tree->object_managers); entry;
- entry = entry->next) {
- manager = entry->data;
- path_len = strlen(manager->path);
- if (strncmp(path, manager->path, path_len) ||
- (path[path_len] != '\0' &&
- path[path_len] != '/' && path_len > 1))
- continue;
- interfaces_added_rec = l_queue_find(manager->announce_added,
- match_interfaces_added_object,
- node);
- if (interfaces_added_rec && l_queue_remove(
- interfaces_added_rec->instances,
- instance)) {
- if (l_queue_isempty(interfaces_added_rec->instances))
- l_queue_remove(manager->announce_added,
- interfaces_added_rec);
- interface_add_record_free(interfaces_added_rec);
- continue;
- }
- interfaces_removed_rec = l_queue_find(manager->announce_removed,
- match_interfaces_removed_object,
- node);
- if (!interfaces_removed_rec) {
- interfaces_removed_rec =
- l_new(struct interface_remove_record, 1);
- interfaces_removed_rec->path = l_strdup(path);
- interfaces_removed_rec->object = node;
- interfaces_removed_rec->interface_names =
- l_queue_new();
- l_queue_push_tail(manager->announce_removed,
- interfaces_removed_rec);
- }
- /* No need to check for duplicates here */
- l_queue_push_tail(interfaces_removed_rec->interface_names,
- l_strdup(interface));
- schedule_emit_signals(manager->dbus);
- }
- property_change_rec = l_queue_remove_if(tree->property_changes,
- match_property_changes_instance,
- instance);
- if (property_change_rec)
- property_change_record_free(property_change_rec);
- interface_instance_free(instance);
- return true;
- }
- static void generate_interface_instance(void *data, void *user)
- {
- struct interface_instance *instance = data;
- struct l_string *buf = user;
- _dbus_interface_introspection(instance->interface, buf);
- }
- void _dbus_object_tree_introspect(struct _dbus_object_tree *tree,
- const char *path, struct l_string *buf)
- {
- struct object_node *node;
- struct child_node *child;
- bool path_is_object = true;
- node = l_hashmap_lookup(tree->objects, path);
- if (!node) {
- path_is_object = false;
- node = _dbus_object_tree_lookup(tree, path);
- }
- l_string_append(buf, XML_HEAD);
- l_string_append(buf, "<node>\n");
- if (node) {
- /*
- * We emit org.freedesktop.DBus.Introspectable only in case the
- * object node corresponds to a registered object, i.e.
- * exposes anything other than:
- * - org.freedesktop.DBus.Introspectable
- * - org.freedesktop.DBus.Peer
- * - org.freedesktop.DBus.Properties
- */
- if (path_is_object)
- l_string_append(buf, static_introspectable);
- l_queue_foreach(node->instances,
- generate_interface_instance, buf);
- for (child = node->children; child; child = child->next)
- l_string_append_printf(buf, "\t<node name=\"%s\"/>\n",
- child->subpath);
- }
- l_string_append(buf, "</node>\n");
- }
- bool _dbus_object_tree_dispatch(struct _dbus_object_tree *tree,
- struct l_dbus *dbus,
- struct l_dbus_message *message)
- {
- const char *path;
- const char *interface;
- const char *member;
- const char *msg_sig;
- const char *sig;
- struct object_node *node;
- struct interface_instance *instance;
- struct _dbus_method *method;
- struct l_dbus_message *reply;
- path = l_dbus_message_get_path(message);
- interface = l_dbus_message_get_interface(message);
- member = l_dbus_message_get_member(message);
- msg_sig = l_dbus_message_get_signature(message);
- /*
- * Nothing in the spec explicitly forbids this, but handling of such
- * messages is left up to the implementation.
- *
- * TODO: Another route is to go looking for a matching method under this
- * object and call it.
- */
- if (!interface)
- return false;
- if (!msg_sig)
- msg_sig = "";
- if (!strcmp(interface, "org.freedesktop.DBus.Introspectable") &&
- !strcmp(member, "Introspect") &&
- !strcmp(msg_sig, "")) {
- struct l_string *buf;
- char *xml;
- buf = l_string_new(0);
- _dbus_object_tree_introspect(tree, path, buf);
- xml = l_string_unwrap(buf);
- reply = l_dbus_message_new_method_return(message);
- l_dbus_message_set_arguments(reply, "s", xml);
- l_dbus_send(dbus, reply);
- l_free(xml);
- return true;
- }
- node = l_hashmap_lookup(tree->objects, path);
- if (!node)
- return false;
- instance = l_queue_find(node->instances,
- match_interface_instance, (char *) interface);
- if (!instance)
- return false;
- method = _dbus_interface_find_method(instance->interface, member);
- if (!method)
- return false;
- sig = method->metainfo + method->name_len + 1;
- if (strcmp(msg_sig, sig))
- return false;
- reply = method->cb(dbus, message, instance->user_data);
- if (reply)
- l_dbus_send(dbus, reply);
- return true;
- }
- LIB_EXPORT bool l_dbus_property_changed(struct l_dbus *dbus, const char *path,
- const char *interface,
- const char *property)
- {
- return _dbus_object_tree_property_changed(dbus, path, interface,
- property);
- }
- static struct l_dbus_message *properties_get(struct l_dbus *dbus,
- struct l_dbus_message *message,
- void *user_data)
- {
- const struct interface_instance *instance;
- const char *interface_name, *property_name, *signature;
- const struct _dbus_property *property;
- struct _dbus_object_tree *tree = _dbus_get_tree(dbus);
- const struct object_node *object;
- struct l_dbus_message *reply;
- struct l_dbus_message_builder *builder;
- if (!l_dbus_message_get_arguments(message, "ss", &interface_name,
- &property_name))
- return l_dbus_message_new_error(message,
- "org.freedesktop.DBus.Error."
- "InvalidArgs",
- "Invalid arguments");
- object = l_hashmap_lookup(tree->objects,
- l_dbus_message_get_path(message));
- /* If we got here the object must exist */
- instance = l_queue_find(object->instances,
- match_interface_instance,
- (char *) interface_name);
- if (!instance)
- return l_dbus_message_new_error(message,
- "org.freedesktop.DBus.Error."
- "InvalidArgs",
- "Object has no interface %s",
- interface_name);
- property = _dbus_interface_find_property(instance->interface,
- property_name);
- if (!property)
- return l_dbus_message_new_error(message,
- "org.freedesktop.DBus.Error."
- "InvalidArgs",
- "Unknown Property %s",
- property_name);
- reply = l_dbus_message_new_method_return(message);
- builder = l_dbus_message_builder_new(reply);
- signature = property->metainfo + strlen(property->metainfo) + 1;
- l_dbus_message_builder_enter_variant(builder, signature);
- if (property->getter(dbus, message, builder, instance->user_data)) {
- l_dbus_message_builder_leave_variant(builder);
- l_dbus_message_builder_finalize(builder);
- } else {
- l_dbus_message_unref(reply);
- reply = l_dbus_message_new_error(message,
- "org.freedesktop.DBus.Error."
- "Failed",
- "Getting property value "
- "failed");
- }
- l_dbus_message_builder_destroy(builder);
- return reply;
- }
- static struct l_dbus_message *properties_set(struct l_dbus *dbus,
- struct l_dbus_message *message,
- void *user_data)
- {
- struct l_dbus_interface *interface;
- const struct interface_instance *instance;
- const char *interface_name, *property_name;
- const struct _dbus_property *property;
- struct l_dbus_message_iter variant;
- struct _dbus_object_tree *tree = _dbus_get_tree(dbus);
- const struct object_node *object;
- struct l_dbus_message *reply;
- l_dbus_property_complete_cb_t complete_cb;
- if (!l_dbus_message_get_arguments(message, "ssv", &interface_name,
- &property_name, &variant))
- return l_dbus_message_new_error(message,
- "org.freedesktop.DBus.Error."
- "InvalidArgs",
- "Invalid arguments");
- interface = l_hashmap_lookup(tree->interfaces, interface_name);
- if (!interface)
- return l_dbus_message_new_error(message,
- "org.freedesktop.DBus.Error."
- "InvalidArgs",
- "Unknown Interface %s",
- interface_name);
- property = _dbus_interface_find_property(interface, property_name);
- if (!property)
- return l_dbus_message_new_error(message,
- "org.freedesktop.DBus.Error."
- "InvalidArgs",
- "Unknown Property %s",
- property_name);
- if (!property->setter)
- return l_dbus_message_new_error(message,
- "org.freedesktop.DBus.Error."
- "InvalidArgs",
- "Property %s is read-only",
- property_name);
- object = l_hashmap_lookup(tree->objects,
- l_dbus_message_get_path(message));
- /* If we got here the object must exist */
- instance = l_queue_find(object->instances,
- match_interface_instance_ptr, interface);
- if (!instance)
- return l_dbus_message_new_error(message,
- "org.freedesktop.DBus.Error."
- "InvalidArgs",
- "Object has no interface %s",
- interface_name);
- if (property->flags & L_DBUS_PROPERTY_FLAG_AUTO_EMIT)
- complete_cb = pending_property_set_done_emit;
- else
- complete_cb = pending_property_set_done;
- reply = property->setter(dbus, l_dbus_message_ref(message), &variant,
- complete_cb, instance->user_data);
- if (reply)
- complete_cb(dbus, message, reply);
- return NULL;
- }
- static struct l_dbus_message *properties_get_all(struct l_dbus *dbus,
- struct l_dbus_message *message,
- void *user_data)
- {
- const struct interface_instance *instance;
- const char *interface_name;
- struct _dbus_object_tree *tree = _dbus_get_tree(dbus);
- const struct object_node *object;
- struct l_dbus_message *reply;
- struct l_dbus_message_builder *builder;
- if (!l_dbus_message_get_arguments(message, "s", &interface_name))
- return l_dbus_message_new_error(message,
- "org.freedesktop.DBus.Error."
- "InvalidArgs",
- "Invalid arguments");
- object = l_hashmap_lookup(tree->objects,
- l_dbus_message_get_path(message));
- /* If we got here the object must exist */
- instance = l_queue_find(object->instances,
- match_interface_instance,
- (char *) interface_name);
- if (!instance)
- return l_dbus_message_new_error(message,
- "org.freedesktop.DBus.Error."
- "InvalidArgs",
- "Object has no interface %s",
- interface_name);
- reply = l_dbus_message_new_method_return(message);
- builder = l_dbus_message_builder_new(reply);
- if (!get_properties_dict(dbus, message, builder, instance->interface,
- instance->user_data)) {
- l_dbus_message_unref(reply);
- reply = l_dbus_message_new_error(message,
- "org.freedesktop.DBus.Error."
- "Failed",
- "Getting property values "
- "failed");
- } else
- l_dbus_message_builder_finalize(builder);
- l_dbus_message_builder_destroy(builder);
- return reply;
- }
- static void properties_setup_func(struct l_dbus_interface *interface)
- {
- l_dbus_interface_method(interface, "Get", 0,
- properties_get, "v", "ss",
- "value", "interface_name", "property_name");
- l_dbus_interface_method(interface, "Set", 0,
- properties_set, "", "ssv",
- "interface_name", "property_name", "value");
- l_dbus_interface_method(interface, "GetAll", 0,
- properties_get_all, "a{sv}", "s",
- "props", "interface_name");
- l_dbus_interface_signal(interface, "PropertiesChanged", 0, "sa{sv}as",
- "interface_name", "changed_properties",
- "invalidated_properties");
- }
- static bool collect_objects(struct l_dbus *dbus, struct l_dbus_message *message,
- struct l_dbus_message_builder *builder,
- const struct object_node *node,
- const char *path)
- {
- const struct l_queue_entry *entry;
- const struct child_node *child;
- char *child_path;
- const struct interface_instance *instance;
- bool r;
- if (!node->instances)
- goto recurse;
- l_dbus_message_builder_enter_dict(builder, "oa{sa{sv}}");
- l_dbus_message_builder_append_basic(builder, 'o', path);
- l_dbus_message_builder_enter_array(builder, "{sa{sv}}");
- for (entry = l_queue_get_entries(node->instances); entry;
- entry = entry->next) {
- instance = entry->data;
- l_dbus_message_builder_enter_dict(builder, "sa{sv}");
- l_dbus_message_builder_append_basic(builder, 's',
- instance->interface->name);
- if (!get_properties_dict(dbus, message, builder,
- instance->interface,
- instance->user_data))
- return false;
- l_dbus_message_builder_leave_dict(builder);
- }
- l_dbus_message_builder_leave_array(builder);
- l_dbus_message_builder_leave_dict(builder);
- recurse:
- if (!strcmp(path, "/"))
- path = "";
- for (child = node->children; child; child = child->next) {
- child_path = l_strdup_printf("%s/%s", path, child->subpath);
- r = collect_objects(dbus, message, builder,
- child->node, child_path);
- l_free(child_path);
- if (!r)
- return false;
- }
- return true;
- }
- struct l_dbus_message *_dbus_object_tree_get_objects(
- struct _dbus_object_tree *tree,
- struct l_dbus *dbus,
- const char *path,
- struct l_dbus_message *message)
- {
- const struct object_node *node;
- struct l_dbus_message *reply;
- struct l_dbus_message_builder *builder;
- node = l_hashmap_lookup(tree->objects, path);
- reply = l_dbus_message_new_method_return(message);
- builder = l_dbus_message_builder_new(reply);
- l_dbus_message_builder_enter_array(builder, "{oa{sa{sv}}}");
- if (!collect_objects(dbus, message, builder, node, path)) {
- l_dbus_message_builder_destroy(builder);
- l_dbus_message_unref(reply);
- return l_dbus_message_new_error(message,
- "org.freedesktop.DBus.Error."
- "Failed",
- "Getting property values "
- "failed");
- }
- l_dbus_message_builder_leave_array(builder);
- l_dbus_message_builder_finalize(builder);
- l_dbus_message_builder_destroy(builder);
- return reply;
- }
- static struct l_dbus_message *get_managed_objects(struct l_dbus *dbus,
- struct l_dbus_message *message,
- void *user_data)
- {
- struct _dbus_object_tree *tree = _dbus_get_tree(dbus);
- const char *path = l_dbus_message_get_path(message);
- return _dbus_object_tree_get_objects(tree, dbus, path, message);
- }
- static void object_manager_setup_func(struct l_dbus_interface *interface)
- {
- l_dbus_interface_method(interface, "GetManagedObjects", 0,
- get_managed_objects, "a{oa{sa{sv}}}", "",
- "objpath_interfaces_and_properties");
- l_dbus_interface_signal(interface, "InterfacesAdded", 0, "oa{sa{sv}}",
- "object_path", "interfaces_and_properties");
- l_dbus_interface_signal(interface, "InterfacesRemoved", 0, "oas",
- "object_path", "interfaces");
- }
|