ladishd: Basic recent projects functionality
[ladish.git] / dbus / helpers.c
blob50dca879d5912aa356dd31a84b5e5147d57c0589
1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
2 /*
3 * LADI Session Handler (ladish)
5 * Copyright (C) 2008, 2009, 2010 Nedko Arnaudov <nedko@arnaudov.name>
6 * Copyright (C) 2008 Juuso Alasuutari <juuso.alasuutari@gmail.com>
8 **************************************************************************
9 * This file contains code of the D-Bus helpers
10 **************************************************************************
12 * Licensed under the Academic Free License version 2.1
14 * LADI Session Handler is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * LADI Session Handler is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with LADI Session Handler. If not, see <http://www.gnu.org/licenses/>
26 * or write to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
30 #include <stdbool.h>
31 #include <dbus/dbus.h>
32 #include <string.h>
33 #include <stdlib.h>
35 #include "helpers.h"
36 #include "method.h"
37 #include "../log.h"
38 #include "../assert.h"
39 #include "../common/klist.h"
41 DBusConnection * g_dbus_connection;
42 DBusError g_dbus_error;
44 struct dbus_signal_hook_descriptor
46 struct list_head siblings;
47 char * object;
48 char * interface;
49 void * hook_context;
50 const struct dbus_signal_hook * signal_hooks;
53 struct dbus_service_descriptor
55 struct list_head siblings;
56 char * service_name;
57 void (* lifetime_hook_function)(bool appeared);
58 struct list_head hooks;
61 LIST_HEAD(g_dbus_services);
63 bool dbus_iter_get_dict_entry(DBusMessageIter * iter_ptr, const char * key, void * value, int * type, int * size)
65 DBusMessageIter dict_iter;
66 DBusMessageIter entry_iter;
67 DBusMessageIter variant_iter;
68 const char * current_key;
69 DBusMessageIter array_iter;
70 int n;
71 int detype;
73 dbus_message_iter_recurse(iter_ptr, &dict_iter);
75 loop:
76 detype = dbus_message_iter_get_arg_type(&dict_iter);
78 if (detype == DBUS_TYPE_INVALID)
80 return false;
83 if (detype != DBUS_TYPE_DICT_ENTRY)
85 log_error("Iterator does not point to a dict entry container");
86 return false;
89 dbus_message_iter_recurse(&dict_iter, &entry_iter);
91 if (dbus_message_iter_get_arg_type(&entry_iter) != DBUS_TYPE_STRING)
93 log_error("Cannot find key in dict entry container");
94 return false;
97 dbus_message_iter_get_basic(&entry_iter, &current_key);
98 if (strcmp(current_key, key) != 0)
100 dbus_message_iter_next(&dict_iter);
101 goto loop;
104 if (!dbus_message_iter_next(&entry_iter) || dbus_message_iter_get_arg_type(&entry_iter) != DBUS_TYPE_VARIANT)
106 log_error("Cannot find variant container in dict entry");
107 return false;
110 dbus_message_iter_recurse(&entry_iter, &variant_iter);
112 *type = dbus_message_iter_get_arg_type(&variant_iter);
113 if (*type == DBUS_TYPE_INVALID)
115 log_error("Cannot find value in variant container");
116 return false;
119 if (*type == DBUS_TYPE_ARRAY)
121 if (dbus_message_iter_get_element_type(&variant_iter) != DBUS_TYPE_BYTE)
123 log_error("Dict entry value is a non-byte array");
124 return false;
126 *type = '-';
128 dbus_message_iter_recurse(&variant_iter, &array_iter);
129 dbus_message_iter_get_fixed_array(&array_iter, value, &n);
131 if (size != NULL)
133 *size = n;
136 else
138 dbus_message_iter_get_basic(&variant_iter, value);
141 return true;
144 bool dbus_iter_get_dict_entry_string(DBusMessageIter * iter_ptr, const char * key, const char ** value)
146 int type;
148 if (!dbus_iter_get_dict_entry(iter_ptr, key, value, &type, NULL))
150 return false;
153 if (type != DBUS_TYPE_STRING)
155 log_error("value of the dict entry '%s' is not a string", key);
156 return false;
159 return true;
163 * Append a variant type to a D-Bus message.
164 * Return false if something fails, true otherwise.
166 bool dbus_iter_append_variant(DBusMessageIter * iter, int type, const void * arg)
168 DBusMessageIter sub_iter;
169 char s[2];
171 s[0] = (char)type;
172 s[1] = '\0';
174 /* Open a variant container. */
175 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, (const char *)s, &sub_iter))
176 return false;
178 /* Append the supplied value. */
179 if (!dbus_message_iter_append_basic(&sub_iter, type, arg))
181 dbus_message_iter_close_container(iter, &sub_iter);
182 return false;
185 /* Close the container. */
186 if (!dbus_message_iter_close_container(iter, &sub_iter))
187 return false;
189 return true;
192 static __inline__ bool dbus_iter_append_variant_raw(DBusMessageIter * iter, const void * buf, int len)
194 DBusMessageIter variant_iter, array_iter;
196 /* Open a variant container. */
197 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
198 "ay", &variant_iter))
199 return false;
201 /* Open an array container. */
202 if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
203 "y", &array_iter))
204 goto fail;
206 /* Append the supplied data. */
207 if (!dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE, buf, len)) {
208 dbus_message_iter_close_container(&variant_iter, &array_iter);
209 goto fail;
212 /* Close the containers. */
213 if (!dbus_message_iter_close_container(&variant_iter, &array_iter))
214 goto fail;
215 else if (!dbus_message_iter_close_container(iter, &variant_iter))
216 return false;
218 return true;
220 fail:
221 dbus_message_iter_close_container(iter, &variant_iter);
222 return false;
225 bool dbus_iter_append_dict_entry(DBusMessageIter * iter, int type, const char * key, const void * value, int length)
227 DBusMessageIter dict_iter;
229 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_iter))
230 return false;
232 if (!dbus_message_iter_append_basic(&dict_iter, DBUS_TYPE_STRING, &key))
233 goto fail;
235 if (type == '-')
237 if (!dbus_iter_append_variant_raw(&dict_iter, value, length))
238 goto fail;
240 else if (!dbus_iter_append_variant(&dict_iter, type, value))
242 goto fail;
245 if (!dbus_message_iter_close_container(iter, &dict_iter))
246 return false;
248 return true;
250 fail:
251 dbus_message_iter_close_container(iter, &dict_iter);
252 return false;
255 bool dbus_maybe_add_dict_entry_string(DBusMessageIter *dict_iter_ptr, const char * key, const char * value)
257 DBusMessageIter dict_entry_iter;
259 if (value == NULL)
261 return true;
264 if (!dbus_message_iter_open_container(dict_iter_ptr, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter))
266 return false;
269 if (!dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, (const void *) &key))
271 dbus_message_iter_close_container(dict_iter_ptr, &dict_entry_iter);
272 return false;
275 dbus_iter_append_variant(&dict_entry_iter, DBUS_TYPE_STRING, &value);
277 if (!dbus_message_iter_close_container(dict_iter_ptr, &dict_entry_iter))
279 return false;
282 return true;
285 bool dbus_add_dict_entry_uint32(DBusMessageIter * dict_iter_ptr, const char * key, dbus_uint32_t value)
287 DBusMessageIter dict_entry_iter;
289 if (!dbus_message_iter_open_container(dict_iter_ptr, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter))
291 return false;
294 if (!dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, (const void *) &key))
296 dbus_message_iter_close_container(dict_iter_ptr, &dict_entry_iter);
297 return false;
300 dbus_iter_append_variant(&dict_entry_iter, DBUS_TYPE_UINT32, &value);
302 if (!dbus_message_iter_close_container(dict_iter_ptr, &dict_entry_iter))
304 return false;
307 return true;
310 bool dbus_add_dict_entry_bool(DBusMessageIter * dict_iter_ptr, const char * key, dbus_bool_t value)
312 DBusMessageIter dict_entry_iter;
314 if (!dbus_message_iter_open_container(dict_iter_ptr, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter))
316 return false;
319 if (!dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, (const void *) &key))
321 dbus_message_iter_close_container(dict_iter_ptr, &dict_entry_iter);
322 return false;
325 dbus_iter_append_variant(&dict_entry_iter, DBUS_TYPE_BOOLEAN, &value);
327 if (!dbus_message_iter_close_container(dict_iter_ptr, &dict_entry_iter))
329 return false;
332 return true;
335 bool
336 dbus_call(
337 const char * service,
338 const char * object,
339 const char * iface,
340 const char * method,
341 const char * input_signature,
342 ...)
344 DBusMessageIter iter;
345 DBusMessage * request_ptr;
346 DBusMessage * reply_ptr;
347 const char * output_signature;
348 const char * reply_signature;
349 va_list ap;
350 bool ret;
351 void * parameter_ptr;
352 int type;
353 DBusSignatureIter sig_iter;
355 //log_info("dbus_call('%s', '%s', '%s', '%s')", service, object, iface, method);
357 ret = false;
358 va_start(ap, input_signature);
360 if (input_signature != NULL)
362 if (!dbus_signature_validate(input_signature, NULL))
364 log_error("input signature '%s' is invalid", input_signature);
365 goto fail;
368 dbus_signature_iter_init(&sig_iter, input_signature);
370 request_ptr = dbus_message_new_method_call(service, object, iface, method);
371 if (request_ptr == NULL)
373 log_error("dbus_message_new_method_call() failed.");
374 goto fail;
377 dbus_message_iter_init_append(request_ptr, &iter);
379 while (*input_signature != '\0')
381 type = dbus_signature_iter_get_current_type(&sig_iter);
382 if (!dbus_type_is_basic(type))
384 log_error("non-basic input parameter '%c' (%d)", *input_signature, type);
385 goto fail;
388 parameter_ptr = va_arg(ap, void *);
390 if (!dbus_message_iter_append_basic(&iter, type, parameter_ptr))
392 log_error("dbus_message_iter_append_basic() failed.");
393 goto fail;
396 dbus_signature_iter_next(&sig_iter);
397 input_signature++;
400 else
402 request_ptr = va_arg(ap, DBusMessage *);
405 output_signature = va_arg(ap, const char *);
407 reply_ptr = dbus_connection_send_with_reply_and_block(
408 g_dbus_connection,
409 request_ptr,
410 DBUS_CALL_DEFAULT_TIMEOUT,
411 &g_dbus_error);
413 if (input_signature != NULL)
415 dbus_message_unref(request_ptr);
418 if (reply_ptr == NULL)
420 //log_error("calling method '%s' failed, error is '%s'", method, g_dbus_error.message);
421 dbus_error_free(&g_dbus_error);
422 goto fail;
425 if (output_signature != NULL)
427 reply_signature = dbus_message_get_signature(reply_ptr);
429 if (strcmp(reply_signature, output_signature) != 0)
431 log_error("reply signature is '%s' but expected signature is '%s'", reply_signature, output_signature);
434 dbus_message_iter_init(reply_ptr, &iter);
436 while (*output_signature++ != '\0')
438 ASSERT(dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INVALID); /* we've checked the signature, this should not happen */
439 parameter_ptr = va_arg(ap, void *);
440 dbus_message_iter_get_basic(&iter, parameter_ptr);
441 dbus_message_iter_next(&iter);
444 ASSERT(dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_INVALID); /* we've checked the signature, this should not happen */
445 dbus_message_unref(reply_ptr);
447 else
449 parameter_ptr = va_arg(ap, DBusMessage **);
450 *(DBusMessage **)parameter_ptr = reply_ptr;
453 ret = true;
455 fail:
456 va_end(ap);
457 return ret;
460 static
461 const char *
462 compose_signal_match(
463 const char * service,
464 const char * object,
465 const char * iface,
466 const char * signal)
468 static char rule[1024];
469 snprintf(rule, sizeof(rule), "type='signal',sender='%s',path='%s',interface='%s',member='%s'", service, object, iface, signal);
470 return rule;
473 static const char * compose_name_owner_match(const char * service)
475 static char rule[1024];
476 snprintf(rule, sizeof(rule), "type='signal',interface='"DBUS_INTERFACE_DBUS"',member=NameOwnerChanged,arg0='%s'", service);
477 return rule;
480 bool
481 dbus_register_object_signal_handler(
482 DBusConnection * connection,
483 const char * service,
484 const char * object,
485 const char * iface,
486 const char * const * signals,
487 DBusHandleMessageFunction handler,
488 void * handler_data)
490 const char * const * signal;
492 for (signal = signals; *signal != NULL; signal++)
494 dbus_bus_add_match(connection, compose_signal_match(service, object, iface, *signal), &g_dbus_error);
495 if (dbus_error_is_set(&g_dbus_error))
497 log_error("Failed to add D-Bus match rule: %s", g_dbus_error.message);
498 dbus_error_free(&g_dbus_error);
499 return false;
503 dbus_connection_add_filter(g_dbus_connection, handler, handler_data, NULL);
505 return true;
508 bool
509 dbus_unregister_object_signal_handler(
510 DBusConnection * connection,
511 const char * service,
512 const char * object,
513 const char * iface,
514 const char * const * signals,
515 DBusHandleMessageFunction handler,
516 void * handler_data)
518 const char * const * signal;
520 for (signal = signals; *signal != NULL; signal++)
522 dbus_bus_remove_match(connection, compose_signal_match(service, object, iface, *signal), &g_dbus_error);
523 if (dbus_error_is_set(&g_dbus_error))
525 log_error("Failed to remove D-Bus match rule: %s", g_dbus_error.message);
526 dbus_error_free(&g_dbus_error);
527 return false;
531 dbus_connection_remove_filter(g_dbus_connection, handler, handler_data);
533 return true;
536 static
537 struct dbus_signal_hook_descriptor *
538 find_signal_hook_descriptor(
539 struct dbus_service_descriptor * service_ptr,
540 const char * object,
541 const char * interface)
543 struct list_head * node_ptr;
544 struct dbus_signal_hook_descriptor * hook_ptr;
546 list_for_each(node_ptr, &service_ptr->hooks)
548 hook_ptr = list_entry(node_ptr, struct dbus_signal_hook_descriptor, siblings);
549 if (strcmp(hook_ptr->object, object) == 0 &&
550 strcmp(hook_ptr->interface, interface) == 0)
552 return hook_ptr;
556 return NULL;
559 #define service_ptr ((struct dbus_service_descriptor *)data)
561 static
562 DBusHandlerResult
563 dbus_signal_handler(
564 DBusConnection * connection_ptr,
565 DBusMessage * message_ptr,
566 void * data)
568 const char * object_path;
569 const char * interface;
570 const char * signal_name;
571 const char * object_name;
572 const char * old_owner;
573 const char * new_owner;
574 struct dbus_signal_hook_descriptor * hook_ptr;
575 const struct dbus_signal_hook * signal_ptr;
577 /* Non-signal messages are ignored */
578 if (dbus_message_get_type(message_ptr) != DBUS_MESSAGE_TYPE_SIGNAL)
580 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
583 interface = dbus_message_get_interface(message_ptr);
584 if (interface == NULL)
586 /* Signals with no interface are ignored */
587 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
590 object_path = dbus_message_get_path(message_ptr);
592 signal_name = dbus_message_get_member(message_ptr);
593 if (signal_name == NULL)
595 log_error("Received signal with NULL member");
596 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
599 log_debug("'%s' sent signal '%s'::'%s'", object_path, interface, signal_name);
601 /* Handle session bus signals to track service alive state */
602 if (strcmp(interface, DBUS_INTERFACE_DBUS) == 0)
604 if (strcmp(signal_name, "NameOwnerChanged") != 0)
606 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
609 if (service_ptr->lifetime_hook_function == NULL)
611 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
614 //log_info("NameOwnerChanged signal received");
616 dbus_error_init(&g_dbus_error);
617 if (!dbus_message_get_args(
618 message_ptr,
619 &g_dbus_error,
620 DBUS_TYPE_STRING, &object_name,
621 DBUS_TYPE_STRING, &old_owner,
622 DBUS_TYPE_STRING, &new_owner,
623 DBUS_TYPE_INVALID))
625 log_error("Cannot get message arguments: %s", g_dbus_error.message);
626 dbus_error_free(&g_dbus_error);
627 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
630 if (strcmp(object_name, service_ptr->service_name) != 0)
632 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
635 if (old_owner[0] == '\0')
637 service_ptr->lifetime_hook_function(true);
639 else if (new_owner[0] == '\0')
641 service_ptr->lifetime_hook_function(false);
644 return DBUS_HANDLER_RESULT_HANDLED;
647 /* Handle object interface signals */
648 if (object_path != NULL)
650 hook_ptr = find_signal_hook_descriptor(service_ptr, object_path, interface);
651 if (hook_ptr != NULL)
653 for (signal_ptr = hook_ptr->signal_hooks; signal_ptr->signal_name != NULL; signal_ptr++)
655 if (strcmp(signal_name, signal_ptr->signal_name) == 0)
657 signal_ptr->hook_function(hook_ptr->hook_context, message_ptr);
658 return DBUS_HANDLER_RESULT_HANDLED;
664 /* Let everything else pass through */
665 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
668 #undef service_ptr
670 static struct dbus_service_descriptor * find_service_descriptor(const char * service_name)
672 struct list_head * node_ptr;
673 struct dbus_service_descriptor * descr_ptr;
675 list_for_each(node_ptr, &g_dbus_services)
677 descr_ptr = list_entry(node_ptr, struct dbus_service_descriptor, siblings);
678 if (strcmp(descr_ptr->service_name, service_name) == 0)
680 return descr_ptr;
684 return NULL;
687 static struct dbus_service_descriptor * find_or_create_service_descriptor(const char * service_name)
689 struct dbus_service_descriptor * descr_ptr;
691 descr_ptr = find_service_descriptor(service_name);
692 if (descr_ptr != NULL)
694 return descr_ptr;
697 descr_ptr = malloc(sizeof(struct dbus_service_descriptor));
698 if (descr_ptr == NULL)
700 log_error("malloc() failed to allocate struct dbus_service_descriptor");
701 return NULL;
704 descr_ptr->service_name = strdup(service_name);
705 if (descr_ptr->service_name == NULL)
707 log_error("strdup() failed for service name '%s'", service_name);
708 free(descr_ptr);
709 return NULL;
712 descr_ptr->lifetime_hook_function = NULL;
713 INIT_LIST_HEAD(&descr_ptr->hooks);
715 list_add_tail(&descr_ptr->siblings, &g_dbus_services);
717 dbus_connection_add_filter(g_dbus_connection, dbus_signal_handler, descr_ptr, NULL);
719 return descr_ptr;
722 static void free_service_descriptor_if_empty(struct dbus_service_descriptor * service_ptr)
724 if (service_ptr->lifetime_hook_function != NULL)
726 return;
729 if (!list_empty(&service_ptr->hooks))
731 return;
734 dbus_connection_remove_filter(g_dbus_connection, dbus_signal_handler, service_ptr);
736 list_del(&service_ptr->siblings);
737 free(service_ptr->service_name);
738 free(service_ptr);
741 bool
742 dbus_register_object_signal_hooks(
743 DBusConnection * connection,
744 const char * service_name,
745 const char * object,
746 const char * iface,
747 void * hook_context,
748 const struct dbus_signal_hook * signal_hooks)
750 struct dbus_service_descriptor * service_ptr;
751 struct dbus_signal_hook_descriptor * hook_ptr;
752 const struct dbus_signal_hook * signal_ptr;
754 if (connection != g_dbus_connection)
756 log_error("multiple connections are not implemented yet");
757 ASSERT_NO_PASS;
758 goto fail;
761 service_ptr = find_or_create_service_descriptor(service_name);
762 if (service_ptr == NULL)
764 log_error("find_or_create_service_descriptor() failed.");
765 goto fail;
768 hook_ptr = find_signal_hook_descriptor(service_ptr, object, iface);
769 if (hook_ptr != NULL)
771 log_error("refusing to register two signal monitors for '%s':'%s':'%s'", service_name, object, iface);
772 ASSERT_NO_PASS;
773 goto maybe_free_service;
776 hook_ptr = malloc(sizeof(struct dbus_signal_hook_descriptor));
777 if (hook_ptr == NULL)
779 log_error("malloc() failed to allocate struct dbus_signal_hook_descriptor");
780 goto maybe_free_service;
783 hook_ptr->object = strdup(object);
784 if (hook_ptr->object == NULL)
786 log_error("strdup() failed for object name");
787 goto free_hook;
790 hook_ptr->interface = strdup(iface);
791 if (hook_ptr->interface == NULL)
793 log_error("strdup() failed for interface name");
794 goto free_object_name;
797 hook_ptr->hook_context = hook_context;
798 hook_ptr->signal_hooks = signal_hooks;
800 list_add_tail(&hook_ptr->siblings, &service_ptr->hooks);
802 for (signal_ptr = signal_hooks; signal_ptr->signal_name != NULL; signal_ptr++)
804 dbus_bus_add_match(connection, compose_signal_match(service_name, object, iface, signal_ptr->signal_name), &g_dbus_error);
805 if (dbus_error_is_set(&g_dbus_error))
807 log_error("Failed to add D-Bus match rule: %s", g_dbus_error.message);
808 dbus_error_free(&g_dbus_error);
810 while (signal_ptr != signal_hooks)
812 ASSERT(signal_ptr > signal_hooks);
813 signal_ptr--;
815 dbus_bus_remove_match(connection, compose_signal_match(service_name, object, iface, signal_ptr->signal_name), &g_dbus_error);
816 if (dbus_error_is_set(&g_dbus_error))
818 log_error("Failed to remove D-Bus match rule: %s", g_dbus_error.message);
819 dbus_error_free(&g_dbus_error);
823 goto remove_hook;
827 return true;
829 remove_hook:
830 list_del(&hook_ptr->siblings);
831 free(hook_ptr->interface);
832 free_object_name:
833 free(hook_ptr->object);
834 free_hook:
835 free(hook_ptr);
836 maybe_free_service:
837 free_service_descriptor_if_empty(service_ptr);
838 fail:
839 return false;
842 void
843 dbus_unregister_object_signal_hooks(
844 DBusConnection * connection,
845 const char * service_name,
846 const char * object,
847 const char * iface)
849 struct dbus_service_descriptor * service_ptr;
850 struct dbus_signal_hook_descriptor * hook_ptr;
851 const struct dbus_signal_hook * signal_ptr;
853 if (connection != g_dbus_connection)
855 log_error("multiple connections are not implemented yet");
856 ASSERT_NO_PASS;
857 return;
860 service_ptr = find_service_descriptor(service_name);
861 if (service_ptr == NULL)
863 log_error("find_service_descriptor() failed.");
864 ASSERT_NO_PASS;
865 return;
868 hook_ptr = find_signal_hook_descriptor(service_ptr, object, iface);
869 if (hook_ptr == NULL)
871 log_error("cannot unregister non-existing signal monitor for '%s':'%s':'%s'", service_name, object, iface);
872 ASSERT_NO_PASS;
873 return;
876 for (signal_ptr = hook_ptr->signal_hooks; signal_ptr->signal_name != NULL; signal_ptr++)
878 dbus_bus_remove_match(connection, compose_signal_match(service_name, object, iface, signal_ptr->signal_name), &g_dbus_error);
879 if (dbus_error_is_set(&g_dbus_error))
881 if (dbus_error_is_set(&g_dbus_error))
883 log_error("Failed to remove D-Bus match rule: %s", g_dbus_error.message);
884 dbus_error_free(&g_dbus_error);
889 list_del(&hook_ptr->siblings);
891 free(hook_ptr->interface);
892 free(hook_ptr->object);
893 free(hook_ptr);
895 free_service_descriptor_if_empty(service_ptr);
898 bool
899 dbus_register_service_lifetime_hook(
900 DBusConnection * connection,
901 const char * service_name,
902 void (* hook_function)(bool appeared))
904 struct dbus_service_descriptor * service_ptr;
906 if (connection != g_dbus_connection)
908 log_error("multiple connections are not implemented yet");
909 ASSERT_NO_PASS;
910 goto fail;
913 service_ptr = find_or_create_service_descriptor(service_name);
914 if (service_ptr == NULL)
916 log_error("find_or_create_service_descriptor() failed.");
917 goto fail;
920 if (service_ptr->lifetime_hook_function != NULL)
922 log_error("cannot register two lifetime hooks for '%s'", service_name);
923 ASSERT_NO_PASS;
924 goto maybe_free_service;
927 service_ptr->lifetime_hook_function = hook_function;
929 dbus_bus_add_match(connection, compose_name_owner_match(service_name), &g_dbus_error);
930 if (dbus_error_is_set(&g_dbus_error))
932 log_error("Failed to add D-Bus match rule: %s", g_dbus_error.message);
933 dbus_error_free(&g_dbus_error);
934 goto clear_hook;
937 return true;
939 clear_hook:
940 service_ptr->lifetime_hook_function = NULL;
941 maybe_free_service:
942 free_service_descriptor_if_empty(service_ptr);
943 fail:
944 return false;
947 void
948 dbus_unregister_service_lifetime_hook(
949 DBusConnection * connection,
950 const char * service_name)
952 struct dbus_service_descriptor * service_ptr;
954 if (connection != g_dbus_connection)
956 log_error("multiple connections are not implemented yet");
957 ASSERT_NO_PASS;
958 return;
961 service_ptr = find_service_descriptor(service_name);
962 if (service_ptr == NULL)
964 log_error("find_service_descriptor() failed.");
965 return;
968 if (service_ptr->lifetime_hook_function == NULL)
970 log_error("cannot unregister non-existent lifetime hook for '%s'", service_name);
971 ASSERT_NO_PASS;
972 return;
975 service_ptr->lifetime_hook_function = NULL;
977 dbus_bus_remove_match(connection, compose_name_owner_match(service_name), &g_dbus_error);
978 if (dbus_error_is_set(&g_dbus_error))
980 log_error("Failed to remove D-Bus match rule: %s", g_dbus_error.message);
981 dbus_error_free(&g_dbus_error);
984 free_service_descriptor_if_empty(service_ptr);