efl/src/lib/eldbus/eldbus_proxy.c

902 lines
28 KiB
C
Raw Normal View History

2013-03-15 01:32:20 -07:00
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "eldbus_private.h"
#include "eldbus_private_types.h"
/* TODO: mempool of Eldbus_Proxy, Eldbus_Proxy_Context_Event_Cb and
* Eldbus_Proxy_Context_Event
*/
typedef struct _Eldbus_Proxy_Context_Event_Cb
{
EINA_INLIST;
Eldbus_Proxy_Event_Cb cb;
const void *cb_data;
Eina_Bool deleted : 1;
} Eldbus_Proxy_Context_Event_Cb;
typedef struct _Eldbus_Proxy_Context_Event
{
Eina_Inlist *list;
int walking;
Eina_List *to_delete;
} Eldbus_Proxy_Context_Event;
struct _Eldbus_Proxy
{
EINA_MAGIC;
int refcount;
Eldbus_Object *obj;
const char *interface;
Eina_Inlist *pendings;
Eina_List *handlers;
Eina_Inlist *cbs_free;
Eina_Inlist *data;
Eldbus_Proxy_Context_Event event_handlers[ELDBUS_PROXY_EVENT_LAST];
Eina_Hash *props;
Eldbus_Signal_Handler *properties_changed;
Eina_Bool monitor_enabled:1;
};
#define ELDBUS_PROXY_CHECK(proxy) \
do \
{ \
EINA_SAFETY_ON_NULL_RETURN(proxy); \
if (!EINA_MAGIC_CHECK(proxy, ELDBUS_PROXY_MAGIC)) \
{ \
EINA_MAGIC_FAIL(proxy, ELDBUS_PROXY_MAGIC); \
return; \
} \
EINA_SAFETY_ON_TRUE_RETURN(proxy->refcount <= 0); \
} \
while (0)
#define ELDBUS_PROXY_CHECK_RETVAL(proxy, retval) \
do \
{ \
EINA_SAFETY_ON_NULL_RETURN_VAL(proxy, retval); \
if (!EINA_MAGIC_CHECK(proxy, ELDBUS_PROXY_MAGIC)) \
{ \
EINA_MAGIC_FAIL(proxy, ELDBUS_PROXY_MAGIC); \
return retval; \
} \
EINA_SAFETY_ON_TRUE_RETURN_VAL(proxy->refcount <= 0, retval); \
} \
while (0)
#define ELDBUS_PROXY_CHECK_GOTO(proxy, label) \
do \
{ \
EINA_SAFETY_ON_NULL_GOTO(proxy, label); \
if (!EINA_MAGIC_CHECK(proxy, ELDBUS_PROXY_MAGIC)) \
{ \
EINA_MAGIC_FAIL(proxy, ELDBUS_PROXY_MAGIC); \
goto label; \
} \
EINA_SAFETY_ON_TRUE_GOTO(proxy->refcount <= 0, label); \
} \
while (0)
Eina_Bool
eldbus_proxy_init(void)
{
return EINA_TRUE;
}
void
eldbus_proxy_shutdown(void)
{
}
static void _eldbus_proxy_event_callback_call(Eldbus_Proxy *proxy, Eldbus_Proxy_Event_Type type, const void *event_info);
static void _eldbus_proxy_context_event_cb_del(Eldbus_Proxy_Context_Event *ce, Eldbus_Proxy_Context_Event_Cb *ctx);
static void _on_signal_handler_free(void *data, const void *dead_pointer);
static void
_eldbus_proxy_call_del(Eldbus_Proxy *proxy)
{
Eldbus_Proxy_Context_Event *ce;
_eldbus_proxy_event_callback_call(proxy, ELDBUS_PROXY_EVENT_DEL, NULL);
/* clear all del callbacks so we don't call them twice at
* _eldbus_proxy_clear()
*/
ce = proxy->event_handlers + ELDBUS_PROXY_EVENT_DEL;
while (ce->list)
{
Eldbus_Proxy_Context_Event_Cb *ctx;
ctx = EINA_INLIST_CONTAINER_GET(ce->list,
Eldbus_Proxy_Context_Event_Cb);
_eldbus_proxy_context_event_cb_del(ce, ctx);
}
}
static void
_eldbus_proxy_clear(Eldbus_Proxy *proxy)
{
Eldbus_Signal_Handler *h;
Eldbus_Pending *p;
Eina_List *iter, *iter_next;
Eina_Inlist *in_l;
DBG("proxy=%p, refcount=%d, interface=%s, obj=%p",
proxy, proxy->refcount, proxy->interface, proxy->obj);
proxy->refcount = 1;
eldbus_object_proxy_del(proxy->obj, proxy, proxy->interface);
_eldbus_proxy_call_del(proxy);
EINA_LIST_FOREACH_SAFE(proxy->handlers, iter, iter_next, h)
{
DBG("proxy=%p delete owned signal handler %p %s",
proxy, h, eldbus_signal_handler_match_get(h));
eldbus_signal_handler_del(h);
}
EINA_INLIST_FOREACH_SAFE(proxy->pendings, in_l, p)
{
DBG("proxy=%p delete owned pending call=%p dest=%s path=%s %s.%s()",
proxy, p,
eldbus_pending_destination_get(p),
eldbus_pending_path_get(p),
eldbus_pending_interface_get(p),
eldbus_pending_method_get(p));
eldbus_pending_cancel(p);
}
eldbus_cbs_free_dispatch(&(proxy->cbs_free), proxy);
if (proxy->props)
{
eina_hash_free(proxy->props);
proxy->props = NULL;
}
proxy->refcount = 0;
}
static void
_eldbus_proxy_free(Eldbus_Proxy *proxy)
{
unsigned int i;
Eldbus_Signal_Handler *h;
DBG("freeing proxy=%p", proxy);
EINA_LIST_FREE(proxy->handlers, h)
{
if (h->dangling)
eldbus_signal_handler_free_cb_del(h, _on_signal_handler_free, proxy);
else
ERR("proxy=%p alive handler=%p %s", proxy, h,
eldbus_signal_handler_match_get(h));
}
if (proxy->pendings)
CRI("Proxy %p released with live pending calls!", proxy);
for (i = 0; i < ELDBUS_PROXY_EVENT_LAST; i++)
{
Eldbus_Proxy_Context_Event *ce = proxy->event_handlers + i;
while (ce->list)
{
Eldbus_Proxy_Context_Event_Cb *ctx;
ctx = EINA_INLIST_CONTAINER_GET(ce->list,
Eldbus_Proxy_Context_Event_Cb);
_eldbus_proxy_context_event_cb_del(ce, ctx);
}
eina_list_free(ce->to_delete);
}
eina_stringshare_del(proxy->interface);
EINA_MAGIC_SET(proxy, EINA_MAGIC_NONE);
free(proxy);
}
static void
_on_object_free(void *data, const void *dead_pointer EINA_UNUSED)
{
Eldbus_Proxy *proxy = data;
ELDBUS_PROXY_CHECK(proxy);
DBG("proxy=%p, refcount=%d, interface=%s, obj=%p",
proxy, proxy->refcount, proxy->interface, proxy->obj);
eldbus_data_del_all(&(proxy->data));
_eldbus_proxy_clear(proxy);
_eldbus_proxy_free(proxy);
}
EAPI Eldbus_Proxy *
eldbus_proxy_get(Eldbus_Object *obj, const char *interface)
{
Eldbus_Proxy *proxy;
EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(interface, NULL);
proxy = eldbus_object_proxy_get(obj, interface);
if (proxy)
return eldbus_proxy_ref(proxy);
proxy = calloc(1, sizeof(Eldbus_Proxy));
EINA_SAFETY_ON_NULL_RETURN_VAL(proxy, NULL);
proxy->refcount = 1;
proxy->obj = obj;
proxy->interface = eina_stringshare_add(interface);
EINA_MAGIC_SET(proxy, ELDBUS_PROXY_MAGIC);
if (!eldbus_object_proxy_add(obj, proxy))
goto cleanup;
eldbus_object_free_cb_add(obj, _on_object_free, proxy);
return proxy;
cleanup:
eina_stringshare_del(proxy->interface);
free(proxy);
return NULL;
}
static void _on_signal_handler_free(void *data, const void *dead_pointer);
static void
_eldbus_proxy_unref(Eldbus_Proxy *proxy)
{
proxy->refcount--;
if (proxy->refcount > 0) return;
eldbus_object_free_cb_del(proxy->obj, _on_object_free, proxy);
eldbus_data_del_all(&(proxy->data));
_eldbus_proxy_clear(proxy);
_eldbus_proxy_free(proxy);
}
EAPI Eldbus_Proxy *
eldbus_proxy_ref(Eldbus_Proxy *proxy)
{
ELDBUS_PROXY_CHECK_RETVAL(proxy, NULL);
DBG("proxy=%p, pre-refcount=%d, interface=%s, obj=%p",
proxy, proxy->refcount, proxy->interface, proxy->obj);
proxy->refcount++;
return proxy;
}
EAPI void
eldbus_proxy_unref(Eldbus_Proxy *proxy)
{
ELDBUS_PROXY_CHECK(proxy);
DBG("proxy=%p, pre-refcount=%d, interface=%s, obj=%p",
proxy, proxy->refcount, proxy->interface, proxy->obj);
_eldbus_proxy_unref(proxy);
}
EAPI void
eldbus_proxy_free_cb_add(Eldbus_Proxy *proxy, Eldbus_Free_Cb cb, const void *data)
{
ELDBUS_PROXY_CHECK(proxy);
EINA_SAFETY_ON_NULL_RETURN(cb);
proxy->cbs_free = eldbus_cbs_free_add(proxy->cbs_free, cb, data);
}
EAPI void
eldbus_proxy_free_cb_del(Eldbus_Proxy *proxy, Eldbus_Free_Cb cb, const void *data)
{
ELDBUS_PROXY_CHECK(proxy);
EINA_SAFETY_ON_NULL_RETURN(cb);
proxy->cbs_free = eldbus_cbs_free_del(proxy->cbs_free, cb, data);
}
EAPI void
eldbus_proxy_data_set(Eldbus_Proxy *proxy, const char *key, const void *data)
{
ELDBUS_PROXY_CHECK(proxy);
EINA_SAFETY_ON_NULL_RETURN(key);
EINA_SAFETY_ON_NULL_RETURN(data);
eldbus_data_set(&(proxy->data), key, data);
}
EAPI void *
eldbus_proxy_data_get(const Eldbus_Proxy *proxy, const char *key)
{
ELDBUS_PROXY_CHECK_RETVAL(proxy, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(key, NULL);
return eldbus_data_get(&(((Eldbus_Proxy *)proxy)->data), key);
}
EAPI void *
eldbus_proxy_data_del(Eldbus_Proxy *proxy, const char *key)
{
ELDBUS_PROXY_CHECK_RETVAL(proxy, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(key, NULL);
return eldbus_data_del(&(((Eldbus_Proxy *)proxy)->data), key);
}
static Eina_Value *
_iter_hash_value_set(Eina_Hash *props, const char *key, Eldbus_Message_Iter *var) EINA_ARG_NONNULL(1, 2, 3)
{
Eina_Value *st_value = _message_iter_struct_to_eina_value(var);
Eina_Value *value;
Eina_Value stack_value;
eina_value_struct_value_get(st_value, "arg0", &stack_value);
value = eina_hash_find(props, key);
if (!value)
{
value = eina_value_new(eina_value_type_get(&stack_value));
eina_hash_add(props, key, value);
}
eina_value_flush(value);
eina_value_copy(&stack_value, value);
eina_value_flush(&stack_value);
eina_value_free(st_value);
return value;
}
static void
_property_changed_iter(void *data, const void *key, Eldbus_Message_Iter *var)
{
Eldbus_Proxy *proxy = data;
const char *skey = key;
Eina_Value *value = _iter_hash_value_set(proxy->props, skey, var);
Eldbus_Proxy_Event_Property_Changed event = {.name = skey,
.value = value,
.proxy = proxy};
_eldbus_proxy_event_callback_call(proxy, ELDBUS_PROXY_EVENT_PROPERTY_CHANGED,
&event);
}
static void
_properties_changed(void *data, const Eldbus_Message *msg)
{
Eldbus_Proxy *proxy = data;
Eldbus_Message_Iter *array, *invalidate;
const char *iface;
const char *invalidate_prop;
if (!eldbus_message_arguments_get(msg, "sa{sv}as", &iface, &array, &invalidate))
{
ERR("Error getting data from properties changed signal.");
return;
}
if (proxy->props)
eldbus_message_iter_dict_iterate(array, "sv", _property_changed_iter,
proxy);
while (eldbus_message_iter_get_and_next(invalidate, 's', &invalidate_prop))
{
Eldbus_Proxy_Event_Property_Removed event;
event.interface = proxy->interface;
event.name = invalidate_prop;
event.proxy = proxy;
if (proxy->props)
eina_hash_del(proxy->props, event.name, NULL);
_eldbus_proxy_event_callback_call(proxy, ELDBUS_PROXY_EVENT_PROPERTY_REMOVED,
&event);
}
}
static void
_props_cache_free(void *data)
{
Eina_Value *value = data;
eina_value_free(value);
}
EAPI void
eldbus_proxy_event_callback_add(Eldbus_Proxy *proxy, Eldbus_Proxy_Event_Type type, Eldbus_Proxy_Event_Cb cb, const void *cb_data)
{
Eldbus_Proxy_Context_Event *ce;
Eldbus_Proxy_Context_Event_Cb *ctx;
ELDBUS_PROXY_CHECK(proxy);
EINA_SAFETY_ON_NULL_RETURN(cb);
EINA_SAFETY_ON_TRUE_RETURN(type >= ELDBUS_PROXY_EVENT_LAST);
ce = proxy->event_handlers + type;
ctx = calloc(1, sizeof(Eldbus_Proxy_Context_Event_Cb));
EINA_SAFETY_ON_NULL_RETURN(ctx);
ctx->cb = cb;
ctx->cb_data = cb_data;
ce->list = eina_inlist_append(ce->list, EINA_INLIST_GET(ctx));
if (type == ELDBUS_PROXY_EVENT_PROPERTY_CHANGED)
{
if (proxy->properties_changed) return;
if (!proxy->props)
proxy->props = eina_hash_string_superfast_new(_props_cache_free);
proxy->properties_changed =
eldbus_proxy_properties_changed_callback_add(proxy,
_properties_changed,
proxy);
}
else if (type == ELDBUS_PROXY_EVENT_PROPERTY_REMOVED)
{
if (proxy->properties_changed) return;
proxy->properties_changed =
eldbus_proxy_properties_changed_callback_add(proxy,
_properties_changed,
proxy);
}
}
static void
_eldbus_proxy_context_event_cb_del(Eldbus_Proxy_Context_Event *ce, Eldbus_Proxy_Context_Event_Cb *ctx)
{
ce->list = eina_inlist_remove(ce->list, EINA_INLIST_GET(ctx));
free(ctx);
}
EAPI void
eldbus_proxy_event_callback_del(Eldbus_Proxy *proxy, Eldbus_Proxy_Event_Type type, Eldbus_Proxy_Event_Cb cb, const void *cb_data)
{
Eldbus_Proxy_Context_Event *ce;
Eldbus_Proxy_Context_Event_Cb *iter, *found = NULL;
ELDBUS_PROXY_CHECK(proxy);
EINA_SAFETY_ON_NULL_RETURN(cb);
EINA_SAFETY_ON_TRUE_RETURN(type >= ELDBUS_PROXY_EVENT_LAST);
ce = proxy->event_handlers + type;
EINA_INLIST_FOREACH(ce->list, iter)
{
if (cb != iter->cb) continue;
if ((cb_data) && (cb_data != iter->cb_data)) continue;
found = iter;
break;
}
EINA_SAFETY_ON_NULL_RETURN(found);
EINA_SAFETY_ON_TRUE_RETURN(found->deleted);
if (ce->walking)
{
found->deleted = EINA_TRUE;
ce->to_delete = eina_list_append(ce->to_delete, found);
return;
}
_eldbus_proxy_context_event_cb_del(ce, found);
if (type == ELDBUS_PROXY_EVENT_PROPERTY_CHANGED)
{
Eldbus_Proxy_Context_Event *ce_prop_remove;
ce_prop_remove = proxy->event_handlers +
ELDBUS_PROXY_EVENT_PROPERTY_REMOVED;
if (!ce->list && !proxy->monitor_enabled)
{
eina_hash_free(proxy->props);
proxy->props = NULL;
}
if (!ce_prop_remove->list && !ce->list && !proxy->monitor_enabled)
{
eldbus_signal_handler_unref(proxy->properties_changed);
proxy->properties_changed = NULL;
}
}
else if (type == ELDBUS_PROXY_EVENT_PROPERTY_REMOVED)
{
Eldbus_Proxy_Context_Event *ce_prop_changed;
ce_prop_changed = proxy->event_handlers +
ELDBUS_PROXY_EVENT_PROPERTY_CHANGED;
if (!ce_prop_changed->list && !ce->list && !proxy->monitor_enabled)
{
eldbus_signal_handler_unref(proxy->properties_changed);
proxy->properties_changed = NULL;
}
}
}
static void
_eldbus_proxy_event_callback_call(Eldbus_Proxy *proxy, Eldbus_Proxy_Event_Type type, const void *event_info)
{
Eldbus_Proxy_Context_Event *ce;
Eldbus_Proxy_Context_Event_Cb *iter;
ce = proxy->event_handlers + type;
ce->walking++;
EINA_INLIST_FOREACH(ce->list, iter)
{
if (iter->deleted) continue;
iter->cb((void *)iter->cb_data, proxy, (void *)event_info);
}
ce->walking--;
if (ce->walking > 0) return;
EINA_LIST_FREE(ce->to_delete, iter)
_eldbus_proxy_context_event_cb_del(ce, iter);
}
EAPI Eldbus_Object *
eldbus_proxy_object_get(const Eldbus_Proxy *proxy)
{
ELDBUS_PROXY_CHECK_RETVAL(proxy, NULL);
return proxy->obj;
}
EAPI const char *
eldbus_proxy_interface_get(const Eldbus_Proxy *proxy)
{
ELDBUS_PROXY_CHECK_RETVAL(proxy, NULL);
return proxy->interface;
}
static void
eldbus: Fix crash when removing the last reference of the message container inside of the message callback If user try to remove the last reference of proxy, object, connection or eldbus(lib) inside of message callback it was causing the eldbus_pending_dispatch() being called 2 times, one because of the eldbus_cancel() that is triggered when the last reference of the message parent is removed and another after the return of the user callback. ==6545== Invalid read of size 8 ==6545== at 0x52F784E: eldbus_cbs_free_dispatch (eldbus_core.c:266) ==6545== by 0x53064AA: eldbus_pending_dispatch (eldbus_pending.c:227) ==6545== by 0x5305961: cb_pending (eldbus_pending.c:74) ==6545== by 0x6B29DB1: ??? (in /usr/lib/libdbus-1.so.3.8.9) ==6545== by 0x6B2D280: dbus_connection_dispatch (in /usr/lib/libdbus-1.so.3.8.9) ==6545== by 0x52F93B4: eldbus_idler (eldbus_core.c:773) ==6545== by 0x4E4B300: _ecore_call_task_cb (ecore_private.h:305) ==6545== by 0x4E4B78F: _ecore_idler_all_call (ecore_idler.c:143) ==6545== by 0x4E4EA73: _ecore_main_loop_spin_core (ecore_main.c:1768) ==6545== by 0x4E4EAF1: _ecore_main_loop_spin_timers (ecore_main.c:1802) ==6545== by 0x4E4ED01: _ecore_main_loop_iterate_internal (ecore_main.c:1925) ==6545== by 0x4E4D03B: ecore_main_loop_begin (ecore_main.c:983) ==6545== Address 0x701aa78 is 104 bytes inside a block of size 128 free'd ==6545== at 0x4C2B200: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==6545== by 0x530655B: eldbus_pending_dispatch (eldbus_pending.c:241) ==6545== by 0x5306763: eldbus_pending_cancel (eldbus_pending.c:259) ==6545== by 0x52F29DB: _eldbus_proxy_clear (eldbus_proxy.c:146) ==6545== by 0x52F3057: _eldbus_proxy_unref (eldbus_proxy.c:244) ==6545== by 0x52F3393: eldbus_proxy_unref (eldbus_proxy.c:264) ==6545== by 0x401039: on_get_playlists (banshee.c:53) ==6545== by 0x5306493: eldbus_pending_dispatch (eldbus_pending.c:225) ==6545== by 0x5305961: cb_pending (eldbus_pending.c:74) ==6545== by 0x6B29DB1: ??? (in /usr/lib/libdbus-1.so.3.8.9) ==6545== by 0x6B2D280: dbus_connection_dispatch (in /usr/lib/libdbus-1.so.3.8.9) ==6545== by 0x52F93B4: eldbus_idler (eldbus_core.c:773) Now we will remove the pending from parent pending list before call the user callback, this way only the pending messages will be canceled. Also we need increase the eldbus reference before call dbus_connection_dispatch() or user could remove the last reference of eldbus inside of a message callback when we still are holding one reference of the connection. @fix ref T1908
2014-12-17 10:57:03 -08:00
_on_proxy_message_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending)
{
eldbus: Fix crash when removing the last reference of the message container inside of the message callback If user try to remove the last reference of proxy, object, connection or eldbus(lib) inside of message callback it was causing the eldbus_pending_dispatch() being called 2 times, one because of the eldbus_cancel() that is triggered when the last reference of the message parent is removed and another after the return of the user callback. ==6545== Invalid read of size 8 ==6545== at 0x52F784E: eldbus_cbs_free_dispatch (eldbus_core.c:266) ==6545== by 0x53064AA: eldbus_pending_dispatch (eldbus_pending.c:227) ==6545== by 0x5305961: cb_pending (eldbus_pending.c:74) ==6545== by 0x6B29DB1: ??? (in /usr/lib/libdbus-1.so.3.8.9) ==6545== by 0x6B2D280: dbus_connection_dispatch (in /usr/lib/libdbus-1.so.3.8.9) ==6545== by 0x52F93B4: eldbus_idler (eldbus_core.c:773) ==6545== by 0x4E4B300: _ecore_call_task_cb (ecore_private.h:305) ==6545== by 0x4E4B78F: _ecore_idler_all_call (ecore_idler.c:143) ==6545== by 0x4E4EA73: _ecore_main_loop_spin_core (ecore_main.c:1768) ==6545== by 0x4E4EAF1: _ecore_main_loop_spin_timers (ecore_main.c:1802) ==6545== by 0x4E4ED01: _ecore_main_loop_iterate_internal (ecore_main.c:1925) ==6545== by 0x4E4D03B: ecore_main_loop_begin (ecore_main.c:983) ==6545== Address 0x701aa78 is 104 bytes inside a block of size 128 free'd ==6545== at 0x4C2B200: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==6545== by 0x530655B: eldbus_pending_dispatch (eldbus_pending.c:241) ==6545== by 0x5306763: eldbus_pending_cancel (eldbus_pending.c:259) ==6545== by 0x52F29DB: _eldbus_proxy_clear (eldbus_proxy.c:146) ==6545== by 0x52F3057: _eldbus_proxy_unref (eldbus_proxy.c:244) ==6545== by 0x52F3393: eldbus_proxy_unref (eldbus_proxy.c:264) ==6545== by 0x401039: on_get_playlists (banshee.c:53) ==6545== by 0x5306493: eldbus_pending_dispatch (eldbus_pending.c:225) ==6545== by 0x5305961: cb_pending (eldbus_pending.c:74) ==6545== by 0x6B29DB1: ??? (in /usr/lib/libdbus-1.so.3.8.9) ==6545== by 0x6B2D280: dbus_connection_dispatch (in /usr/lib/libdbus-1.so.3.8.9) ==6545== by 0x52F93B4: eldbus_idler (eldbus_core.c:773) Now we will remove the pending from parent pending list before call the user callback, this way only the pending messages will be canceled. Also we need increase the eldbus reference before call dbus_connection_dispatch() or user could remove the last reference of eldbus inside of a message callback when we still are holding one reference of the connection. @fix ref T1908
2014-12-17 10:57:03 -08:00
Eldbus_Message_Cb cb = eldbus_pending_data_del(pending, "__user_cb");
Eldbus_Proxy *proxy = eldbus_pending_data_del(pending, "__proxy");
ELDBUS_PROXY_CHECK(proxy);
proxy->pendings = eina_inlist_remove(proxy->pendings,
EINA_INLIST_GET(pending));
eldbus: Fix crash when removing the last reference of the message container inside of the message callback If user try to remove the last reference of proxy, object, connection or eldbus(lib) inside of message callback it was causing the eldbus_pending_dispatch() being called 2 times, one because of the eldbus_cancel() that is triggered when the last reference of the message parent is removed and another after the return of the user callback. ==6545== Invalid read of size 8 ==6545== at 0x52F784E: eldbus_cbs_free_dispatch (eldbus_core.c:266) ==6545== by 0x53064AA: eldbus_pending_dispatch (eldbus_pending.c:227) ==6545== by 0x5305961: cb_pending (eldbus_pending.c:74) ==6545== by 0x6B29DB1: ??? (in /usr/lib/libdbus-1.so.3.8.9) ==6545== by 0x6B2D280: dbus_connection_dispatch (in /usr/lib/libdbus-1.so.3.8.9) ==6545== by 0x52F93B4: eldbus_idler (eldbus_core.c:773) ==6545== by 0x4E4B300: _ecore_call_task_cb (ecore_private.h:305) ==6545== by 0x4E4B78F: _ecore_idler_all_call (ecore_idler.c:143) ==6545== by 0x4E4EA73: _ecore_main_loop_spin_core (ecore_main.c:1768) ==6545== by 0x4E4EAF1: _ecore_main_loop_spin_timers (ecore_main.c:1802) ==6545== by 0x4E4ED01: _ecore_main_loop_iterate_internal (ecore_main.c:1925) ==6545== by 0x4E4D03B: ecore_main_loop_begin (ecore_main.c:983) ==6545== Address 0x701aa78 is 104 bytes inside a block of size 128 free'd ==6545== at 0x4C2B200: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==6545== by 0x530655B: eldbus_pending_dispatch (eldbus_pending.c:241) ==6545== by 0x5306763: eldbus_pending_cancel (eldbus_pending.c:259) ==6545== by 0x52F29DB: _eldbus_proxy_clear (eldbus_proxy.c:146) ==6545== by 0x52F3057: _eldbus_proxy_unref (eldbus_proxy.c:244) ==6545== by 0x52F3393: eldbus_proxy_unref (eldbus_proxy.c:264) ==6545== by 0x401039: on_get_playlists (banshee.c:53) ==6545== by 0x5306493: eldbus_pending_dispatch (eldbus_pending.c:225) ==6545== by 0x5305961: cb_pending (eldbus_pending.c:74) ==6545== by 0x6B29DB1: ??? (in /usr/lib/libdbus-1.so.3.8.9) ==6545== by 0x6B2D280: dbus_connection_dispatch (in /usr/lib/libdbus-1.so.3.8.9) ==6545== by 0x52F93B4: eldbus_idler (eldbus_core.c:773) Now we will remove the pending from parent pending list before call the user callback, this way only the pending messages will be canceled. Also we need increase the eldbus reference before call dbus_connection_dispatch() or user could remove the last reference of eldbus inside of a message callback when we still are holding one reference of the connection. @fix ref T1908
2014-12-17 10:57:03 -08:00
cb(data, msg, pending);
}
static Eldbus_Pending *
_eldbus_proxy_send(Eldbus_Proxy *proxy, Eldbus_Message *msg, Eldbus_Message_Cb cb, const void *cb_data, double timeout)
{
Eldbus_Pending *pending;
eldbus: Fix crash when removing the last reference of the message container inside of the message callback If user try to remove the last reference of proxy, object, connection or eldbus(lib) inside of message callback it was causing the eldbus_pending_dispatch() being called 2 times, one because of the eldbus_cancel() that is triggered when the last reference of the message parent is removed and another after the return of the user callback. ==6545== Invalid read of size 8 ==6545== at 0x52F784E: eldbus_cbs_free_dispatch (eldbus_core.c:266) ==6545== by 0x53064AA: eldbus_pending_dispatch (eldbus_pending.c:227) ==6545== by 0x5305961: cb_pending (eldbus_pending.c:74) ==6545== by 0x6B29DB1: ??? (in /usr/lib/libdbus-1.so.3.8.9) ==6545== by 0x6B2D280: dbus_connection_dispatch (in /usr/lib/libdbus-1.so.3.8.9) ==6545== by 0x52F93B4: eldbus_idler (eldbus_core.c:773) ==6545== by 0x4E4B300: _ecore_call_task_cb (ecore_private.h:305) ==6545== by 0x4E4B78F: _ecore_idler_all_call (ecore_idler.c:143) ==6545== by 0x4E4EA73: _ecore_main_loop_spin_core (ecore_main.c:1768) ==6545== by 0x4E4EAF1: _ecore_main_loop_spin_timers (ecore_main.c:1802) ==6545== by 0x4E4ED01: _ecore_main_loop_iterate_internal (ecore_main.c:1925) ==6545== by 0x4E4D03B: ecore_main_loop_begin (ecore_main.c:983) ==6545== Address 0x701aa78 is 104 bytes inside a block of size 128 free'd ==6545== at 0x4C2B200: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==6545== by 0x530655B: eldbus_pending_dispatch (eldbus_pending.c:241) ==6545== by 0x5306763: eldbus_pending_cancel (eldbus_pending.c:259) ==6545== by 0x52F29DB: _eldbus_proxy_clear (eldbus_proxy.c:146) ==6545== by 0x52F3057: _eldbus_proxy_unref (eldbus_proxy.c:244) ==6545== by 0x52F3393: eldbus_proxy_unref (eldbus_proxy.c:264) ==6545== by 0x401039: on_get_playlists (banshee.c:53) ==6545== by 0x5306493: eldbus_pending_dispatch (eldbus_pending.c:225) ==6545== by 0x5305961: cb_pending (eldbus_pending.c:74) ==6545== by 0x6B29DB1: ??? (in /usr/lib/libdbus-1.so.3.8.9) ==6545== by 0x6B2D280: dbus_connection_dispatch (in /usr/lib/libdbus-1.so.3.8.9) ==6545== by 0x52F93B4: eldbus_idler (eldbus_core.c:773) Now we will remove the pending from parent pending list before call the user callback, this way only the pending messages will be canceled. Also we need increase the eldbus reference before call dbus_connection_dispatch() or user could remove the last reference of eldbus inside of a message callback when we still are holding one reference of the connection. @fix ref T1908
2014-12-17 10:57:03 -08:00
if (!cb)
{
_eldbus_connection_send(proxy->obj->conn, msg, NULL, NULL, timeout);
return NULL;
}
pending = _eldbus_connection_send(proxy->obj->conn, msg,
_on_proxy_message_cb, cb_data, timeout);
EINA_SAFETY_ON_NULL_RETURN_VAL(pending, NULL);
eldbus: Fix crash when removing the last reference of the message container inside of the message callback If user try to remove the last reference of proxy, object, connection or eldbus(lib) inside of message callback it was causing the eldbus_pending_dispatch() being called 2 times, one because of the eldbus_cancel() that is triggered when the last reference of the message parent is removed and another after the return of the user callback. ==6545== Invalid read of size 8 ==6545== at 0x52F784E: eldbus_cbs_free_dispatch (eldbus_core.c:266) ==6545== by 0x53064AA: eldbus_pending_dispatch (eldbus_pending.c:227) ==6545== by 0x5305961: cb_pending (eldbus_pending.c:74) ==6545== by 0x6B29DB1: ??? (in /usr/lib/libdbus-1.so.3.8.9) ==6545== by 0x6B2D280: dbus_connection_dispatch (in /usr/lib/libdbus-1.so.3.8.9) ==6545== by 0x52F93B4: eldbus_idler (eldbus_core.c:773) ==6545== by 0x4E4B300: _ecore_call_task_cb (ecore_private.h:305) ==6545== by 0x4E4B78F: _ecore_idler_all_call (ecore_idler.c:143) ==6545== by 0x4E4EA73: _ecore_main_loop_spin_core (ecore_main.c:1768) ==6545== by 0x4E4EAF1: _ecore_main_loop_spin_timers (ecore_main.c:1802) ==6545== by 0x4E4ED01: _ecore_main_loop_iterate_internal (ecore_main.c:1925) ==6545== by 0x4E4D03B: ecore_main_loop_begin (ecore_main.c:983) ==6545== Address 0x701aa78 is 104 bytes inside a block of size 128 free'd ==6545== at 0x4C2B200: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==6545== by 0x530655B: eldbus_pending_dispatch (eldbus_pending.c:241) ==6545== by 0x5306763: eldbus_pending_cancel (eldbus_pending.c:259) ==6545== by 0x52F29DB: _eldbus_proxy_clear (eldbus_proxy.c:146) ==6545== by 0x52F3057: _eldbus_proxy_unref (eldbus_proxy.c:244) ==6545== by 0x52F3393: eldbus_proxy_unref (eldbus_proxy.c:264) ==6545== by 0x401039: on_get_playlists (banshee.c:53) ==6545== by 0x5306493: eldbus_pending_dispatch (eldbus_pending.c:225) ==6545== by 0x5305961: cb_pending (eldbus_pending.c:74) ==6545== by 0x6B29DB1: ??? (in /usr/lib/libdbus-1.so.3.8.9) ==6545== by 0x6B2D280: dbus_connection_dispatch (in /usr/lib/libdbus-1.so.3.8.9) ==6545== by 0x52F93B4: eldbus_idler (eldbus_core.c:773) Now we will remove the pending from parent pending list before call the user callback, this way only the pending messages will be canceled. Also we need increase the eldbus reference before call dbus_connection_dispatch() or user could remove the last reference of eldbus inside of a message callback when we still are holding one reference of the connection. @fix ref T1908
2014-12-17 10:57:03 -08:00
eldbus_pending_data_set(pending, "__user_cb", cb);
eldbus_pending_data_set(pending, "__proxy", proxy);
proxy->pendings = eina_inlist_append(proxy->pendings,
EINA_INLIST_GET(pending));
return pending;
}
static Eldbus_Message *
_eldbus_proxy_send_and_block(Eldbus_Proxy *proxy, Eldbus_Message *msg, double timeout)
{
return _eldbus_connection_send_and_block(proxy->obj->conn, msg, timeout);
}
EAPI Eldbus_Pending *
eldbus_proxy_send(Eldbus_Proxy *proxy, Eldbus_Message *msg, Eldbus_Message_Cb cb, const void *cb_data, double timeout)
{
ELDBUS_PROXY_CHECK_RETVAL(proxy, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(msg, NULL);
return _eldbus_proxy_send(proxy, msg, cb, cb_data, timeout);
}
EAPI Eldbus_Message *
eldbus_proxy_send_and_block(Eldbus_Proxy *proxy, Eldbus_Message *msg, double timeout)
{
ELDBUS_PROXY_CHECK_RETVAL(proxy, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(msg, NULL);
return _eldbus_proxy_send_and_block(proxy, msg, timeout);
}
EAPI Eldbus_Message *
eldbus_proxy_method_call_new(Eldbus_Proxy *proxy, const char *member)
{
Eldbus_Message *msg;
ELDBUS_PROXY_CHECK_RETVAL(proxy, NULL);
msg = eldbus_message_method_call_new(
eldbus_object_bus_name_get(proxy->obj),
eldbus_object_path_get(proxy->obj),
proxy->interface, member);
return msg;
}
static Eldbus_Pending *
_eldbus_proxy_vcall(Eldbus_Proxy *proxy, const char *member, Eldbus_Message_Cb cb, const void *cb_data, double timeout, const char *signature, va_list ap)
{
Eldbus_Message *msg = eldbus_proxy_method_call_new(proxy, member);
EINA_SAFETY_ON_NULL_RETURN_VAL(msg, NULL);
if (!eldbus_message_arguments_vappend(msg, signature, ap))
{
eldbus_message_unref(msg);
ERR("Error setting arguments");
return NULL;
}
return _eldbus_proxy_send(proxy, msg, cb, cb_data, timeout);
}
EAPI Eldbus_Pending *
eldbus_proxy_call(Eldbus_Proxy *proxy, const char *member, Eldbus_Message_Cb cb, const void *cb_data, double timeout, const char *signature, ...)
{
Eldbus_Pending *pending;
va_list ap;
ELDBUS_PROXY_CHECK_RETVAL(proxy, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(member, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(signature, NULL);
va_start(ap, signature);
pending = _eldbus_proxy_vcall(proxy, member, cb, cb_data, timeout,
signature, ap);
va_end(ap);
return pending;
}
EAPI Eldbus_Pending *
eldbus_proxy_vcall(Eldbus_Proxy *proxy, const char *member, Eldbus_Message_Cb cb, const void *cb_data, double timeout, const char *signature, va_list ap)
{
ELDBUS_PROXY_CHECK_RETVAL(proxy, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(member, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(signature, NULL);
return _eldbus_proxy_vcall(proxy, member, cb, cb_data, timeout,
signature, ap);
}
static void
_on_signal_handler_free(void *data, const void *dead_pointer)
{
Eldbus_Proxy *proxy = data;
ELDBUS_PROXY_CHECK(proxy);
proxy->handlers = eina_list_remove(proxy->handlers, dead_pointer);
}
EAPI Eldbus_Signal_Handler *
eldbus_proxy_signal_handler_add(Eldbus_Proxy *proxy, const char *member, Eldbus_Signal_Cb cb, const void *cb_data)
{
Eldbus_Signal_Handler *handler;
const char *name, *path;
ELDBUS_PROXY_CHECK_RETVAL(proxy, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(cb, NULL);
name = eldbus_object_bus_name_get(proxy->obj);
path = eldbus_object_path_get(proxy->obj);
handler = _eldbus_signal_handler_add(proxy->obj->conn, name, path,
edbus: Fix bug found in refactored banshee example Refactor edbus_signal_handler_add() so internal signal handlers don't set the connection free callback. This fixes the bug in which EDBus_Connection was freeing the signal handler of EDBus_Conenction_Name ==22814== Invalid read of size 4 ==22814== at 0x40564B0: edbus_signal_handler_del (edbus_signal_handler.c:278) ==22814== by 0x4040E65: _edbus_connection_name_unref (edbus_core.c:507) ==22814== by 0x404106B: edbus_connection_name_owner_monitor (edbus_core.c:520) ==22814== by 0x4055F63: _edbus_signal_handler_clean (edbus_signal_handler.c:217) ==22814== by 0x40564F8: edbus_signal_handler_del (edbus_signal_handler.c:279) ==22814== by 0x4043088: _edbus_connection_unref (edbus_core.c:1045) ==22814== by 0x404352F: edbus_connection_unref (edbus_core.c:1105) ==22814== by 0x80498AA: main (banshee.c:233) ==22814== Address 0x44bea48 is 0 bytes inside a block of size 72 free'd ==22814== at 0x402C06C: free (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so) ==22814== by 0x4056118: _edbus_signal_handler_del (edbus_signal_handler.c:249) ==22814== by 0x4056401: edbus_signal_handler_unref (edbus_signal_handler.c:272) ==22814== by 0x4056503: edbus_signal_handler_del (edbus_signal_handler.c:280) ==22814== by 0x4043088: _edbus_connection_unref (edbus_core.c:1045) ==22814== by 0x404352F: edbus_connection_unref (edbus_core.c:1105) ==22814== by 0x80498AA: main (banshee.c:233) ==22814== CRI<22814>: src/lib/edbus_signal_handler.c:278 edbus_signal_handler_del() *** Eina Magic Check Failed !!! Input handle has already been freed! *** NAUGHTY PROGRAMMER!!! *** SPANK SPANK SPANK!!! *** Now go fix your code. Tut tut tut! Patch by: José Roberto de Souza <zehortigoza@profusion.mobi> SVN revision: 80686
2012-12-11 11:50:01 -08:00
proxy->interface, member, cb, cb_data);
EINA_SAFETY_ON_NULL_RETURN_VAL(handler, NULL);
DBG("signal handler added: proxy=%p handler=%p cb=%p", proxy, handler, cb);
eldbus_signal_handler_free_cb_add(handler, _on_signal_handler_free, proxy);
proxy->handlers = eina_list_append(proxy->handlers, handler);
return handler;
}
EAPI Eldbus_Pending *
eldbus_proxy_property_get(Eldbus_Proxy *proxy, const char *name, Eldbus_Message_Cb cb, const void *data)
{
ELDBUS_PROXY_CHECK_RETVAL(proxy, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL);
return eldbus_proxy_call(proxy->obj->properties, "Get", cb, data, -1,
"ss", proxy->interface, name);
}
static inline Eina_Bool
_type_is_number(char sig)
{
switch (sig)
{
case 'y': case 'b': case 'n': case 'q': case 'i':
case 'u': case 'x': case 't': case 'd': case 'h':
return EINA_TRUE;
default:
break;
}
return EINA_FALSE;
}
EAPI Eldbus_Pending *
eldbus_proxy_property_set(Eldbus_Proxy *proxy, const char *name, const char *sig, const void *value, Eldbus_Message_Cb cb, const void *data)
{
Eldbus_Message *msg;
Eldbus_Message_Iter *iter, *variant;
ELDBUS_PROXY_CHECK_RETVAL(proxy, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(sig, NULL);
EINA_SAFETY_ON_FALSE_RETURN_VAL(dbus_signature_validate_single(sig, NULL), NULL);
EINA_SAFETY_ON_FALSE_RETURN_VAL((_type_is_number(sig[0]) || value), NULL);
msg = eldbus_proxy_method_call_new(proxy->obj->properties, "Set");
iter = eldbus_message_iter_get(msg);
eldbus_message_iter_basic_append(iter, 's', proxy->interface);
eldbus_message_iter_basic_append(iter, 's', name);
variant = eldbus_message_iter_container_new(iter, 'v', sig);
if (dbus_type_is_basic(sig[0]))
dbus_message_iter_append_basic(&variant->dbus_iterator, sig[0], &value);
else
{
if (!_message_iter_from_eina_value_struct(sig, variant, value))
{
eldbus_message_unref(msg);
return NULL;
}
}
eldbus_message_iter_container_close(iter, variant);
return eldbus_proxy_send(proxy->obj->properties, msg, cb, data, -1);
}
EAPI Eldbus_Pending *
eldbus_proxy_property_value_set(Eldbus_Proxy *proxy, const char *name, const char *sig, const Eina_Value *value, Eldbus_Message_Cb cb, const void *data)
{
Eldbus_Message *msg;
Eldbus_Message_Iter *iter, *variant;
ELDBUS_PROXY_CHECK_RETVAL(proxy, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(sig, NULL);
EINA_SAFETY_ON_FALSE_RETURN_VAL(dbus_signature_validate_single(sig, NULL), NULL);
EINA_SAFETY_ON_FALSE_RETURN_VAL((_type_is_number(sig[0]) || value), NULL);
msg = eldbus_proxy_method_call_new(proxy->obj->properties, "Set");
iter = eldbus_message_iter_get(msg);
eldbus_message_iter_basic_append(iter, 's', proxy->interface);
eldbus_message_iter_basic_append(iter, 's', name);
variant = eldbus_message_iter_container_new(iter, 'v', sig);
if (dbus_type_is_basic(sig[0]))
{
if (!_message_iter_from_eina_value(sig, variant, value))
goto error;
}
else
{
if (!_message_iter_from_eina_value_struct(sig, variant, value))
goto error;
}
eldbus_message_iter_container_close(iter, variant);
return eldbus_proxy_send(proxy->obj->properties, msg, cb, data, -1);
error:
eldbus_message_unref(msg);
return NULL;
}
EAPI Eldbus_Pending *
eldbus_proxy_property_get_all(Eldbus_Proxy *proxy, Eldbus_Message_Cb cb, const void *data)
{
ELDBUS_PROXY_CHECK_RETVAL(proxy, NULL);
return eldbus_proxy_call(proxy->obj->properties, "GetAll", cb, data, -1,
"s", proxy->interface);
}
EAPI Eldbus_Signal_Handler *
eldbus_proxy_properties_changed_callback_add(Eldbus_Proxy *proxy, Eldbus_Signal_Cb cb, const void *data)
{
Eldbus_Signal_Handler *sh;
ELDBUS_PROXY_CHECK_RETVAL(proxy, NULL);
sh = eldbus_proxy_signal_handler_add(proxy->obj->properties,
"PropertiesChanged", cb, data);
EINA_SAFETY_ON_NULL_RETURN_VAL(sh, NULL);
eldbus_signal_handler_match_extra_set(sh, "arg0", proxy->interface, NULL);
return sh;
}
static void
_property_iter(void *data, const void *key, Eldbus_Message_Iter *var)
{
Eldbus_Proxy *proxy = data;
const char *skey = key;
_iter_hash_value_set(proxy->props, skey, var);
}
static void
_on_monitored_proxy_del(void *data, Eldbus_Proxy *proxy EINA_UNUSED, void *event_info EINA_UNUSED)
{
Eldbus_Pending *pending = data;
eldbus_pending_cancel(pending);
}
static void
_props_get_all(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending)
{
Eldbus_Proxy *proxy = data;
Eldbus_Message_Iter *dict;
const char *name, *error_msg;
Eldbus_Proxy_Event_Property_Loaded event;
eldbus_proxy_event_callback_del(proxy, ELDBUS_PROXY_EVENT_DEL,
_on_monitored_proxy_del, pending);
if (eldbus_message_error_get(msg, &name, &error_msg))
{
/* don't print warnings for user-canceled calls */
if (!eina_streq(name, "org.enlightenment.DBus.Canceled"))
WRN("Error getting all properties of %s %s, error message: %s %s",
proxy->obj->name, proxy->obj->path, name, error_msg);
return;
}
if (!eldbus_message_arguments_get(msg, "a{sv}", &dict))
{
char *txt;
if (eldbus_message_arguments_get(msg, "s", &txt))
WRN("Error getting data from properties getAll: %s", txt);
return;
}
eldbus_message_iter_dict_iterate(dict, "sv", _property_iter, proxy);
event.proxy = proxy;
_eldbus_proxy_event_callback_call(proxy, ELDBUS_PROXY_EVENT_PROPERTY_LOADED,
&event);
}
EAPI Eina_Bool
eldbus_proxy_properties_monitor(Eldbus_Proxy *proxy, Eina_Bool enable)
{
Eldbus_Pending *pending;
ELDBUS_PROXY_CHECK_RETVAL(proxy, EINA_FALSE);
if (proxy->monitor_enabled == enable)
return proxy->props ? !!eina_hash_population(proxy->props) : EINA_FALSE;
proxy->monitor_enabled = enable;
if (!enable)
{
Eldbus_Proxy_Context_Event *ce_prop_changed, *ce_prop_removed;
ce_prop_changed = proxy->event_handlers + ELDBUS_PROXY_EVENT_PROPERTY_CHANGED;
ce_prop_removed = proxy->event_handlers + ELDBUS_PROXY_EVENT_PROPERTY_REMOVED;
if (!ce_prop_changed->list)
{
eina_hash_free(proxy->props);
proxy->props = NULL;
}
if (!ce_prop_changed->list && !ce_prop_removed->list)
{
eldbus_signal_handler_unref(proxy->properties_changed);
proxy->properties_changed = NULL;
}
return EINA_TRUE;
}
if (!proxy->props)
proxy->props = eina_hash_string_superfast_new(_props_cache_free);
pending = eldbus_proxy_property_get_all(proxy, _props_get_all, proxy);
eldbus_proxy_event_callback_add(proxy, ELDBUS_PROXY_EVENT_DEL,
_on_monitored_proxy_del, pending);
if (proxy->properties_changed)
return !!eina_hash_population(proxy->props);
proxy->properties_changed =
eldbus_proxy_properties_changed_callback_add(proxy,
_properties_changed,
proxy);
return !!eina_hash_population(proxy->props);
}
EAPI Eina_Value *
eldbus_proxy_property_local_get(Eldbus_Proxy *proxy, const char *name)
{
ELDBUS_PROXY_CHECK_RETVAL(proxy, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(proxy->props, NULL);
return eina_hash_find(proxy->props, name);
}
EAPI const Eina_Hash *
eldbus_proxy_property_local_get_all(Eldbus_Proxy *proxy)
{
ELDBUS_PROXY_CHECK_RETVAL(proxy, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(proxy->props, NULL);
return proxy->props;
}