object.c 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. *
  4. * D-Bus helper library
  5. *
  6. * Copyright (C) 2004-2011 Marcel Holtmann <marcel@holtmann.org>
  7. *
  8. *
  9. */
  10. #ifdef HAVE_CONFIG_H
  11. #include <config.h>
  12. #endif
  13. #include <stdio.h>
  14. #include <string.h>
  15. #include <glib.h>
  16. #include <dbus/dbus.h>
  17. #include "gdbus.h"
  18. #define info(fmt...)
  19. #define error(fmt...)
  20. #define debug(fmt...)
  21. #define DBUS_INTERFACE_OBJECT_MANAGER "org.freedesktop.DBus.ObjectManager"
  22. #ifndef DBUS_ERROR_UNKNOWN_PROPERTY
  23. #define DBUS_ERROR_UNKNOWN_PROPERTY "org.freedesktop.DBus.Error.UnknownProperty"
  24. #endif
  25. #ifndef DBUS_ERROR_PROPERTY_READ_ONLY
  26. #define DBUS_ERROR_PROPERTY_READ_ONLY "org.freedesktop.DBus.Error.PropertyReadOnly"
  27. #endif
  28. struct generic_data {
  29. unsigned int refcount;
  30. DBusConnection *conn;
  31. char *path;
  32. GSList *interfaces;
  33. GSList *objects;
  34. GSList *added;
  35. GSList *removed;
  36. guint process_id;
  37. gboolean pending_prop;
  38. char *introspect;
  39. struct generic_data *parent;
  40. };
  41. struct interface_data {
  42. char *name;
  43. const GDBusMethodTable *methods;
  44. const GDBusSignalTable *signals;
  45. const GDBusPropertyTable *properties;
  46. GSList *pending_prop;
  47. void *user_data;
  48. GDBusDestroyFunction destroy;
  49. };
  50. struct security_data {
  51. GDBusPendingReply pending;
  52. DBusMessage *message;
  53. const GDBusMethodTable *method;
  54. void *iface_user_data;
  55. };
  56. struct property_data {
  57. DBusConnection *conn;
  58. GDBusPendingPropertySet id;
  59. DBusMessage *message;
  60. };
  61. static int global_flags = 0;
  62. static struct generic_data *root;
  63. static GSList *pending = NULL;
  64. static gboolean process_changes(gpointer user_data);
  65. static void process_properties_from_interface(struct generic_data *data,
  66. struct interface_data *iface);
  67. static void process_property_changes(struct generic_data *data);
  68. static void print_arguments(GString *gstr, const GDBusArgInfo *args,
  69. const char *direction)
  70. {
  71. for (; args && args->name; args++) {
  72. g_string_append_printf(gstr,
  73. "<arg name=\"%s\" type=\"%s\"",
  74. args->name, args->signature);
  75. if (direction)
  76. g_string_append_printf(gstr,
  77. " direction=\"%s\"/>\n", direction);
  78. else
  79. g_string_append_printf(gstr, "/>\n");
  80. }
  81. }
  82. #define G_DBUS_ANNOTATE(name_, value_) \
  83. "<annotation name=\"org.freedesktop.DBus." name_ "\" " \
  84. "value=\"" value_ "\"/>"
  85. #define G_DBUS_ANNOTATE_DEPRECATED \
  86. G_DBUS_ANNOTATE("Deprecated", "true")
  87. #define G_DBUS_ANNOTATE_NOREPLY \
  88. G_DBUS_ANNOTATE("Method.NoReply", "true")
  89. static gboolean check_experimental(int flags, int flag)
  90. {
  91. if (!(flags & flag))
  92. return FALSE;
  93. return !(global_flags & G_DBUS_FLAG_ENABLE_EXPERIMENTAL);
  94. }
  95. static void generate_interface_xml(GString *gstr, struct interface_data *iface)
  96. {
  97. const GDBusMethodTable *method;
  98. const GDBusSignalTable *signal;
  99. const GDBusPropertyTable *property;
  100. for (method = iface->methods; method && method->name; method++) {
  101. if (check_experimental(method->flags,
  102. G_DBUS_METHOD_FLAG_EXPERIMENTAL))
  103. continue;
  104. g_string_append_printf(gstr, "<method name=\"%s\">",
  105. method->name);
  106. print_arguments(gstr, method->in_args, "in");
  107. print_arguments(gstr, method->out_args, "out");
  108. if (method->flags & G_DBUS_METHOD_FLAG_DEPRECATED)
  109. g_string_append_printf(gstr,
  110. G_DBUS_ANNOTATE_DEPRECATED);
  111. if (method->flags & G_DBUS_METHOD_FLAG_NOREPLY)
  112. g_string_append_printf(gstr, G_DBUS_ANNOTATE_NOREPLY);
  113. g_string_append_printf(gstr, "</method>");
  114. }
  115. for (signal = iface->signals; signal && signal->name; signal++) {
  116. if (check_experimental(signal->flags,
  117. G_DBUS_SIGNAL_FLAG_EXPERIMENTAL))
  118. continue;
  119. g_string_append_printf(gstr, "<signal name=\"%s\">",
  120. signal->name);
  121. print_arguments(gstr, signal->args, NULL);
  122. if (signal->flags & G_DBUS_SIGNAL_FLAG_DEPRECATED)
  123. g_string_append_printf(gstr,
  124. G_DBUS_ANNOTATE_DEPRECATED);
  125. g_string_append_printf(gstr, "</signal>\n");
  126. }
  127. for (property = iface->properties; property && property->name;
  128. property++) {
  129. if (check_experimental(property->flags,
  130. G_DBUS_PROPERTY_FLAG_EXPERIMENTAL))
  131. continue;
  132. g_string_append_printf(gstr, "<property name=\"%s\""
  133. " type=\"%s\" access=\"%s%s\">",
  134. property->name, property->type,
  135. property->get ? "read" : "",
  136. property->set ? "write" : "");
  137. if (property->flags & G_DBUS_PROPERTY_FLAG_DEPRECATED)
  138. g_string_append_printf(gstr,
  139. G_DBUS_ANNOTATE_DEPRECATED);
  140. g_string_append_printf(gstr, "</property>");
  141. }
  142. }
  143. static void generate_introspection_xml(DBusConnection *conn,
  144. struct generic_data *data, const char *path)
  145. {
  146. GSList *list;
  147. GString *gstr;
  148. char **children;
  149. int i;
  150. g_free(data->introspect);
  151. gstr = g_string_new(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE);
  152. g_string_append_printf(gstr, "<node>");
  153. for (list = data->interfaces; list; list = list->next) {
  154. struct interface_data *iface = list->data;
  155. g_string_append_printf(gstr, "<interface name=\"%s\">",
  156. iface->name);
  157. generate_interface_xml(gstr, iface);
  158. g_string_append_printf(gstr, "</interface>");
  159. }
  160. if (!dbus_connection_list_registered(conn, path, &children))
  161. goto done;
  162. for (i = 0; children[i]; i++)
  163. g_string_append_printf(gstr, "<node name=\"%s\"/>",
  164. children[i]);
  165. dbus_free_string_array(children);
  166. done:
  167. g_string_append_printf(gstr, "</node>");
  168. data->introspect = g_string_free(gstr, FALSE);
  169. }
  170. static DBusMessage *introspect(DBusConnection *connection,
  171. DBusMessage *message, void *user_data)
  172. {
  173. struct generic_data *data = user_data;
  174. DBusMessage *reply;
  175. if (data->introspect == NULL)
  176. generate_introspection_xml(connection, data,
  177. dbus_message_get_path(message));
  178. reply = dbus_message_new_method_return(message);
  179. if (reply == NULL)
  180. return NULL;
  181. dbus_message_append_args(reply, DBUS_TYPE_STRING, &data->introspect,
  182. DBUS_TYPE_INVALID);
  183. return reply;
  184. }
  185. static DBusHandlerResult process_message(DBusConnection *connection,
  186. DBusMessage *message, const GDBusMethodTable *method,
  187. void *iface_user_data)
  188. {
  189. DBusMessage *reply;
  190. reply = method->function(connection, message, iface_user_data);
  191. if (method->flags & G_DBUS_METHOD_FLAG_NOREPLY ||
  192. dbus_message_get_no_reply(message)) {
  193. if (reply != NULL)
  194. dbus_message_unref(reply);
  195. return DBUS_HANDLER_RESULT_HANDLED;
  196. }
  197. if (method->flags & G_DBUS_METHOD_FLAG_ASYNC) {
  198. if (reply == NULL)
  199. return DBUS_HANDLER_RESULT_HANDLED;
  200. }
  201. if (reply == NULL)
  202. return DBUS_HANDLER_RESULT_NEED_MEMORY;
  203. g_dbus_send_message(connection, reply);
  204. return DBUS_HANDLER_RESULT_HANDLED;
  205. }
  206. static GDBusPendingReply next_pending = 1;
  207. static GSList *pending_security = NULL;
  208. static const GDBusSecurityTable *security_table = NULL;
  209. void g_dbus_pending_success(DBusConnection *connection,
  210. GDBusPendingReply pending)
  211. {
  212. GSList *list;
  213. for (list = pending_security; list; list = list->next) {
  214. struct security_data *secdata = list->data;
  215. if (secdata->pending != pending)
  216. continue;
  217. pending_security = g_slist_remove(pending_security, secdata);
  218. process_message(connection, secdata->message,
  219. secdata->method, secdata->iface_user_data);
  220. dbus_message_unref(secdata->message);
  221. g_free(secdata);
  222. return;
  223. }
  224. }
  225. void g_dbus_pending_error_valist(DBusConnection *connection,
  226. GDBusPendingReply pending, const char *name,
  227. const char *format, va_list args)
  228. {
  229. GSList *list;
  230. for (list = pending_security; list; list = list->next) {
  231. struct security_data *secdata = list->data;
  232. if (secdata->pending != pending)
  233. continue;
  234. pending_security = g_slist_remove(pending_security, secdata);
  235. g_dbus_send_error_valist(connection, secdata->message,
  236. name, format, args);
  237. dbus_message_unref(secdata->message);
  238. g_free(secdata);
  239. return;
  240. }
  241. }
  242. void g_dbus_pending_error(DBusConnection *connection,
  243. GDBusPendingReply pending,
  244. const char *name, const char *format, ...)
  245. {
  246. va_list args;
  247. va_start(args, format);
  248. g_dbus_pending_error_valist(connection, pending, name, format, args);
  249. va_end(args);
  250. }
  251. int polkit_check_authorization(DBusConnection *conn,
  252. const char *action, gboolean interaction,
  253. void (*function) (dbus_bool_t authorized,
  254. void *user_data),
  255. void *user_data, int timeout);
  256. struct builtin_security_data {
  257. DBusConnection *conn;
  258. GDBusPendingReply pending;
  259. };
  260. static void builtin_security_result(dbus_bool_t authorized, void *user_data)
  261. {
  262. struct builtin_security_data *data = user_data;
  263. if (authorized == TRUE)
  264. g_dbus_pending_success(data->conn, data->pending);
  265. else
  266. g_dbus_pending_error(data->conn, data->pending,
  267. DBUS_ERROR_AUTH_FAILED, NULL);
  268. g_free(data);
  269. }
  270. static void builtin_security_function(DBusConnection *conn,
  271. const char *action,
  272. gboolean interaction,
  273. GDBusPendingReply pending)
  274. {
  275. struct builtin_security_data *data;
  276. data = g_new0(struct builtin_security_data, 1);
  277. data->conn = conn;
  278. data->pending = pending;
  279. if (polkit_check_authorization(conn, action, interaction,
  280. builtin_security_result, data, 30000) < 0)
  281. g_dbus_pending_error(conn, pending, NULL, NULL);
  282. }
  283. static gboolean check_privilege(DBusConnection *conn, DBusMessage *msg,
  284. const GDBusMethodTable *method, void *iface_user_data)
  285. {
  286. const GDBusSecurityTable *security;
  287. for (security = security_table; security && security->privilege;
  288. security++) {
  289. struct security_data *secdata;
  290. gboolean interaction;
  291. if (security->privilege != method->privilege)
  292. continue;
  293. secdata = g_new(struct security_data, 1);
  294. secdata->pending = next_pending++;
  295. secdata->message = dbus_message_ref(msg);
  296. secdata->method = method;
  297. secdata->iface_user_data = iface_user_data;
  298. pending_security = g_slist_prepend(pending_security, secdata);
  299. if (security->flags & G_DBUS_SECURITY_FLAG_ALLOW_INTERACTION)
  300. interaction = TRUE;
  301. else
  302. interaction = FALSE;
  303. if (!(security->flags & G_DBUS_SECURITY_FLAG_BUILTIN) &&
  304. security->function)
  305. security->function(conn, security->action,
  306. interaction, secdata->pending);
  307. else
  308. builtin_security_function(conn, security->action,
  309. interaction, secdata->pending);
  310. return TRUE;
  311. }
  312. return FALSE;
  313. }
  314. static GDBusPendingPropertySet next_pending_property = 1;
  315. static GSList *pending_property_set;
  316. static struct property_data *remove_pending_property_data(
  317. GDBusPendingPropertySet id)
  318. {
  319. struct property_data *propdata;
  320. GSList *l;
  321. for (l = pending_property_set; l != NULL; l = l->next) {
  322. propdata = l->data;
  323. if (propdata->id != id)
  324. continue;
  325. break;
  326. }
  327. if (l == NULL)
  328. return NULL;
  329. pending_property_set = g_slist_delete_link(pending_property_set, l);
  330. return propdata;
  331. }
  332. void g_dbus_pending_property_success(GDBusPendingPropertySet id)
  333. {
  334. struct property_data *propdata;
  335. propdata = remove_pending_property_data(id);
  336. if (propdata == NULL)
  337. return;
  338. g_dbus_send_reply(propdata->conn, propdata->message,
  339. DBUS_TYPE_INVALID);
  340. dbus_message_unref(propdata->message);
  341. g_free(propdata);
  342. }
  343. void g_dbus_pending_property_error_valist(GDBusPendingReply id,
  344. const char *name, const char *format,
  345. va_list args)
  346. {
  347. struct property_data *propdata;
  348. propdata = remove_pending_property_data(id);
  349. if (propdata == NULL)
  350. return;
  351. g_dbus_send_error_valist(propdata->conn, propdata->message, name,
  352. format, args);
  353. dbus_message_unref(propdata->message);
  354. g_free(propdata);
  355. }
  356. void g_dbus_pending_property_error(GDBusPendingReply id, const char *name,
  357. const char *format, ...)
  358. {
  359. va_list args;
  360. va_start(args, format);
  361. g_dbus_pending_property_error_valist(id, name, format, args);
  362. va_end(args);
  363. }
  364. static void reset_parent(gpointer data, gpointer user_data)
  365. {
  366. struct generic_data *child = data;
  367. struct generic_data *parent = user_data;
  368. child->parent = parent;
  369. }
  370. static void append_property(struct interface_data *iface,
  371. const GDBusPropertyTable *p, DBusMessageIter *dict)
  372. {
  373. DBusMessageIter entry, value;
  374. dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL,
  375. &entry);
  376. dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &p->name);
  377. dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, p->type,
  378. &value);
  379. p->get(p, &value, iface->user_data);
  380. dbus_message_iter_close_container(&entry, &value);
  381. dbus_message_iter_close_container(dict, &entry);
  382. }
  383. static void append_properties(struct interface_data *data,
  384. DBusMessageIter *iter)
  385. {
  386. DBusMessageIter dict;
  387. const GDBusPropertyTable *p;
  388. dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
  389. DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
  390. DBUS_TYPE_STRING_AS_STRING
  391. DBUS_TYPE_VARIANT_AS_STRING
  392. DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
  393. for (p = data->properties; p && p->name; p++) {
  394. if (check_experimental(p->flags,
  395. G_DBUS_PROPERTY_FLAG_EXPERIMENTAL))
  396. continue;
  397. if (p->get == NULL)
  398. continue;
  399. if (p->exists != NULL && !p->exists(p, data->user_data))
  400. continue;
  401. append_property(data, p, &dict);
  402. }
  403. dbus_message_iter_close_container(iter, &dict);
  404. }
  405. static void append_interface(gpointer data, gpointer user_data)
  406. {
  407. struct interface_data *iface = data;
  408. DBusMessageIter *array = user_data;
  409. DBusMessageIter entry;
  410. dbus_message_iter_open_container(array, DBUS_TYPE_DICT_ENTRY, NULL,
  411. &entry);
  412. dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &iface->name);
  413. append_properties(data, &entry);
  414. dbus_message_iter_close_container(array, &entry);
  415. }
  416. static void emit_interfaces_added(struct generic_data *data)
  417. {
  418. DBusMessage *signal;
  419. DBusMessageIter iter, array;
  420. if (root == NULL || data == root)
  421. return;
  422. signal = dbus_message_new_signal(root->path,
  423. DBUS_INTERFACE_OBJECT_MANAGER,
  424. "InterfacesAdded");
  425. if (signal == NULL)
  426. return;
  427. dbus_message_iter_init_append(signal, &iter);
  428. dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
  429. &data->path);
  430. dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
  431. DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
  432. DBUS_TYPE_STRING_AS_STRING
  433. DBUS_TYPE_ARRAY_AS_STRING
  434. DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
  435. DBUS_TYPE_STRING_AS_STRING
  436. DBUS_TYPE_VARIANT_AS_STRING
  437. DBUS_DICT_ENTRY_END_CHAR_AS_STRING
  438. DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &array);
  439. g_slist_foreach(data->added, append_interface, &array);
  440. g_slist_free(data->added);
  441. data->added = NULL;
  442. dbus_message_iter_close_container(&iter, &array);
  443. /* Use dbus_connection_send to avoid recursive calls to g_dbus_flush */
  444. dbus_connection_send(data->conn, signal, NULL);
  445. dbus_message_unref(signal);
  446. }
  447. static struct interface_data *find_interface(GSList *interfaces,
  448. const char *name)
  449. {
  450. GSList *list;
  451. if (name == NULL)
  452. return NULL;
  453. for (list = interfaces; list; list = list->next) {
  454. struct interface_data *iface = list->data;
  455. if (!strcmp(name, iface->name))
  456. return iface;
  457. }
  458. return NULL;
  459. }
  460. static gboolean g_dbus_args_have_signature(const GDBusArgInfo *args,
  461. DBusMessage *message)
  462. {
  463. const char *sig = dbus_message_get_signature(message);
  464. const char *p = NULL;
  465. for (; args && args->signature && *sig; args++) {
  466. p = args->signature;
  467. for (; *sig && *p; sig++, p++) {
  468. if (*p != *sig)
  469. return FALSE;
  470. }
  471. }
  472. if (*sig || (p && *p) || (args && args->signature))
  473. return FALSE;
  474. return TRUE;
  475. }
  476. static void add_pending(struct generic_data *data)
  477. {
  478. guint old_id = data->process_id;
  479. data->process_id = g_idle_add(process_changes, data);
  480. if (old_id > 0) {
  481. /*
  482. * If the element already had an old idler, remove the old one,
  483. * no need to re-add it to the pending list.
  484. */
  485. g_source_remove(old_id);
  486. return;
  487. }
  488. pending = g_slist_append(pending, data);
  489. }
  490. static gboolean remove_interface(struct generic_data *data, const char *name)
  491. {
  492. struct interface_data *iface;
  493. iface = find_interface(data->interfaces, name);
  494. if (iface == NULL)
  495. return FALSE;
  496. process_properties_from_interface(data, iface);
  497. data->interfaces = g_slist_remove(data->interfaces, iface);
  498. if (iface->destroy) {
  499. iface->destroy(iface->user_data);
  500. iface->user_data = NULL;
  501. }
  502. /*
  503. * Interface being removed was just added, on the same mainloop
  504. * iteration? Don't send any signal
  505. */
  506. if (g_slist_find(data->added, iface)) {
  507. data->added = g_slist_remove(data->added, iface);
  508. g_free(iface->name);
  509. g_free(iface);
  510. return TRUE;
  511. }
  512. if (data->parent == NULL) {
  513. g_free(iface->name);
  514. g_free(iface);
  515. return TRUE;
  516. }
  517. data->removed = g_slist_prepend(data->removed, iface->name);
  518. g_free(iface);
  519. add_pending(data);
  520. return TRUE;
  521. }
  522. static struct generic_data *invalidate_parent_data(DBusConnection *conn,
  523. const char *child_path)
  524. {
  525. struct generic_data *data = NULL, *child = NULL, *parent = NULL;
  526. char *parent_path, *slash;
  527. parent_path = g_strdup(child_path);
  528. slash = strrchr(parent_path, '/');
  529. if (slash == NULL)
  530. goto done;
  531. if (slash == parent_path && parent_path[1] != '\0')
  532. parent_path[1] = '\0';
  533. else
  534. *slash = '\0';
  535. if (!strlen(parent_path))
  536. goto done;
  537. if (dbus_connection_get_object_path_data(conn, parent_path,
  538. (void *) &data) == FALSE) {
  539. goto done;
  540. }
  541. parent = invalidate_parent_data(conn, parent_path);
  542. if (data == NULL) {
  543. data = parent;
  544. if (data == NULL)
  545. goto done;
  546. }
  547. g_free(data->introspect);
  548. data->introspect = NULL;
  549. if (!dbus_connection_get_object_path_data(conn, child_path,
  550. (void *) &child))
  551. goto done;
  552. if (child == NULL || g_slist_find(data->objects, child) != NULL)
  553. goto done;
  554. data->objects = g_slist_prepend(data->objects, child);
  555. child->parent = data;
  556. done:
  557. g_free(parent_path);
  558. return data;
  559. }
  560. static inline const GDBusPropertyTable *find_property(const GDBusPropertyTable *properties,
  561. const char *name)
  562. {
  563. const GDBusPropertyTable *p;
  564. for (p = properties; p && p->name; p++) {
  565. if (strcmp(name, p->name) != 0)
  566. continue;
  567. if (check_experimental(p->flags,
  568. G_DBUS_PROPERTY_FLAG_EXPERIMENTAL))
  569. break;
  570. return p;
  571. }
  572. return NULL;
  573. }
  574. static DBusMessage *properties_get(DBusConnection *connection,
  575. DBusMessage *message, void *user_data)
  576. {
  577. struct generic_data *data = user_data;
  578. struct interface_data *iface;
  579. const GDBusPropertyTable *property;
  580. const char *interface, *name;
  581. DBusMessageIter iter, value;
  582. DBusMessage *reply;
  583. if (!dbus_message_get_args(message, NULL,
  584. DBUS_TYPE_STRING, &interface,
  585. DBUS_TYPE_STRING, &name,
  586. DBUS_TYPE_INVALID))
  587. return NULL;
  588. iface = find_interface(data->interfaces, interface);
  589. if (iface == NULL)
  590. return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
  591. "No such interface '%s'", interface);
  592. property = find_property(iface->properties, name);
  593. if (property == NULL)
  594. return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
  595. "No such property '%s'", name);
  596. if (property->exists != NULL &&
  597. !property->exists(property, iface->user_data))
  598. return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
  599. "No such property '%s'", name);
  600. if (property->get == NULL)
  601. return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
  602. "Property '%s' is not readable", name);
  603. reply = dbus_message_new_method_return(message);
  604. if (reply == NULL)
  605. return NULL;
  606. dbus_message_iter_init_append(reply, &iter);
  607. dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
  608. property->type, &value);
  609. if (!property->get(property, &value, iface->user_data)) {
  610. dbus_message_unref(reply);
  611. return NULL;
  612. }
  613. dbus_message_iter_close_container(&iter, &value);
  614. return reply;
  615. }
  616. static DBusMessage *properties_get_all(DBusConnection *connection,
  617. DBusMessage *message, void *user_data)
  618. {
  619. struct generic_data *data = user_data;
  620. struct interface_data *iface;
  621. const char *interface;
  622. DBusMessageIter iter;
  623. DBusMessage *reply;
  624. if (!dbus_message_get_args(message, NULL,
  625. DBUS_TYPE_STRING, &interface,
  626. DBUS_TYPE_INVALID))
  627. return NULL;
  628. iface = find_interface(data->interfaces, interface);
  629. if (iface == NULL)
  630. return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
  631. "No such interface '%s'", interface);
  632. reply = dbus_message_new_method_return(message);
  633. if (reply == NULL)
  634. return NULL;
  635. dbus_message_iter_init_append(reply, &iter);
  636. append_properties(iface, &iter);
  637. return reply;
  638. }
  639. static DBusMessage *properties_set(DBusConnection *connection,
  640. DBusMessage *message, void *user_data)
  641. {
  642. struct generic_data *data = user_data;
  643. DBusMessageIter iter, sub;
  644. struct interface_data *iface;
  645. const GDBusPropertyTable *property;
  646. const char *name, *interface;
  647. struct property_data *propdata;
  648. gboolean valid_signature;
  649. char *signature;
  650. if (!dbus_message_iter_init(message, &iter))
  651. return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
  652. "No arguments given");
  653. if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
  654. return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
  655. "Invalid argument type: '%c'",
  656. dbus_message_iter_get_arg_type(&iter));
  657. dbus_message_iter_get_basic(&iter, &interface);
  658. dbus_message_iter_next(&iter);
  659. if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
  660. return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
  661. "Invalid argument type: '%c'",
  662. dbus_message_iter_get_arg_type(&iter));
  663. dbus_message_iter_get_basic(&iter, &name);
  664. dbus_message_iter_next(&iter);
  665. if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
  666. return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
  667. "Invalid argument type: '%c'",
  668. dbus_message_iter_get_arg_type(&iter));
  669. dbus_message_iter_recurse(&iter, &sub);
  670. iface = find_interface(data->interfaces, interface);
  671. if (iface == NULL)
  672. return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
  673. "No such interface '%s'", interface);
  674. property = find_property(iface->properties, name);
  675. if (property == NULL)
  676. return g_dbus_create_error(message,
  677. DBUS_ERROR_UNKNOWN_PROPERTY,
  678. "No such property '%s'", name);
  679. if (property->set == NULL)
  680. return g_dbus_create_error(message,
  681. DBUS_ERROR_PROPERTY_READ_ONLY,
  682. "Property '%s' is not writable", name);
  683. if (property->exists != NULL &&
  684. !property->exists(property, iface->user_data))
  685. return g_dbus_create_error(message,
  686. DBUS_ERROR_UNKNOWN_PROPERTY,
  687. "No such property '%s'", name);
  688. signature = dbus_message_iter_get_signature(&sub);
  689. valid_signature = strcmp(signature, property->type) ? FALSE : TRUE;
  690. dbus_free(signature);
  691. if (!valid_signature)
  692. return g_dbus_create_error(message,
  693. DBUS_ERROR_INVALID_SIGNATURE,
  694. "Invalid signature for '%s'", name);
  695. propdata = g_new(struct property_data, 1);
  696. propdata->id = next_pending_property++;
  697. propdata->message = dbus_message_ref(message);
  698. propdata->conn = connection;
  699. pending_property_set = g_slist_prepend(pending_property_set, propdata);
  700. property->set(property, &sub, propdata->id, iface->user_data);
  701. return NULL;
  702. }
  703. static const GDBusMethodTable properties_methods[] = {
  704. { GDBUS_METHOD("Get",
  705. GDBUS_ARGS({ "interface", "s" }, { "name", "s" }),
  706. GDBUS_ARGS({ "value", "v" }),
  707. properties_get) },
  708. { GDBUS_ASYNC_METHOD("Set",
  709. GDBUS_ARGS({ "interface", "s" }, { "name", "s" },
  710. { "value", "v" }),
  711. NULL,
  712. properties_set) },
  713. { GDBUS_METHOD("GetAll",
  714. GDBUS_ARGS({ "interface", "s" }),
  715. GDBUS_ARGS({ "properties", "a{sv}" }),
  716. properties_get_all) },
  717. { }
  718. };
  719. static const GDBusSignalTable properties_signals[] = {
  720. { GDBUS_SIGNAL("PropertiesChanged",
  721. GDBUS_ARGS({ "interface", "s" },
  722. { "changed_properties", "a{sv}" },
  723. { "invalidated_properties", "as"})) },
  724. { }
  725. };
  726. static void append_name(gpointer data, gpointer user_data)
  727. {
  728. char *name = data;
  729. DBusMessageIter *iter = user_data;
  730. dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &name);
  731. }
  732. static void emit_interfaces_removed(struct generic_data *data)
  733. {
  734. DBusMessage *signal;
  735. DBusMessageIter iter, array;
  736. if (root == NULL || data == root)
  737. return;
  738. signal = dbus_message_new_signal(root->path,
  739. DBUS_INTERFACE_OBJECT_MANAGER,
  740. "InterfacesRemoved");
  741. if (signal == NULL)
  742. return;
  743. dbus_message_iter_init_append(signal, &iter);
  744. dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
  745. &data->path);
  746. dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
  747. DBUS_TYPE_STRING_AS_STRING, &array);
  748. g_slist_foreach(data->removed, append_name, &array);
  749. g_slist_free_full(data->removed, g_free);
  750. data->removed = NULL;
  751. dbus_message_iter_close_container(&iter, &array);
  752. /* Use dbus_connection_send to avoid recursive calls to g_dbus_flush */
  753. dbus_connection_send(data->conn, signal, NULL);
  754. dbus_message_unref(signal);
  755. }
  756. static void remove_pending(struct generic_data *data)
  757. {
  758. if (data->process_id > 0) {
  759. g_source_remove(data->process_id);
  760. data->process_id = 0;
  761. }
  762. pending = g_slist_remove(pending, data);
  763. }
  764. static gboolean process_changes(gpointer user_data)
  765. {
  766. struct generic_data *data = user_data;
  767. remove_pending(data);
  768. if (data->added != NULL)
  769. emit_interfaces_added(data);
  770. /* Flush pending properties */
  771. if (data->pending_prop == TRUE)
  772. process_property_changes(data);
  773. if (data->removed != NULL)
  774. emit_interfaces_removed(data);
  775. data->process_id = 0;
  776. return FALSE;
  777. }
  778. static void generic_unregister(DBusConnection *connection, void *user_data)
  779. {
  780. struct generic_data *data = user_data;
  781. struct generic_data *parent = data->parent;
  782. if (parent != NULL)
  783. parent->objects = g_slist_remove(parent->objects, data);
  784. if (data->process_id > 0) {
  785. g_source_remove(data->process_id);
  786. data->process_id = 0;
  787. process_changes(data);
  788. }
  789. g_slist_foreach(data->objects, reset_parent, data->parent);
  790. g_slist_free(data->objects);
  791. dbus_connection_unref(data->conn);
  792. g_free(data->introspect);
  793. g_free(data->path);
  794. g_free(data);
  795. }
  796. static DBusHandlerResult generic_message(DBusConnection *connection,
  797. DBusMessage *message, void *user_data)
  798. {
  799. struct generic_data *data = user_data;
  800. struct interface_data *iface;
  801. const GDBusMethodTable *method;
  802. const char *interface;
  803. interface = dbus_message_get_interface(message);
  804. iface = find_interface(data->interfaces, interface);
  805. if (iface == NULL)
  806. return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
  807. for (method = iface->methods; method &&
  808. method->name && method->function; method++) {
  809. if (dbus_message_is_method_call(message, iface->name,
  810. method->name) == FALSE)
  811. continue;
  812. if (check_experimental(method->flags,
  813. G_DBUS_METHOD_FLAG_EXPERIMENTAL))
  814. return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
  815. if (g_dbus_args_have_signature(method->in_args,
  816. message) == FALSE)
  817. continue;
  818. if (check_privilege(connection, message, method,
  819. iface->user_data) == TRUE)
  820. return DBUS_HANDLER_RESULT_HANDLED;
  821. return process_message(connection, message, method,
  822. iface->user_data);
  823. }
  824. return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
  825. }
  826. static DBusObjectPathVTable generic_table = {
  827. .unregister_function = generic_unregister,
  828. .message_function = generic_message,
  829. };
  830. static const GDBusMethodTable introspect_methods[] = {
  831. { GDBUS_METHOD("Introspect", NULL,
  832. GDBUS_ARGS({ "xml", "s" }), introspect) },
  833. { }
  834. };
  835. static void append_interfaces(struct generic_data *data, DBusMessageIter *iter)
  836. {
  837. DBusMessageIter array;
  838. dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
  839. DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
  840. DBUS_TYPE_STRING_AS_STRING
  841. DBUS_TYPE_ARRAY_AS_STRING
  842. DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
  843. DBUS_TYPE_STRING_AS_STRING
  844. DBUS_TYPE_VARIANT_AS_STRING
  845. DBUS_DICT_ENTRY_END_CHAR_AS_STRING
  846. DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &array);
  847. g_slist_foreach(data->interfaces, append_interface, &array);
  848. dbus_message_iter_close_container(iter, &array);
  849. }
  850. static void append_object(gpointer data, gpointer user_data)
  851. {
  852. struct generic_data *child = data;
  853. DBusMessageIter *array = user_data;
  854. DBusMessageIter entry;
  855. dbus_message_iter_open_container(array, DBUS_TYPE_DICT_ENTRY, NULL,
  856. &entry);
  857. dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH,
  858. &child->path);
  859. append_interfaces(child, &entry);
  860. dbus_message_iter_close_container(array, &entry);
  861. g_slist_foreach(child->objects, append_object, user_data);
  862. }
  863. static DBusMessage *get_objects(DBusConnection *connection,
  864. DBusMessage *message, void *user_data)
  865. {
  866. struct generic_data *data = user_data;
  867. DBusMessage *reply;
  868. DBusMessageIter iter;
  869. DBusMessageIter array;
  870. reply = dbus_message_new_method_return(message);
  871. if (reply == NULL)
  872. return NULL;
  873. dbus_message_iter_init_append(reply, &iter);
  874. dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
  875. DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
  876. DBUS_TYPE_OBJECT_PATH_AS_STRING
  877. DBUS_TYPE_ARRAY_AS_STRING
  878. DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
  879. DBUS_TYPE_STRING_AS_STRING
  880. DBUS_TYPE_ARRAY_AS_STRING
  881. DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
  882. DBUS_TYPE_STRING_AS_STRING
  883. DBUS_TYPE_VARIANT_AS_STRING
  884. DBUS_DICT_ENTRY_END_CHAR_AS_STRING
  885. DBUS_DICT_ENTRY_END_CHAR_AS_STRING
  886. DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
  887. &array);
  888. g_slist_foreach(data->objects, append_object, &array);
  889. dbus_message_iter_close_container(&iter, &array);
  890. return reply;
  891. }
  892. static const GDBusMethodTable manager_methods[] = {
  893. { GDBUS_METHOD("GetManagedObjects", NULL,
  894. GDBUS_ARGS({ "objects", "a{oa{sa{sv}}}" }), get_objects) },
  895. { }
  896. };
  897. static const GDBusSignalTable manager_signals[] = {
  898. { GDBUS_SIGNAL("InterfacesAdded",
  899. GDBUS_ARGS({ "object", "o" },
  900. { "interfaces", "a{sa{sv}}" })) },
  901. { GDBUS_SIGNAL("InterfacesRemoved",
  902. GDBUS_ARGS({ "object", "o" }, { "interfaces", "as" })) },
  903. { }
  904. };
  905. static gboolean add_interface(struct generic_data *data,
  906. const char *name,
  907. const GDBusMethodTable *methods,
  908. const GDBusSignalTable *signals,
  909. const GDBusPropertyTable *properties,
  910. void *user_data,
  911. GDBusDestroyFunction destroy)
  912. {
  913. struct interface_data *iface;
  914. const GDBusMethodTable *method;
  915. const GDBusSignalTable *signal;
  916. const GDBusPropertyTable *property;
  917. for (method = methods; method && method->name; method++) {
  918. if (!check_experimental(method->flags,
  919. G_DBUS_METHOD_FLAG_EXPERIMENTAL))
  920. goto done;
  921. }
  922. for (signal = signals; signal && signal->name; signal++) {
  923. if (!check_experimental(signal->flags,
  924. G_DBUS_SIGNAL_FLAG_EXPERIMENTAL))
  925. goto done;
  926. }
  927. for (property = properties; property && property->name; property++) {
  928. if (!check_experimental(property->flags,
  929. G_DBUS_PROPERTY_FLAG_EXPERIMENTAL))
  930. goto done;
  931. }
  932. /* Nothing to register */
  933. return FALSE;
  934. done:
  935. iface = g_new0(struct interface_data, 1);
  936. iface->name = g_strdup(name);
  937. iface->methods = methods;
  938. iface->signals = signals;
  939. iface->properties = properties;
  940. iface->user_data = user_data;
  941. iface->destroy = destroy;
  942. data->interfaces = g_slist_append(data->interfaces, iface);
  943. if (data->parent == NULL)
  944. return TRUE;
  945. data->added = g_slist_append(data->added, iface);
  946. add_pending(data);
  947. return TRUE;
  948. }
  949. static struct generic_data *object_path_ref(DBusConnection *connection,
  950. const char *path)
  951. {
  952. struct generic_data *data;
  953. if (dbus_connection_get_object_path_data(connection, path,
  954. (void *) &data) == TRUE) {
  955. if (data != NULL) {
  956. data->refcount++;
  957. return data;
  958. }
  959. }
  960. data = g_new0(struct generic_data, 1);
  961. data->conn = dbus_connection_ref(connection);
  962. data->path = g_strdup(path);
  963. data->refcount = 1;
  964. data->introspect = g_strdup(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE "<node></node>");
  965. if (!dbus_connection_register_object_path(connection, path,
  966. &generic_table, data)) {
  967. dbus_connection_unref(data->conn);
  968. g_free(data->path);
  969. g_free(data->introspect);
  970. g_free(data);
  971. return NULL;
  972. }
  973. invalidate_parent_data(connection, path);
  974. add_interface(data, DBUS_INTERFACE_INTROSPECTABLE, introspect_methods,
  975. NULL, NULL, data, NULL);
  976. return data;
  977. }
  978. static void object_path_unref(DBusConnection *connection, const char *path)
  979. {
  980. struct generic_data *data = NULL;
  981. if (dbus_connection_get_object_path_data(connection, path,
  982. (void *) &data) == FALSE)
  983. return;
  984. if (data == NULL)
  985. return;
  986. data->refcount--;
  987. if (data->refcount > 0)
  988. return;
  989. remove_interface(data, DBUS_INTERFACE_INTROSPECTABLE);
  990. remove_interface(data, DBUS_INTERFACE_PROPERTIES);
  991. invalidate_parent_data(data->conn, data->path);
  992. dbus_connection_unregister_object_path(data->conn, data->path);
  993. }
  994. static gboolean check_signal(DBusConnection *conn, const char *path,
  995. const char *interface, const char *name,
  996. const GDBusArgInfo **args)
  997. {
  998. struct generic_data *data = NULL;
  999. struct interface_data *iface;
  1000. const GDBusSignalTable *signal;
  1001. *args = NULL;
  1002. if (!dbus_connection_get_object_path_data(conn, path,
  1003. (void *) &data) || data == NULL) {
  1004. error("dbus_connection_emit_signal: path %s isn't registered",
  1005. path);
  1006. return FALSE;
  1007. }
  1008. iface = find_interface(data->interfaces, interface);
  1009. if (iface == NULL) {
  1010. error("dbus_connection_emit_signal: %s does not implement %s",
  1011. path, interface);
  1012. return FALSE;
  1013. }
  1014. for (signal = iface->signals; signal && signal->name; signal++) {
  1015. if (strcmp(signal->name, name) != 0)
  1016. continue;
  1017. if (signal->flags & G_DBUS_SIGNAL_FLAG_EXPERIMENTAL) {
  1018. const char *env = g_getenv("GDBUS_EXPERIMENTAL");
  1019. if (g_strcmp0(env, "1") != 0)
  1020. break;
  1021. }
  1022. *args = signal->args;
  1023. return TRUE;
  1024. }
  1025. error("No signal named %s on interface %s", name, interface);
  1026. return FALSE;
  1027. }
  1028. gboolean g_dbus_register_interface(DBusConnection *connection,
  1029. const char *path, const char *name,
  1030. const GDBusMethodTable *methods,
  1031. const GDBusSignalTable *signals,
  1032. const GDBusPropertyTable *properties,
  1033. void *user_data,
  1034. GDBusDestroyFunction destroy)
  1035. {
  1036. struct generic_data *data;
  1037. if (!dbus_validate_path(path, NULL)) {
  1038. error("Invalid object path: %s", path);
  1039. return FALSE;
  1040. }
  1041. if (!dbus_validate_interface(name, NULL)) {
  1042. error("Invalid interface: %s", name);
  1043. return FALSE;
  1044. }
  1045. data = object_path_ref(connection, path);
  1046. if (data == NULL)
  1047. return FALSE;
  1048. if (find_interface(data->interfaces, name)) {
  1049. object_path_unref(connection, path);
  1050. return FALSE;
  1051. }
  1052. if (!add_interface(data, name, methods, signals, properties, user_data,
  1053. destroy)) {
  1054. object_path_unref(connection, path);
  1055. return FALSE;
  1056. }
  1057. if (properties != NULL && !find_interface(data->interfaces,
  1058. DBUS_INTERFACE_PROPERTIES))
  1059. add_interface(data, DBUS_INTERFACE_PROPERTIES,
  1060. properties_methods, properties_signals, NULL,
  1061. data, NULL);
  1062. g_free(data->introspect);
  1063. data->introspect = NULL;
  1064. return TRUE;
  1065. }
  1066. gboolean g_dbus_unregister_interface(DBusConnection *connection,
  1067. const char *path, const char *name)
  1068. {
  1069. struct generic_data *data = NULL;
  1070. if (path == NULL)
  1071. return FALSE;
  1072. if (dbus_connection_get_object_path_data(connection, path,
  1073. (void *) &data) == FALSE)
  1074. return FALSE;
  1075. if (data == NULL)
  1076. return FALSE;
  1077. if (remove_interface(data, name) == FALSE)
  1078. return FALSE;
  1079. g_free(data->introspect);
  1080. data->introspect = NULL;
  1081. object_path_unref(connection, data->path);
  1082. return TRUE;
  1083. }
  1084. gboolean g_dbus_register_security(const GDBusSecurityTable *security)
  1085. {
  1086. if (security_table != NULL)
  1087. return FALSE;
  1088. security_table = security;
  1089. return TRUE;
  1090. }
  1091. gboolean g_dbus_unregister_security(const GDBusSecurityTable *security)
  1092. {
  1093. security_table = NULL;
  1094. return TRUE;
  1095. }
  1096. DBusMessage *g_dbus_create_error_valist(DBusMessage *message, const char *name,
  1097. const char *format, va_list args)
  1098. {
  1099. char str[1024];
  1100. /* Check if the message can be replied */
  1101. if (dbus_message_get_no_reply(message))
  1102. return NULL;
  1103. if (format)
  1104. vsnprintf(str, sizeof(str), format, args);
  1105. else
  1106. str[0] = '\0';
  1107. return dbus_message_new_error(message, name, str);
  1108. }
  1109. DBusMessage *g_dbus_create_error(DBusMessage *message, const char *name,
  1110. const char *format, ...)
  1111. {
  1112. va_list args;
  1113. DBusMessage *reply;
  1114. va_start(args, format);
  1115. reply = g_dbus_create_error_valist(message, name, format, args);
  1116. va_end(args);
  1117. return reply;
  1118. }
  1119. DBusMessage *g_dbus_create_reply_valist(DBusMessage *message,
  1120. int type, va_list args)
  1121. {
  1122. DBusMessage *reply;
  1123. /* Check if the message can be replied */
  1124. if (dbus_message_get_no_reply(message))
  1125. return NULL;
  1126. reply = dbus_message_new_method_return(message);
  1127. if (reply == NULL)
  1128. return NULL;
  1129. if (dbus_message_append_args_valist(reply, type, args) == FALSE) {
  1130. dbus_message_unref(reply);
  1131. return NULL;
  1132. }
  1133. return reply;
  1134. }
  1135. DBusMessage *g_dbus_create_reply(DBusMessage *message, int type, ...)
  1136. {
  1137. va_list args;
  1138. DBusMessage *reply;
  1139. va_start(args, type);
  1140. reply = g_dbus_create_reply_valist(message, type, args);
  1141. va_end(args);
  1142. return reply;
  1143. }
  1144. static void g_dbus_flush(DBusConnection *connection)
  1145. {
  1146. GSList *l;
  1147. for (l = pending; l;) {
  1148. struct generic_data *data = l->data;
  1149. l = l->next;
  1150. if (data->conn != connection)
  1151. continue;
  1152. process_changes(data);
  1153. }
  1154. }
  1155. gboolean g_dbus_send_message(DBusConnection *connection, DBusMessage *message)
  1156. {
  1157. dbus_bool_t result = FALSE;
  1158. if (!message)
  1159. return FALSE;
  1160. if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL)
  1161. dbus_message_set_no_reply(message, TRUE);
  1162. else if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL) {
  1163. const char *path = dbus_message_get_path(message);
  1164. const char *interface = dbus_message_get_interface(message);
  1165. const char *name = dbus_message_get_member(message);
  1166. const GDBusArgInfo *args;
  1167. if (!check_signal(connection, path, interface, name, &args))
  1168. goto out;
  1169. }
  1170. /* Flush pending signal to guarantee message order */
  1171. g_dbus_flush(connection);
  1172. result = dbus_connection_send(connection, message, NULL);
  1173. out:
  1174. dbus_message_unref(message);
  1175. return result;
  1176. }
  1177. gboolean g_dbus_send_message_with_reply(DBusConnection *connection,
  1178. DBusMessage *message,
  1179. DBusPendingCall **call, int timeout)
  1180. {
  1181. dbus_bool_t ret;
  1182. /* Flush pending signal to guarantee message order */
  1183. g_dbus_flush(connection);
  1184. ret = dbus_connection_send_with_reply(connection, message, call,
  1185. timeout);
  1186. if (ret == TRUE && call != NULL && *call == NULL) {
  1187. error("Unable to send message (passing fd blocked?)");
  1188. return FALSE;
  1189. }
  1190. return ret;
  1191. }
  1192. gboolean g_dbus_send_error_valist(DBusConnection *connection,
  1193. DBusMessage *message, const char *name,
  1194. const char *format, va_list args)
  1195. {
  1196. DBusMessage *error;
  1197. error = g_dbus_create_error_valist(message, name, format, args);
  1198. if (error == NULL)
  1199. return FALSE;
  1200. return g_dbus_send_message(connection, error);
  1201. }
  1202. gboolean g_dbus_send_error(DBusConnection *connection, DBusMessage *message,
  1203. const char *name, const char *format, ...)
  1204. {
  1205. va_list args;
  1206. gboolean result;
  1207. va_start(args, format);
  1208. result = g_dbus_send_error_valist(connection, message, name,
  1209. format, args);
  1210. va_end(args);
  1211. return result;
  1212. }
  1213. gboolean g_dbus_send_reply_valist(DBusConnection *connection,
  1214. DBusMessage *message, int type, va_list args)
  1215. {
  1216. DBusMessage *reply;
  1217. reply = g_dbus_create_reply_valist(message, type, args);
  1218. if (!reply)
  1219. return FALSE;
  1220. return g_dbus_send_message(connection, reply);
  1221. }
  1222. gboolean g_dbus_send_reply(DBusConnection *connection,
  1223. DBusMessage *message, int type, ...)
  1224. {
  1225. va_list args;
  1226. gboolean result;
  1227. va_start(args, type);
  1228. result = g_dbus_send_reply_valist(connection, message, type, args);
  1229. va_end(args);
  1230. return result;
  1231. }
  1232. gboolean g_dbus_emit_signal(DBusConnection *connection,
  1233. const char *path, const char *interface,
  1234. const char *name, int type, ...)
  1235. {
  1236. va_list args;
  1237. gboolean result;
  1238. va_start(args, type);
  1239. result = g_dbus_emit_signal_valist(connection, path, interface,
  1240. name, type, args);
  1241. va_end(args);
  1242. return result;
  1243. }
  1244. gboolean g_dbus_emit_signal_valist(DBusConnection *connection,
  1245. const char *path, const char *interface,
  1246. const char *name, int type, va_list args)
  1247. {
  1248. DBusMessage *signal;
  1249. dbus_bool_t ret;
  1250. const GDBusArgInfo *args_info;
  1251. if (!check_signal(connection, path, interface, name, &args_info))
  1252. return FALSE;
  1253. signal = dbus_message_new_signal(path, interface, name);
  1254. if (signal == NULL) {
  1255. error("Unable to allocate new %s.%s signal", interface, name);
  1256. return FALSE;
  1257. }
  1258. ret = dbus_message_append_args_valist(signal, type, args);
  1259. if (!ret)
  1260. goto fail;
  1261. if (g_dbus_args_have_signature(args_info, signal) == FALSE) {
  1262. error("%s.%s: got unexpected signature '%s'", interface, name,
  1263. dbus_message_get_signature(signal));
  1264. ret = FALSE;
  1265. goto fail;
  1266. }
  1267. return g_dbus_send_message(connection, signal);
  1268. fail:
  1269. dbus_message_unref(signal);
  1270. return ret;
  1271. }
  1272. static void process_properties_from_interface(struct generic_data *data,
  1273. struct interface_data *iface)
  1274. {
  1275. GSList *l;
  1276. DBusMessage *signal;
  1277. DBusMessageIter iter, dict, array;
  1278. GSList *invalidated;
  1279. if (iface->pending_prop == NULL)
  1280. return;
  1281. signal = dbus_message_new_signal(data->path,
  1282. DBUS_INTERFACE_PROPERTIES, "PropertiesChanged");
  1283. if (signal == NULL) {
  1284. error("Unable to allocate new " DBUS_INTERFACE_PROPERTIES
  1285. ".PropertiesChanged signal");
  1286. return;
  1287. }
  1288. iface->pending_prop = g_slist_reverse(iface->pending_prop);
  1289. dbus_message_iter_init_append(signal, &iter);
  1290. dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &iface->name);
  1291. dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
  1292. DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
  1293. DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
  1294. DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
  1295. invalidated = NULL;
  1296. for (l = iface->pending_prop; l != NULL; l = l->next) {
  1297. GDBusPropertyTable *p = l->data;
  1298. if (p->get == NULL)
  1299. continue;
  1300. if (p->exists != NULL && !p->exists(p, iface->user_data)) {
  1301. invalidated = g_slist_prepend(invalidated, p);
  1302. continue;
  1303. }
  1304. append_property(iface, p, &dict);
  1305. }
  1306. dbus_message_iter_close_container(&iter, &dict);
  1307. dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
  1308. DBUS_TYPE_STRING_AS_STRING, &array);
  1309. for (l = invalidated; l != NULL; l = g_slist_next(l)) {
  1310. GDBusPropertyTable *p = l->data;
  1311. dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING,
  1312. &p->name);
  1313. }
  1314. g_slist_free(invalidated);
  1315. dbus_message_iter_close_container(&iter, &array);
  1316. g_slist_free(iface->pending_prop);
  1317. iface->pending_prop = NULL;
  1318. /* Use dbus_connection_send to avoid recursive calls to g_dbus_flush */
  1319. dbus_connection_send(data->conn, signal, NULL);
  1320. dbus_message_unref(signal);
  1321. }
  1322. static void process_property_changes(struct generic_data *data)
  1323. {
  1324. GSList *l;
  1325. data->pending_prop = FALSE;
  1326. for (l = data->interfaces; l != NULL; l = l->next) {
  1327. struct interface_data *iface = l->data;
  1328. process_properties_from_interface(data, iface);
  1329. }
  1330. }
  1331. void g_dbus_emit_property_changed_full(DBusConnection *connection,
  1332. const char *path, const char *interface,
  1333. const char *name,
  1334. GDbusPropertyChangedFlags flags)
  1335. {
  1336. const GDBusPropertyTable *property;
  1337. struct generic_data *data;
  1338. struct interface_data *iface;
  1339. if (path == NULL)
  1340. return;
  1341. if (!dbus_connection_get_object_path_data(connection, path,
  1342. (void **) &data) || data == NULL)
  1343. return;
  1344. iface = find_interface(data->interfaces, interface);
  1345. if (iface == NULL)
  1346. return;
  1347. /*
  1348. * If ObjectManager is attached, don't emit property changed if
  1349. * interface is not yet published
  1350. */
  1351. if (root && g_slist_find(data->added, iface))
  1352. return;
  1353. property = find_property(iface->properties, name);
  1354. if (property == NULL) {
  1355. error("Could not find property %s in %p", name,
  1356. iface->properties);
  1357. return;
  1358. }
  1359. if (g_slist_find(iface->pending_prop, (void *) property) != NULL)
  1360. return;
  1361. data->pending_prop = TRUE;
  1362. iface->pending_prop = g_slist_prepend(iface->pending_prop,
  1363. (void *) property);
  1364. if (flags & G_DBUS_PROPERTY_CHANGED_FLAG_FLUSH)
  1365. process_property_changes(data);
  1366. else
  1367. add_pending(data);
  1368. }
  1369. void g_dbus_emit_property_changed(DBusConnection *connection, const char *path,
  1370. const char *interface, const char *name)
  1371. {
  1372. g_dbus_emit_property_changed_full(connection, path, interface, name, 0);
  1373. }
  1374. gboolean g_dbus_get_properties(DBusConnection *connection, const char *path,
  1375. const char *interface, DBusMessageIter *iter)
  1376. {
  1377. struct generic_data *data;
  1378. struct interface_data *iface;
  1379. if (path == NULL)
  1380. return FALSE;
  1381. if (!dbus_connection_get_object_path_data(connection, path,
  1382. (void **) &data) || data == NULL)
  1383. return FALSE;
  1384. iface = find_interface(data->interfaces, interface);
  1385. if (iface == NULL)
  1386. return FALSE;
  1387. append_properties(iface, iter);
  1388. return TRUE;
  1389. }
  1390. gboolean g_dbus_attach_object_manager(DBusConnection *connection)
  1391. {
  1392. struct generic_data *data;
  1393. data = object_path_ref(connection, "/");
  1394. if (data == NULL)
  1395. return FALSE;
  1396. add_interface(data, DBUS_INTERFACE_OBJECT_MANAGER,
  1397. manager_methods, manager_signals,
  1398. NULL, data, NULL);
  1399. root = data;
  1400. return TRUE;
  1401. }
  1402. gboolean g_dbus_detach_object_manager(DBusConnection *connection)
  1403. {
  1404. if (!g_dbus_unregister_interface(connection, "/",
  1405. DBUS_INTERFACE_OBJECT_MANAGER))
  1406. return FALSE;
  1407. root = NULL;
  1408. return TRUE;
  1409. }
  1410. void g_dbus_set_flags(int flags)
  1411. {
  1412. global_flags = flags;
  1413. }
  1414. int g_dbus_get_flags(void)
  1415. {
  1416. return global_flags;
  1417. }