1 #ifdef HAVE_CONFIG_H
2 # include "config.h"
3 #endif
4 
5 #include "eldbus_private.h"
6 #include "eldbus_private_types.h"
7 
8 #define ELDBUS_CONNECTION_CHECK(conn)                        \
9   do                                                        \
10     {                                                       \
11        EINA_SAFETY_ON_NULL_RETURN(conn);                    \
12        if (!EINA_MAGIC_CHECK(conn, ELDBUS_CONNECTION_MAGIC)) \
13          {                                                  \
14             EINA_MAGIC_FAIL(conn, ELDBUS_CONNECTION_MAGIC);  \
15             return;                                         \
16          }                                                  \
17        EINA_SAFETY_ON_TRUE_RETURN(conn->refcount <= 0);     \
18     }                                                       \
19   while (0)
20 
21 #define ELDBUS_CONNECTION_CHECK_RETVAL(conn, retval)                 \
22   do                                                                \
23     {                                                               \
24        EINA_SAFETY_ON_NULL_RETURN_VAL(conn, retval);                \
25        if (!EINA_MAGIC_CHECK(conn, ELDBUS_CONNECTION_MAGIC))         \
26          {                                                          \
27             EINA_MAGIC_FAIL(conn, ELDBUS_CONNECTION_MAGIC);          \
28             return retval;                                          \
29          }                                                          \
30        EINA_SAFETY_ON_TRUE_RETURN_VAL(conn->refcount <= 0, retval); \
31     }                                                               \
32   while (0)
33 
34 typedef struct _Eldbus_Connection_Context_Event_Cb
35 {
36    EINA_INLIST;
37    Eldbus_Connection_Event_Cb cb;
38    const void               *cb_data;
39    Eina_Bool                 deleted : 1;
40 } Eldbus_Connection_Context_Event_Cb;
41 
42 typedef struct _Eldbus_Connection_Context_NOC_Cb
43 {
44    EINA_INLIST;
45    Eldbus_Name_Owner_Changed_Cb cb;
46    const void                 *cb_data;
47    Eina_Bool                   deleted : 1;
48    Ecore_Idle_Enterer         *idle_enterer;
49    Eina_Bool                   allow_initial : 1;
50 } Eldbus_Connection_Context_NOC_Cb;
51 
52 typedef struct _Eldbus_Handler_Data
53 {
54    EINA_INLIST;
55    int               fd;
56    Ecore_Fd_Handler *fd_handler;
57    Eldbus_Connection *conn;
58    DBusWatch        *watch;
59    int               enabled;
60 } Eldbus_Handler_Data;
61 
62 typedef struct _Eldbus_Timeout_Data
63 {
64    EINA_INLIST;
65    Ecore_Timer      *handler;
66    DBusTimeout      *timeout;
67    Eldbus_Connection *conn;
68    int               interval;
69 } Eldbus_Timeout_Data;
70 
71 static const Eldbus_Version _version = {VMAJ, VMIN, VMIC, VREV};
72 EAPI const Eldbus_Version * eldbus_version = &_version;
73 
74 static int _eldbus_init_count = 0;
75 int _eldbus_log_dom = -1;
76 int eldbus_model_log_dom = -1;
77 
78 /* We don't save ELDBUS_CONNECTION_TYPE_UNKNOWN in here so we need room for
79  * last - 1 elements */
80 static void *shared_connections[ELDBUS_CONNECTION_TYPE_LAST - 1];
81 static Eina_Hash *address_connections = NULL;
82 
83 static void _eldbus_connection_event_callback_call(Eldbus_Connection *conn, Eldbus_Connection_Event_Type type, const void *event_info);
84 static void _eldbus_connection_context_event_cb_del(Eldbus_Connection_Context_Event *ce, Eldbus_Connection_Context_Event_Cb *ctx);
85 static void eldbus_dispatch_name_owner_change(Eldbus_Connection_Name *cn, const char *old_id);
86 static void _eldbus_connection_free(Eldbus_Connection *conn);
87 
88 static void
eldbus_fd_handler_del(Eldbus_Handler_Data * hd)89 eldbus_fd_handler_del(Eldbus_Handler_Data *hd)
90 {
91    if (!hd->fd_handler) return;
92 
93    DBG("free Eldbus_Handler_Data %d", hd->fd);
94    hd->conn->fd_handlers = eina_inlist_remove(hd->conn->fd_handlers,
95                                               EINA_INLIST_GET(hd));
96    if (hd->fd_handler)
97      {
98         ecore_main_fd_handler_del(hd->fd_handler);
99         hd->fd_handler = NULL;
100      }
101 
102    free(hd);
103 }
104 
105 static void
_eldbus_fork_reset()106 _eldbus_fork_reset()
107 {
108    int i;
109 
110    for (i =0; i < ELDBUS_CONNECTION_TYPE_LAST - 1; i++)
111      {
112         Eldbus_Connection *conn = shared_connections[i];
113         if (conn)
114           {
115              Eina_Inlist *list;
116              Eldbus_Handler_Data *fd_handler;
117 
118              EINA_INLIST_FOREACH_SAFE(conn->fd_handlers, list, fd_handler)
119                dbus_watch_set_data(fd_handler->watch, NULL, NULL);
120           }
121         shared_connections[i] = NULL;
122      }
123    if (address_connections) eina_hash_free(address_connections);
124    address_connections = NULL;
125 }
126 
127 EAPI int
eldbus_init(void)128 eldbus_init(void)
129 {
130    if (_eldbus_init_count++ > 0)
131      return _eldbus_init_count;
132 
133    if (!eina_init())
134      {
135         fputs("Eldbus: Unable to initialize eina\n", stderr);
136         return 0;
137      }
138 
139    if (!ecore_init())
140      {
141         fputs("Eldbus: Unable to initialize ecore\n", stderr);
142         eina_shutdown();
143         return 0;
144      }
145 
146    _eldbus_log_dom = eina_log_domain_register("eldbus", EINA_COLOR_BLUE);
147    if (_eldbus_log_dom < 0)
148      {
149         EINA_LOG_ERR("Unable to create an 'eldbus' log domain");
150         ecore_shutdown();
151         eina_shutdown();
152         return 0;
153      }
154 
155    eldbus_model_log_dom = eina_log_domain_register("eldbus_model", EINA_COLOR_CYAN);
156    if (eldbus_model_log_dom < 0)
157      {
158         EINA_LOG_ERR("Unable to create an 'eldbus_model' log domain");
159         eina_log_domain_unregister(_eldbus_log_dom);
160         _eldbus_log_dom = -1;
161         ecore_shutdown();
162         eina_shutdown();
163         return 0;
164      }
165 
166    eina_magic_string_set(ELDBUS_CONNECTION_MAGIC, "Eldbus_Connection");
167    eina_magic_string_set(ELDBUS_MESSAGE_MAGIC, "Eldbus_Message");
168    eina_magic_string_set(ELDBUS_SIGNAL_HANDLER_MAGIC, "Eldbus_Signal_Handler");
169    eina_magic_string_set(ELDBUS_PENDING_MAGIC, "Eldbus_Pending");
170    eina_magic_string_set(ELDBUS_OBJECT_MAGIC, "Eldbus_Object");
171    eina_magic_string_set(ELDBUS_PROXY_MAGIC, "Eldbus_Proxy");
172    eina_magic_string_set(ELDBUS_MESSAGE_ITERATOR_MAGIC, "Eldbus_Message_Iterator");
173    eina_magic_string_set(ELDBUS_SERVICE_INTERFACE_MAGIC, "Eldbus_Service_Interface");
174 
175 
176    if (!eldbus_message_init()) goto message_failed;
177    if (!eldbus_signal_handler_init()) goto signal_handler_failed;
178    if (!eldbus_pending_init()) goto pending_failed;
179    if (!eldbus_object_init()) goto object_failed;
180    if (!eldbus_proxy_init()) goto proxy_failed;
181    if (!eldbus_service_init()) goto service_failed;
182    ecore_fork_reset_callback_add(_eldbus_fork_reset, NULL);
183    return _eldbus_init_count;
184 
185 service_failed:
186    eldbus_proxy_shutdown();
187 proxy_failed:
188    eldbus_object_shutdown();
189 object_failed:
190    eldbus_pending_shutdown();
191 pending_failed:
192    eldbus_signal_handler_shutdown();
193 signal_handler_failed:
194    eldbus_message_shutdown();
195 message_failed:
196    eina_log_domain_unregister(eldbus_model_log_dom);
197    eldbus_model_log_dom = -1;
198    eina_log_domain_unregister(_eldbus_log_dom);
199    _eldbus_log_dom = -1;
200    ecore_shutdown();
201    eina_shutdown();
202 
203    return 0;
204 }
205 
206 static void
print_live_connection(Eldbus_Connection * conn)207 print_live_connection(Eldbus_Connection *conn)
208 {
209    if (!conn->names)
210      ERR("conn=%p has no alive objects", conn);
211    else
212      {
213         Eina_Iterator *iter = eina_hash_iterator_data_new(conn->names);
214         Eldbus_Connection_Name *name;
215         EINA_ITERATOR_FOREACH(iter, name)
216           {
217              Eldbus_Object *obj;
218              Eina_Iterator *inner_itr;
219              if (!name->objects) continue;
220 
221              inner_itr = eina_hash_iterator_data_new(name->objects);
222              EINA_ITERATOR_FOREACH(inner_itr, obj)
223                 ERR("conn=%p alive object=%p %s of bus=%s", conn, obj,
224                     obj->name, name->name);
225              eina_iterator_free(inner_itr);
226           }
227         eina_iterator_free(iter);
228      }
229 
230    if (!conn->pendings)
231      ERR("conn=%p has no alive pending calls", conn);
232    else
233      {
234         Eldbus_Pending *p;
235         EINA_INLIST_FOREACH(conn->pendings, p)
236           ERR("conn=%p alive pending call=%p dest=%s path=%s %s.%s()",
237               conn, p,
238               eldbus_pending_destination_get(p),
239               eldbus_pending_path_get(p),
240               eldbus_pending_interface_get(p),
241               eldbus_pending_method_get(p));
242      }
243 }
244 
245 EAPI int
eldbus_shutdown(void)246 eldbus_shutdown(void)
247 {
248    if (_eldbus_init_count <= 0)
249      {
250         ERR("Init count not greater than 0 in shutdown.");
251         _eldbus_init_count = 0;
252         return 0;
253      }
254    if (--_eldbus_init_count)
255      return _eldbus_init_count;
256 
257    ecore_fork_reset_callback_del(_eldbus_fork_reset, NULL);
258    if (shared_connections[ELDBUS_CONNECTION_TYPE_SESSION - 1])
259      {
260         CRI("Alive TYPE_SESSION connection");
261         print_live_connection(shared_connections[ELDBUS_CONNECTION_TYPE_SESSION - 1]);
262      }
263    if (shared_connections[ELDBUS_CONNECTION_TYPE_SYSTEM - 1])
264      {
265         CRI("Alive TYPE_SYSTEM connection");
266         print_live_connection(shared_connections[ELDBUS_CONNECTION_TYPE_SYSTEM - 1]);
267      }
268    if (shared_connections[ELDBUS_CONNECTION_TYPE_STARTER - 1])
269      {
270         CRI("Alive TYPE_STARTER connection");
271         print_live_connection(shared_connections[ELDBUS_CONNECTION_TYPE_STARTER - 1]);
272      }
273    if (shared_connections[ELDBUS_CONNECTION_TYPE_ADDRESS - 1])
274      {
275         if (eina_hash_population(address_connections))
276           {
277              Eina_Iterator *it;
278              Eina_Hash_Tuple *tuple;
279 
280              it = eina_hash_iterator_tuple_new(address_connections);
281              EINA_ITERATOR_FOREACH(it, tuple)
282                {
283                   CRI("Alive TYPE_ADDRESS connection: %s", (char*)tuple->key);
284                   print_live_connection(tuple->data);
285                }
286              eina_iterator_free(it);
287           }
288 
289         eina_hash_free(address_connections);
290         address_connections = shared_connections[ELDBUS_CONNECTION_TYPE_ADDRESS - 1] = NULL;
291      }
292 
293    eldbus_service_shutdown();
294    eldbus_proxy_shutdown();
295    eldbus_object_shutdown();
296    eldbus_pending_shutdown();
297    eldbus_signal_handler_shutdown();
298    eldbus_message_shutdown();
299 
300    ecore_shutdown();
301 
302    eina_log_domain_unregister(eldbus_model_log_dom);
303    eldbus_model_log_dom = -1;
304    eina_log_domain_unregister(_eldbus_log_dom);
305    _eldbus_log_dom = -1;
306 
307    eina_shutdown();
308 
309    return 0;
310 }
311 
312 /* TODO: mempool of Eldbus_Context_Free_Cb */
313 typedef struct _Eldbus_Context_Free_Cb
314 {
315    EINA_INLIST;
316    Eldbus_Free_Cb cb;
317    const void   *data;
318 } Eldbus_Context_Free_Cb;
319 
320 void
eldbus_cbs_free_dispatch(Eina_Inlist ** p_lst,const void * dead_pointer)321 eldbus_cbs_free_dispatch(Eina_Inlist **p_lst, const void *dead_pointer)
322 {
323    Eina_Inlist *lst = *p_lst;
324    *p_lst = NULL;
325    while (lst)
326      {
327         Eina_Inlist *next = lst->next;
328         Eldbus_Context_Free_Cb *ctx;
329 
330         ctx = EINA_INLIST_CONTAINER_GET(lst, Eldbus_Context_Free_Cb);
331         ctx->cb((void *)ctx->data, dead_pointer);
332         free(ctx);
333 
334         lst = next;
335      }
336 }
337 
338 Eina_Inlist *
eldbus_cbs_free_add(Eina_Inlist * lst,Eldbus_Free_Cb cb,const void * data)339 eldbus_cbs_free_add(Eina_Inlist *lst, Eldbus_Free_Cb cb, const void *data)
340 {
341    Eldbus_Context_Free_Cb *ctx = malloc(sizeof(Eldbus_Context_Free_Cb));
342    EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, lst);
343 
344    ctx->cb = cb;
345    ctx->data = data;
346 
347    return eina_inlist_append(lst, EINA_INLIST_GET(ctx));
348 }
349 
350 Eina_Inlist *
eldbus_cbs_free_del(Eina_Inlist * lst,Eldbus_Free_Cb cb,const void * data)351 eldbus_cbs_free_del(Eina_Inlist *lst, Eldbus_Free_Cb cb, const void *data)
352 {
353    Eldbus_Context_Free_Cb *ctx;
354 
355    EINA_INLIST_FOREACH(lst, ctx)
356      {
357         if (ctx->cb != cb) continue;
358         if ((data) && (ctx->data != data)) continue;
359 
360         lst = eina_inlist_remove(lst, EINA_INLIST_GET(ctx));
361         free(ctx);
362         return lst;
363      }
364 
365    ERR("Couldn't find cb_free=%p data=%p", cb, data);
366    return lst;
367 }
368 
369 typedef struct _Eldbus_Data
370 {
371    EINA_INLIST;
372    const void  *data;
373    unsigned int keylen;
374    char         key[];
375 } Eldbus_Data;
376 
377 static inline Eldbus_Data *
eldbus_data_find(Eina_Inlist ** p_lst,const char * key)378 eldbus_data_find(Eina_Inlist **p_lst, const char *key)
379 {
380    unsigned int keylen = strlen(key);
381    Eldbus_Data *d;
382 
383    EINA_INLIST_FOREACH(*p_lst, d)
384      {
385         if ((keylen == d->keylen) && (memcmp(key, d->key, keylen) == 0))
386           {
387              *p_lst = eina_inlist_promote(*p_lst, EINA_INLIST_GET(d));
388              return d;
389           }
390      }
391 
392    return NULL;
393 }
394 
395 void
eldbus_data_set(Eina_Inlist ** p_lst,const char * key,const void * data)396 eldbus_data_set(Eina_Inlist **p_lst, const char *key, const void *data)
397 {
398    Eldbus_Data *d = eldbus_data_find(p_lst, key);
399    unsigned int keylen = strlen(key);
400 
401    if (d)
402      {
403         *p_lst = eina_inlist_remove(*p_lst, EINA_INLIST_GET(d));
404         free(d);
405      }
406 
407    d = malloc(sizeof(Eldbus_Data) + keylen + 1);
408    EINA_SAFETY_ON_NULL_RETURN(d);
409 
410    d->data = data;
411    d->keylen = keylen;
412    memcpy(d->key, key, keylen + 1);
413 
414    *p_lst = eina_inlist_prepend(*p_lst, EINA_INLIST_GET(d));
415 }
416 
417 void *
eldbus_data_get(Eina_Inlist ** p_lst,const char * key)418 eldbus_data_get(Eina_Inlist **p_lst, const char *key)
419 {
420    Eldbus_Data *d = eldbus_data_find(p_lst, key);
421    return d ? (void *)d->data : NULL;
422 }
423 
424 void *
eldbus_data_del(Eina_Inlist ** p_lst,const char * key)425 eldbus_data_del(Eina_Inlist **p_lst, const char *key)
426 {
427    Eldbus_Data *d = eldbus_data_find(p_lst, key);
428    void *ret;
429    if (!d) return NULL;
430 
431    ret = (void *)d->data;
432    *p_lst = eina_inlist_remove(*p_lst, EINA_INLIST_GET(d));
433    free(d);
434 
435    return ret;
436 }
437 
438 void
eldbus_data_del_all(Eina_Inlist ** p_list)439 eldbus_data_del_all(Eina_Inlist **p_list)
440 {
441    Eina_Inlist *n = *p_list;
442    *p_list = NULL;
443 
444    while (n)
445      {
446         Eldbus_Data *d = EINA_INLIST_CONTAINER_GET(n, Eldbus_Data);
447         n = eina_inlist_remove(n, n);
448         DBG("key=%s, data=%p", d->key, d->data);
449         free(d);
450      }
451 }
452 
453 static void
eldbus_connection_name_gc(Eldbus_Connection * conn,Eldbus_Connection_Name * cn)454 eldbus_connection_name_gc(Eldbus_Connection *conn, Eldbus_Connection_Name *cn)
455 {
456    if (cn->refcount > 0)
457      return;
458    if (cn->objects && eina_hash_population(cn->objects) > 0)
459      return;
460    if (cn->event_handlers.list != NULL)
461      return;
462 
463    eina_hash_del(conn->names, cn->name, cn);
464    if (cn->name_owner_changed)
465      eldbus_signal_handler_del(cn->name_owner_changed);
466    if (cn->objects)
467      eina_hash_free(cn->objects);
468    eina_stringshare_del(cn->name);
469    if (cn->name_owner_get)
470      eldbus_pending_cancel(cn->name_owner_get);
471    if (cn->unique_id)
472      eina_stringshare_del(cn->unique_id);
473    eina_list_free(cn->event_handlers.to_delete);
474    free(cn);
475 }
476 
477 void
eldbus_connection_name_object_del(Eldbus_Connection * conn,const Eldbus_Object * obj)478 eldbus_connection_name_object_del(Eldbus_Connection *conn, const Eldbus_Object *obj)
479 {
480    Eldbus_Connection_Name *cn = eina_hash_find(conn->names, obj->name);
481 
482    if (!cn) return;
483    if (!cn->objects) return;
484    eina_hash_del(cn->objects, obj->path, obj);
485 
486    eldbus_connection_name_gc(conn, cn);
487 }
488 
489 void
eldbus_connection_name_object_set(Eldbus_Connection * conn,Eldbus_Object * obj)490 eldbus_connection_name_object_set(Eldbus_Connection *conn, Eldbus_Object *obj)
491 {
492    Eldbus_Connection_Name *cn;
493 
494    cn = eldbus_connection_name_get(conn, obj->name);
495    eina_hash_add(cn->objects, obj->path, obj);
496 
497    return;
498 }
499 
500 static void
on_name_owner_changed(void * data,const Eldbus_Message * msg)501 on_name_owner_changed(void *data, const Eldbus_Message *msg)
502 {
503    const char *bus, *older_id, *new_id;
504    Eldbus_Connection_Name *cn = data;
505 
506    if (!eldbus_message_arguments_get(msg, "sss", &bus, &older_id, &new_id))
507      {
508         ERR("Error getting arguments from NameOwnerChanged cn=%s", cn->name);
509         return;
510      }
511 
512    eina_stringshare_replace(&cn->unique_id, new_id);
513    eldbus_dispatch_name_owner_change(cn, older_id);
514 }
515 
516 static void
on_get_name_owner(void * data,const Eldbus_Message * msg,Eldbus_Pending * pending EINA_UNUSED)517 on_get_name_owner(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED)
518 {
519    const char *unique_id = "", *error_name;
520    Eldbus_Connection_Name *cn = data;
521 
522    cn->name_owner_get = NULL;
523 
524    if (eldbus_message_error_get(msg, &error_name, NULL))
525      {
526         if (!strcmp(error_name, ELDBUS_ERROR_PENDING_CANCELED))
527           return;
528         DBG("GetNameOwner of bus = %s returned an error", cn->name);
529      }
530    else if (!eldbus_message_arguments_get(msg, "s", &unique_id))
531      ERR("Error getting arguments from GetNameOwner");
532 
533    cn->unique_id = eina_stringshare_add(unique_id);
534    eldbus_dispatch_name_owner_change(cn, NULL);
535 }
536 
537 void
eldbus_connection_name_ref(Eldbus_Connection_Name * cn)538 eldbus_connection_name_ref(Eldbus_Connection_Name *cn)
539 {
540    EINA_SAFETY_ON_NULL_RETURN(cn);
541    cn->refcount++;
542 }
543 
544 void
eldbus_connection_name_unref(Eldbus_Connection * conn,Eldbus_Connection_Name * cn)545 eldbus_connection_name_unref(Eldbus_Connection *conn, Eldbus_Connection_Name *cn)
546 {
547    ELDBUS_CONNECTION_CHECK(conn);
548    EINA_SAFETY_ON_NULL_RETURN(cn);
549 
550    cn->refcount--;
551    eldbus_connection_name_gc(conn, cn);
552 }
553 
554 Eldbus_Connection_Name *
eldbus_connection_name_get(Eldbus_Connection * conn,const char * name)555 eldbus_connection_name_get(Eldbus_Connection *conn, const char *name)
556 {
557    Eldbus_Connection_Name *cn;
558    ELDBUS_CONNECTION_CHECK_RETVAL(conn, NULL);
559 
560    cn = eina_hash_find(conn->names, name);
561    if (cn) return cn;
562 
563    cn = calloc(1, sizeof(Eldbus_Connection_Name));
564    EINA_SAFETY_ON_NULL_RETURN_VAL(cn, NULL);
565    cn->name = eina_stringshare_add(name);
566    cn->objects = eina_hash_string_superfast_new(NULL);
567 
568    if (!strcmp(name, ELDBUS_FDO_BUS))
569      {
570         cn->unique_id = eina_stringshare_add(name);
571         goto end;
572      }
573 
574    if (name[0] == ':')
575      cn->unique_id = eina_stringshare_add(name);
576    else
577      cn->name_owner_get = eldbus_name_owner_get(conn, cn->name, on_get_name_owner, cn);
578 
579    cn->name_owner_changed = _eldbus_signal_handler_add(conn, ELDBUS_FDO_BUS,
580                                                       ELDBUS_FDO_PATH,
581                                                       ELDBUS_FDO_INTERFACE,
582                                                       "NameOwnerChanged",
583                                                       on_name_owner_changed, cn);
584    eldbus_signal_handler_match_extra_set(cn->name_owner_changed, "arg0",
585                                         cn->name, NULL);
586 
587 end:
588    eina_hash_direct_add(conn->names, cn->name, cn);
589    return cn;
590 }
591 
592 Eldbus_Object *
eldbus_connection_name_object_get(Eldbus_Connection * conn,const char * name,const char * path)593 eldbus_connection_name_object_get(Eldbus_Connection *conn, const char *name, const char *path)
594 {
595    Eldbus_Connection_Name *cn;
596 
597    ELDBUS_CONNECTION_CHECK_RETVAL(conn, NULL);
598    cn = eina_hash_find(conn->names, name);
599    if (!cn) return NULL;
600    if (!cn->objects) return NULL;
601    return eina_hash_find(cn->objects, path);
602 }
603 
604 static Eina_Bool
eldbus_fd_handler(void * data,Ecore_Fd_Handler * fd_handler)605 eldbus_fd_handler(void *data, Ecore_Fd_Handler *fd_handler)
606 {
607    Eldbus_Handler_Data *hd = data;
608    unsigned int condition = 0;
609 
610    DBG("Got Ecore_Fd_Handle@%p", fd_handler);
611 
612    if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ)) condition |= DBUS_WATCH_READABLE;
613    if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_WRITE)) condition |= DBUS_WATCH_WRITABLE;
614    if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_ERROR)) condition |= DBUS_WATCH_ERROR;
615 
616    DBG("dbus connection@%p fdh=%d flags: [%s%s%s]", hd->conn, hd->fd,
617        (condition & DBUS_WATCH_READABLE) ? "read " : "",
618        (condition & DBUS_WATCH_WRITABLE) ? "write " : "",
619        (condition & DBUS_WATCH_ERROR) ? "error" : "");
620 
621    dbus_watch_handle(hd->watch, condition);
622 
623    return ECORE_CALLBACK_RENEW;
624 }
625 
626 static void
eldbus_fd_handler_add(Eldbus_Handler_Data * hd)627 eldbus_fd_handler_add(Eldbus_Handler_Data *hd)
628 {
629    unsigned int dflags;
630    Ecore_Fd_Handler_Flags eflags;
631 
632    if (hd->fd_handler) return;
633    dflags = dbus_watch_get_flags(hd->watch);
634    eflags = ECORE_FD_ERROR;
635    if (dflags & DBUS_WATCH_READABLE) eflags |= ECORE_FD_READ;
636    if (dflags & DBUS_WATCH_WRITABLE) eflags |= ECORE_FD_WRITE;
637 
638    DBG("Watching fd %d with flags: [%s%serror]", hd->fd,
639       (eflags & ECORE_FD_READ) ? "read " : "",
640       (eflags & ECORE_FD_WRITE) ? "write " : "");
641 
642    hd->fd_handler = ecore_main_fd_handler_add(hd->fd,
643                                               eflags,
644                                               eldbus_fd_handler,
645                                               hd,
646                                               NULL,
647                                               NULL);
648 }
649 
650 static void
eldbus_handler_data_free(void * data)651 eldbus_handler_data_free(void *data)
652 {
653    Eldbus_Handler_Data *hd = data;
654    eldbus_fd_handler_del(hd);
655 }
656 
657 static dbus_bool_t
cb_watch_add(DBusWatch * watch,void * data)658 cb_watch_add(DBusWatch *watch, void *data)
659 {
660    Eldbus_Connection *conn = data;
661    Eldbus_Handler_Data *hd;
662 
663    if (!dbus_watch_get_enabled(watch)) return EINA_TRUE;
664 
665    DBG("cb_watch_add (enabled: %d)", dbus_watch_get_unix_fd(watch));
666 
667    hd = calloc(1, sizeof(Eldbus_Handler_Data));
668    EINA_SAFETY_ON_NULL_RETURN_VAL(hd, EINA_FALSE);
669    dbus_watch_set_data(watch, hd, eldbus_handler_data_free);
670    hd->conn = conn;
671    hd->watch = watch;
672    hd->enabled = dbus_watch_get_enabled(watch);
673    hd->fd = dbus_watch_get_unix_fd(hd->watch);
674 
675    conn->fd_handlers = eina_inlist_append(hd->conn->fd_handlers,
676                                           EINA_INLIST_GET(hd));
677    eldbus_fd_handler_add(hd);
678 
679    return EINA_TRUE;
680 }
681 
682 static void
cb_watch_del(DBusWatch * watch,void * data EINA_UNUSED)683 cb_watch_del(DBusWatch *watch, void *data EINA_UNUSED)
684 {
685    DBG("cb_watch_del");
686    /* will trigger eldbus_handler_data_free() */
687    dbus_watch_set_data(watch, NULL, NULL);
688 }
689 
690 static void
cb_watch_toggle(DBusWatch * watch,void * data EINA_UNUSED)691 cb_watch_toggle(DBusWatch *watch, void *data EINA_UNUSED)
692 {
693    Eldbus_Handler_Data *hd;
694    hd = dbus_watch_get_data(watch);
695    if (!hd) return;
696    DBG("cb_watch_toggle %d", hd->fd);
697 
698    hd->enabled = dbus_watch_get_enabled(watch);
699 
700    DBG("watch %p is %sabled", hd, hd->enabled ? "en" : "dis");
701    if (hd->enabled)
702      {
703         eldbus_fd_handler_add(hd);
704      }
705    else
706      {
707         ecore_main_fd_handler_del(hd->fd_handler);
708         hd->fd_handler = NULL;
709      }
710 }
711 
712 static void
eldbus_timeout_data_free(void * timeout_data)713 eldbus_timeout_data_free(void *timeout_data)
714 {
715    Eldbus_Timeout_Data *td = timeout_data;
716    td->conn->timeouts = eina_inlist_remove(td->conn->timeouts,
717                                            EINA_INLIST_GET(td));
718    DBG("Timeout -- freeing timeout_data %p", td);
719    if (td->handler) ecore_timer_del(td->handler);
720    free(td);
721 }
722 
723 static Eina_Bool
eldbus_timeout_handler(void * data)724 eldbus_timeout_handler(void *data)
725 {
726    Eldbus_Timeout_Data *td = data;
727    td->handler = NULL;
728 
729    if (!dbus_timeout_get_enabled(td->timeout))
730      {
731         DBG("timeout_handler (not enabled, ending)");
732         return ECORE_CALLBACK_CANCEL;
733      }
734 
735    DBG("Telling dbus to handle timeout with data %p", data);
736    dbus_timeout_handle(td->timeout);
737    return ECORE_CALLBACK_CANCEL;
738 }
739 
740 static dbus_bool_t
cb_timeout_add(DBusTimeout * timeout,void * data)741 cb_timeout_add(DBusTimeout *timeout, void *data)
742 {
743    Eldbus_Connection *conn = data;
744    Eldbus_Timeout_Data *td;
745 
746    if (!dbus_timeout_get_enabled(timeout))
747      return EINA_TRUE;
748 
749    DBG("Adding timeout for connection@%p", conn);
750    td = calloc(1, sizeof(Eldbus_Timeout_Data));
751    EINA_SAFETY_ON_NULL_RETURN_VAL(td, EINA_FALSE);
752    td->conn = conn;
753    dbus_timeout_set_data(timeout, (void *)td, eldbus_timeout_data_free);
754    td->interval = dbus_timeout_get_interval(timeout);
755    td->timeout = timeout;
756 
757    td->handler = ecore_timer_add(td->interval / 1000.0, eldbus_timeout_handler, td);
758    conn->timeouts = eina_inlist_append(conn->timeouts,
759                                        EINA_INLIST_GET(td));
760 
761    return EINA_TRUE;
762 }
763 
764 static void
cb_timeout_del(DBusTimeout * timeout,void * data EINA_UNUSED)765 cb_timeout_del(DBusTimeout *timeout, void *data EINA_UNUSED)
766 {
767    DBG("timeout del!");
768    /* will trigger eldbus_timeout_data_free() */
769    dbus_timeout_set_data(timeout, NULL, NULL);
770 }
771 
772 static void
cb_timeout_toggle(DBusTimeout * timeout,void * data EINA_UNUSED)773 cb_timeout_toggle(DBusTimeout *timeout, void *data EINA_UNUSED)
774 {
775    Eldbus_Timeout_Data *td;
776 
777    td = dbus_timeout_get_data(timeout);
778 
779    DBG("Timeout toggle; data@%p", td);
780    if (dbus_timeout_get_enabled(td->timeout))
781      {
782         td->interval = dbus_timeout_get_interval(timeout);
783         td->handler
784           = ecore_timer_add(td->interval, eldbus_timeout_handler, td);
785 
786         DBG("Timeout is enabled with interval %d, timer@%p",
787            td->interval, td->handler);
788      }
789    else
790      {
791         DBG("Timeout is disabled, destroying timer@%p", td->handler);
792         ecore_timer_del(td->handler);
793         td->handler = NULL;
794      }
795 }
796 
797 static Eina_Bool
eldbus_idle_enterer(void * data)798 eldbus_idle_enterer(void *data)
799 {
800    Eldbus_Connection *conn = data;
801 
802    DBG("Connection@%p: Dispatch status: %d", conn,
803        dbus_connection_get_dispatch_status(conn->dbus_conn));
804 
805    if (dbus_connection_get_dispatch_status(conn->dbus_conn) ==
806        DBUS_DISPATCH_COMPLETE)
807      {
808         DBG("Connection@%p: Dispatch complete, idle_enterer@%p finishing",
809             conn, conn->idle_enterer);
810         conn->idle_enterer = NULL;
811         return ECORE_CALLBACK_CANCEL;
812      }
813    DBG("Connection@%p: Dispatching", conn);
814    eldbus_init();
815    eldbus_connection_ref(conn);
816 
817    DBusDispatchStatus status;
818    do
819      {
820         status = dbus_connection_dispatch(conn->dbus_conn);
821      }
822    while(status == DBUS_DISPATCH_DATA_REMAINS);
823 
824    eldbus_connection_unref(conn);
825    eldbus_shutdown();
826    return ECORE_CALLBACK_RENEW;
827 }
828 
829 static void
cb_dispatch_status(DBusConnection * dbus_conn EINA_UNUSED,DBusDispatchStatus new_status,void * data)830 cb_dispatch_status(DBusConnection *dbus_conn EINA_UNUSED, DBusDispatchStatus new_status, void *data)
831 {
832    Eldbus_Connection *conn = data;
833 
834    if (!conn->refcount)
835      {
836         DBG("Connection[%p] being freed, dispatch blocked", conn);
837         return;
838      }
839 
840    DBG("Connection@%p: Dispatch status: %d", conn, new_status);
841 
842    if ((new_status == DBUS_DISPATCH_DATA_REMAINS) && (!conn->idle_enterer))
843      {
844         conn->idle_enterer = ecore_idle_enterer_add(eldbus_idle_enterer, conn);
845         DBG("Connection@%p: Adding idle_enterer@%p to handle remaining dispatch data",
846             conn, conn->idle_enterer);
847      }
848    else if ((new_status != DBUS_DISPATCH_DATA_REMAINS) && (conn->idle_enterer))
849      {
850         DBG("Connection@%p: No remaining dispatch data, clearing idle_enterer@%p",
851             conn, conn->idle_enterer);
852 
853         ecore_idle_enterer_del(conn->idle_enterer);
854         conn->idle_enterer = NULL;
855      }
856 }
857 
858 static inline Eina_Bool
extra_arguments_check(DBusMessage * msg,Eldbus_Signal_Handler * sh)859 extra_arguments_check(DBusMessage *msg, Eldbus_Signal_Handler *sh)
860 {
861    DBusMessageIter iter;
862    Signal_Argument *arg;
863    unsigned int arg_index = 0;
864 
865    dbus_message_iter_init(msg, &iter);
866    EINA_INLIST_FOREACH(sh->args, arg)
867      {
868         const char *arg_msg;
869         int type = 0;
870 
871         while((arg->index > arg_index) && dbus_message_iter_next(&iter))
872           arg_index++;
873 
874         if (arg_index != arg->index)
875           return EINA_FALSE;
876 
877         type = dbus_message_iter_get_arg_type(&iter);
878         if (!(type == 's' || type == 'o'))
879           return EINA_FALSE;
880 
881         dbus_message_iter_get_basic(&iter, &arg_msg);
882         if (strcmp(arg_msg, arg->value))
883           return EINA_FALSE;
884      }
885    return EINA_TRUE;
886 }
887 
888 static void
cb_signal_dispatcher(Eldbus_Connection * conn,DBusMessage * msg)889 cb_signal_dispatcher(Eldbus_Connection *conn, DBusMessage *msg)
890 {
891    Eldbus_Message *eldbus_msg;
892    Eina_Inlist *next;
893 
894    eldbus_msg = eldbus_message_new(EINA_FALSE);
895    EINA_SAFETY_ON_NULL_RETURN(eldbus_msg);
896 
897    eldbus_msg->dbus_msg = dbus_message_ref(msg);
898    dbus_message_iter_init(eldbus_msg->dbus_msg,
899                           &eldbus_msg->iterator->dbus_iterator);
900 
901    eldbus_connection_ref(conn);
902    eldbus_init();
903    /*
904     * Do the walking open-coded so we don't crash if a callback
905     * removes other signal handlers from the list and we don't own
906     * yet a reference to them.
907     */
908    next = conn->signal_handlers;
909    while (next != NULL)
910      {
911         Eldbus_Signal_Handler *sh;
912 
913         sh = EINA_INLIST_CONTAINER_GET(next, Eldbus_Signal_Handler);
914         next = next->next;
915 
916         if (sh->dangling) continue;
917         if (sh->sender)
918           {
919              if (sh->bus)
920                {
921                   if ((sh->bus->unique_id == NULL) ||
922                       (!sh->bus->unique_id[0]) ||
923                       (!dbus_message_has_sender(msg, sh->bus->unique_id)))
924                     continue;
925                }
926              else
927                if (!dbus_message_has_sender(msg, sh->sender)) continue;
928           }
929         if (sh->path && !dbus_message_has_path(msg, sh->path)) continue;
930         if (sh->interface && !dbus_message_has_interface(msg, sh->interface))
931           continue;
932         if (sh->member && !dbus_message_has_member(msg, sh->member)) continue;
933         if (!extra_arguments_check(msg, sh)) continue;
934 
935         eldbus_signal_handler_ref(sh);
936         sh->cb((void *)sh->cb_data, eldbus_msg);
937         /* update next signal handler because the list may have changed */
938         next = EINA_INLIST_GET(sh)->next;
939         eldbus_signal_handler_unref(sh);
940 
941         /*
942          * Rewind iterator so another signal handler matching the same signal
943          * can iterate over it.
944          */
945         dbus_message_iter_init(eldbus_msg->dbus_msg,
946                                &eldbus_msg->iterator->dbus_iterator);
947      }
948 
949    eldbus_message_unref(eldbus_msg);
950    eldbus_connection_unref(conn);
951    eldbus_shutdown();
952 }
953 
954 static DBusHandlerResult
eldbus_filter(DBusConnection * conn_dbus EINA_UNUSED,DBusMessage * message,void * user_data)955 eldbus_filter(DBusConnection *conn_dbus EINA_UNUSED, DBusMessage *message, void *user_data)
956 {
957    Eldbus_Connection *conn = user_data;
958 
959    DBG("Connection@%p Got message:\n"
960        "  Type: %s\n"
961        "  Path: %s\n"
962        "  Interface: %s\n"
963        "  Member: %s\n"
964        "  Sender: %s", conn,
965        dbus_message_type_to_string(dbus_message_get_type(message)),
966        dbus_message_get_path(message),
967        dbus_message_get_interface(message),
968        dbus_message_get_member(message),
969        dbus_message_get_sender(message));
970 
971    switch (dbus_message_get_type(message))
972      {
973       case DBUS_MESSAGE_TYPE_METHOD_CALL:
974         DBG("  Signature: %s", dbus_message_get_signature(message));
975         break;
976       case DBUS_MESSAGE_TYPE_METHOD_RETURN:
977       case DBUS_MESSAGE_TYPE_ERROR:
978         DBG("  Reply serial: %d", dbus_message_get_reply_serial(message));
979         break;
980       case DBUS_MESSAGE_TYPE_SIGNAL:
981         DBG("  Signature: %s", dbus_message_get_signature(message));
982         cb_signal_dispatcher(conn, message);
983         break;
984      }
985 
986    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
987 }
988 
989 static void
eldbus_connection_setup(Eldbus_Connection * conn)990 eldbus_connection_setup(Eldbus_Connection *conn)
991 {
992    DBG("Setting up connection %p", conn);
993 
994    /* connection_setup */
995    dbus_connection_set_exit_on_disconnect(conn->dbus_conn, EINA_FALSE);
996    dbus_connection_set_watch_functions(conn->dbus_conn,
997                                        cb_watch_add,
998                                        cb_watch_del,
999                                        cb_watch_toggle,
1000                                        conn,
1001                                        NULL);
1002 
1003    dbus_connection_set_timeout_functions(conn->dbus_conn,
1004                                          cb_timeout_add,
1005                                          cb_timeout_del,
1006                                          cb_timeout_toggle,
1007                                          conn,
1008                                          NULL);
1009 
1010    dbus_connection_set_dispatch_status_function(conn->dbus_conn,
1011                                                 cb_dispatch_status,
1012                                                 conn, NULL);
1013    dbus_connection_add_filter(conn->dbus_conn, eldbus_filter, conn, NULL);
1014 
1015    cb_dispatch_status(conn->dbus_conn,
1016                       dbus_connection_get_dispatch_status(conn->dbus_conn),
1017                       conn);
1018 }
1019 
1020 static void
_disconnected(void * data,const Eldbus_Message * msg EINA_UNUSED)1021 _disconnected(void *data, const Eldbus_Message *msg EINA_UNUSED)
1022 {
1023    Eldbus_Connection *conn = data;
1024    Ecore_Event_Signal_Exit *ev;
1025 
1026    _eldbus_connection_event_callback_call(
1027       conn, ELDBUS_CONNECTION_EVENT_DISCONNECTED, NULL);
1028    if (conn->type != ELDBUS_CONNECTION_TYPE_SESSION) return;
1029 
1030    ev = calloc(1, sizeof(Ecore_Event_Signal_Exit));
1031    if (!ev) return;
1032 
1033    ev->quit = EINA_TRUE;
1034    ecore_event_add(ECORE_EVENT_SIGNAL_EXIT, ev, NULL, NULL);
1035 }
1036 
1037 /* Param address is only used for ELDBUS_CONNECTION_TYPE_ADDRESS type */
1038 static Eldbus_Connection *
_connection_get(Eldbus_Connection_Type type,const char * address,Eina_Bool shared)1039 _connection_get(Eldbus_Connection_Type type, const char *address, Eina_Bool shared)
1040 {
1041    Eldbus_Connection *conn;
1042    DBusError err;
1043    Eldbus_Object *obj;
1044 
1045    EINA_SAFETY_ON_FALSE_RETURN_VAL((type < ELDBUS_CONNECTION_TYPE_LAST) &&
1046                                    (type > ELDBUS_CONNECTION_TYPE_UNKNOWN), NULL);
1047    EINA_SAFETY_ON_TRUE_RETURN_VAL((type == ELDBUS_CONNECTION_TYPE_ADDRESS) &&
1048                                   (address == NULL), NULL);
1049 
1050    conn = calloc(1, sizeof(Eldbus_Connection));
1051    EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
1052 
1053    dbus_error_init(&err);
1054    if (type == ELDBUS_CONNECTION_TYPE_ADDRESS)
1055       conn->dbus_conn = dbus_connection_open_private(address, &err);
1056    else
1057       conn->dbus_conn = dbus_bus_get_private(type - 1, &err);
1058 
1059    if (!conn->dbus_conn || dbus_error_is_set(&err))
1060      {
1061         free(conn);
1062         ERR("Error connecting to bus of type %d. error name: %s error message: %s",
1063             type, err.name, err.message);
1064         return NULL;
1065      }
1066 
1067    if (type == ELDBUS_CONNECTION_TYPE_ADDRESS &&
1068        !dbus_bus_register(conn->dbus_conn, &err))
1069      {
1070         dbus_connection_close(conn->dbus_conn);
1071         dbus_connection_unref(conn->dbus_conn);
1072         conn->dbus_conn = NULL;
1073         free(conn);
1074         ERR("Error registering with bus: %s", err.message);
1075         return NULL;
1076      }
1077 
1078    conn->type = type;
1079    conn->refcount = 1;
1080    conn->shared = !!shared;
1081    EINA_MAGIC_SET(conn, ELDBUS_CONNECTION_MAGIC);
1082    conn->names = eina_hash_string_superfast_new(NULL);
1083    eldbus_connection_setup(conn);
1084 
1085    eldbus_signal_handler_add(conn, NULL, DBUS_PATH_LOCAL, DBUS_INTERFACE_LOCAL,
1086                              "Disconnected", _disconnected, conn);
1087    obj = eldbus_object_get(conn, ELDBUS_FDO_BUS, ELDBUS_FDO_PATH);
1088    conn->fdo_proxy = eldbus_proxy_get(obj, ELDBUS_FDO_INTERFACE);
1089 
1090    DBG("Returned new connection at %p", conn);
1091    return conn;
1092 }
1093 
1094 EAPI Eldbus_Connection *
eldbus_private_connection_get(Eldbus_Connection_Type type)1095 eldbus_private_connection_get(Eldbus_Connection_Type type)
1096 {
1097    DBG("Getting private connection with type %d", type);
1098    return _connection_get(type, NULL, EINA_FALSE);
1099 }
1100 
1101 EAPI Eldbus_Connection *
eldbus_connection_get(Eldbus_Connection_Type type)1102 eldbus_connection_get(Eldbus_Connection_Type type)
1103 {
1104    Eldbus_Connection *conn;
1105 
1106    DBG("Getting connection with type %d", type);
1107 
1108    if (!type)
1109      return NULL;
1110 
1111    if (type == ELDBUS_CONNECTION_TYPE_ADDRESS)
1112      {
1113         ERR("CONNECTION_TYPE_ADDRESS must be used with appropriate address_connection_get() function");
1114         return NULL;
1115      }
1116 
1117    conn = (Eldbus_Connection *) shared_connections[type - 1];
1118    if (conn)
1119      {
1120         DBG("Connection with type %d exists at %p; reffing and returning",
1121             type, conn);
1122         return eldbus_connection_ref(conn);
1123      }
1124 
1125    conn = _connection_get(type, NULL, EINA_TRUE);
1126    EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
1127    shared_connections[type - 1] = conn;
1128 
1129    return conn;
1130 }
1131 
1132 EAPI Eldbus_Connection *
eldbus_address_connection_get(const char * address)1133 eldbus_address_connection_get(const char *address)
1134 {
1135    Eldbus_Connection *conn = NULL;
1136 
1137    DBG("Getting connection with address %s", address);
1138 
1139    if (address_connections == NULL)
1140      {
1141         address_connections = eina_hash_string_small_new(NULL);
1142         shared_connections[ELDBUS_CONNECTION_TYPE_ADDRESS - 1] = address_connections;
1143      }
1144    else
1145      {
1146         conn = (Eldbus_Connection *) eina_hash_find(address_connections, address);
1147      }
1148 
1149    if (conn != NULL)
1150      {
1151         DBG("Connection with address %s exists at %p; reffing and returning",
1152             address, conn);
1153         return eldbus_connection_ref(conn);
1154      }
1155 
1156    conn = _connection_get(ELDBUS_CONNECTION_TYPE_ADDRESS, address, EINA_TRUE);
1157    EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
1158    eina_hash_add(address_connections, address, conn);
1159 
1160    return conn;
1161 }
1162 
1163 EAPI Eldbus_Connection *
eldbus_private_address_connection_get(const char * address)1164 eldbus_private_address_connection_get(const char *address)
1165 {
1166    DBG("Getting private connection with address %s", address);
1167    return _connection_get(ELDBUS_CONNECTION_TYPE_ADDRESS, address, EINA_FALSE);
1168 }
1169 
1170 EAPI Eldbus_Connection *
eldbus_connection_ref(Eldbus_Connection * conn)1171 eldbus_connection_ref(Eldbus_Connection *conn)
1172 {
1173    ELDBUS_CONNECTION_CHECK_RETVAL(conn, NULL);
1174    DBG("conn=%p, pre-refcount=%d", conn, conn->refcount);
1175    conn->refcount++;
1176    return conn;
1177 }
1178 
1179 static void
_eldbus_connection_free(Eldbus_Connection * conn)1180 _eldbus_connection_free(Eldbus_Connection *conn)
1181 {
1182    unsigned int i;
1183    Eldbus_Handler_Data *fd_handler;
1184    Eldbus_Timeout_Data *timer;
1185    Eina_Inlist *list;
1186    Eldbus_Signal_Handler *h;
1187    Eldbus_Pending *p;
1188    Eina_Iterator *iter;
1189    Eldbus_Connection_Name *cn;
1190    Eina_Array *cns;
1191    const char *name;
1192 
1193    DBG("Freeing connection %p", conn);
1194 
1195    _eldbus_connection_event_callback_call
1196      (conn, ELDBUS_CONNECTION_EVENT_DEL, NULL);
1197 
1198    conn->refcount = 1;
1199    eldbus_cbs_free_dispatch(&(conn->cbs_free), conn);
1200 
1201    /**
1202     * Flush all messages in outgoing queue, also this will send all
1203     * ObjectManager and Property changed signals of all paths that
1204     * this connection is server.
1205     */
1206    dbus_connection_flush(conn->dbus_conn);
1207 
1208    EINA_INLIST_FOREACH_SAFE(conn->pendings, list, p)
1209      eldbus_pending_cancel(p);
1210 
1211    cns = eina_array_new(eina_hash_population(conn->names));
1212    iter = eina_hash_iterator_data_new(conn->names);
1213    EINA_ITERATOR_FOREACH(iter, cn)
1214      {
1215         while (cn->event_handlers.list)
1216           {
1217              Eldbus_Connection_Context_NOC_Cb *ctx;
1218              ctx = EINA_INLIST_CONTAINER_GET(cn->event_handlers.list,
1219                                              Eldbus_Connection_Context_NOC_Cb);
1220              cn->event_handlers.list = eina_inlist_remove(cn->event_handlers.list,
1221                                                           cn->event_handlers.list);
1222              free(ctx);
1223           }
1224         eina_array_push(cns, eina_stringshare_add(cn->name));
1225      }
1226    eina_iterator_free(iter);
1227 
1228    while ((name = eina_array_pop(cns)))
1229      {
1230         cn = eina_hash_find(conn->names, name);
1231         if (cn) eldbus_connection_name_gc(conn, cn);
1232         eina_stringshare_del(name);
1233      }
1234 
1235    eina_hash_free(conn->names);
1236    eina_array_free(cns);
1237 
1238    conn->refcount = 0;
1239 
1240    /* after cbs_free dispatch these shouldn't exit, error if they do */
1241 
1242    if (conn->pendings)
1243      {
1244         CRI("Connection %p released with live pending calls!",
1245                  conn);
1246         EINA_INLIST_FOREACH(conn->pendings, p)
1247           ERR("conn=%p alive pending call=%p dest=%s path=%s %s.%s()", conn, p,
1248               eldbus_pending_destination_get(p),
1249               eldbus_pending_path_get(p),
1250               eldbus_pending_interface_get(p),
1251               eldbus_pending_method_get(p));
1252      }
1253 
1254    if (conn->signal_handlers)
1255      {
1256         CRI("Connection %p released with live signal handlers!", conn);
1257         EINA_INLIST_FOREACH(conn->signal_handlers, h)
1258           ERR("conn=%p alive signal=%p %s.%s path=%s", conn, h, h->interface,
1259               h->member, h->path);
1260      }
1261 
1262    for (i = 0; i < ELDBUS_CONNECTION_EVENT_LAST; i++)
1263      {
1264         Eldbus_Connection_Context_Event *ce = conn->event_handlers + i;
1265         while (ce->list)
1266           {
1267              Eldbus_Connection_Context_Event_Cb *ctx;
1268 
1269              ctx = EINA_INLIST_CONTAINER_GET(ce->list,
1270                                              Eldbus_Connection_Context_Event_Cb);
1271              _eldbus_connection_context_event_cb_del(ce, ctx);
1272           }
1273         eina_list_free(ce->to_delete);
1274      }
1275 
1276    EINA_MAGIC_SET(conn, EINA_MAGIC_NONE);
1277    //will trigger a cb_dispatch_status()
1278    dbus_connection_close(conn->dbus_conn);
1279    dbus_connection_unref(conn->dbus_conn);
1280    conn->dbus_conn = NULL;
1281 
1282    EINA_INLIST_FOREACH_SAFE(conn->fd_handlers, list, fd_handler)
1283      eldbus_fd_handler_del(fd_handler);
1284 
1285    EINA_INLIST_FOREACH_SAFE(conn->timeouts, list, timer)
1286      eldbus_timeout_data_free(timer->handler);
1287 
1288    eldbus_data_del_all(&conn->data);
1289 
1290    if (conn->idle_enterer) ecore_idle_enterer_del(conn->idle_enterer);
1291    if (conn->type && conn->shared)
1292      {
1293         if (conn->type == ELDBUS_CONNECTION_TYPE_ADDRESS)
1294            {
1295               if (address_connections)
1296                 eina_hash_del_by_data(address_connections, conn);
1297            }
1298         else if (shared_connections[conn->type - 1] == (void *) conn)
1299            shared_connections[conn->type - 1] = NULL;
1300      }
1301 
1302    free(conn);
1303 }
1304 
1305 EAPI void
eldbus_connection_unref(Eldbus_Connection * conn)1306 eldbus_connection_unref(Eldbus_Connection *conn)
1307 {
1308    ELDBUS_CONNECTION_CHECK(conn);
1309    DBG("conn=%p, pre-refcount=%d", conn, conn->refcount);
1310    if (--conn->refcount > 0)
1311       return;
1312    _eldbus_connection_free(conn);
1313 }
1314 
1315 EAPI void
eldbus_connection_free_cb_add(Eldbus_Connection * conn,Eldbus_Free_Cb cb,const void * data)1316 eldbus_connection_free_cb_add(Eldbus_Connection *conn, Eldbus_Free_Cb cb, const void *data)
1317 {
1318    ELDBUS_CONNECTION_CHECK(conn);
1319    EINA_SAFETY_ON_NULL_RETURN(cb);
1320    conn->cbs_free = eldbus_cbs_free_add(conn->cbs_free, cb, data);
1321 }
1322 
1323 EAPI void
eldbus_connection_free_cb_del(Eldbus_Connection * conn,Eldbus_Free_Cb cb,const void * data)1324 eldbus_connection_free_cb_del(Eldbus_Connection *conn, Eldbus_Free_Cb cb, const void *data)
1325 {
1326    ELDBUS_CONNECTION_CHECK(conn);
1327    EINA_SAFETY_ON_NULL_RETURN(cb);
1328    conn->cbs_free = eldbus_cbs_free_del(conn->cbs_free, cb, data);
1329 }
1330 
1331 EAPI void
eldbus_connection_data_set(Eldbus_Connection * conn,const char * key,const void * data)1332 eldbus_connection_data_set(Eldbus_Connection *conn, const char *key, const void *data)
1333 {
1334    ELDBUS_CONNECTION_CHECK(conn);
1335    EINA_SAFETY_ON_NULL_RETURN(key);
1336    EINA_SAFETY_ON_NULL_RETURN(data);
1337    eldbus_data_set(&(conn->data), key, data);
1338 }
1339 
1340 EAPI void *
eldbus_connection_data_get(const Eldbus_Connection * conn,const char * key)1341 eldbus_connection_data_get(const Eldbus_Connection *conn, const char *key)
1342 {
1343    ELDBUS_CONNECTION_CHECK_RETVAL(conn, NULL);
1344    EINA_SAFETY_ON_NULL_RETURN_VAL(key, NULL);
1345    return eldbus_data_get(&(((Eldbus_Connection *)conn)->data), key);
1346 }
1347 
1348 EAPI void *
eldbus_connection_data_del(Eldbus_Connection * conn,const char * key)1349 eldbus_connection_data_del(Eldbus_Connection *conn, const char *key)
1350 {
1351    ELDBUS_CONNECTION_CHECK_RETVAL(conn, NULL);
1352    EINA_SAFETY_ON_NULL_RETURN_VAL(key, NULL);
1353    return eldbus_data_del(&(((Eldbus_Connection *)conn)->data), key);
1354 }
1355 
1356 static void
eldbus_dispatch_name_owner_change(Eldbus_Connection_Name * cn,const char * old_id)1357 eldbus_dispatch_name_owner_change(Eldbus_Connection_Name *cn, const char *old_id)
1358 {
1359    Eldbus_Connection_Context_NOC_Cb *ctx;
1360    const char *previous_id = !old_id ? "" : old_id;
1361    cn->event_handlers.walking++;
1362    EINA_INLIST_FOREACH(cn->event_handlers.list, ctx)
1363      {
1364         if (ctx->deleted) continue;
1365         if (!old_id && !ctx->allow_initial)
1366           continue;
1367         ctx->cb((void *)ctx->cb_data, cn->name, previous_id, cn->unique_id);
1368      }
1369    cn->event_handlers.walking--;
1370    EINA_LIST_FREE(cn->event_handlers.to_delete, ctx)
1371      {
1372         cn->event_handlers.list = eina_inlist_remove(cn->event_handlers.list,
1373                                                      EINA_INLIST_GET(ctx));
1374         free(ctx);
1375      }
1376    eldbus_connection_name_gc(cn->name_owner_changed->conn, cn);
1377 }
1378 
1379 typedef struct _dispach_name_owner_data
1380 {
1381    Eldbus_Connection_Context_NOC_Cb *ctx;
1382    const Eldbus_Connection_Name *cn;
1383 } dispatch_name_owner_data;
1384 
1385 static Eina_Bool
dispach_name_owner_cb(void * context)1386 dispach_name_owner_cb(void *context)
1387 {
1388    dispatch_name_owner_data *data = context;
1389    data->ctx->cb((void *)data->ctx->cb_data, data->cn->name, "",
1390                  data->cn->unique_id);
1391    data->ctx->idle_enterer = NULL;
1392    free(data);
1393    return ECORE_CALLBACK_CANCEL;
1394 }
1395 
1396 EAPI void
eldbus_name_owner_changed_callback_add(Eldbus_Connection * conn,const char * bus,Eldbus_Name_Owner_Changed_Cb cb,const void * cb_data,Eina_Bool allow_initial_call)1397 eldbus_name_owner_changed_callback_add(Eldbus_Connection *conn, const char *bus, Eldbus_Name_Owner_Changed_Cb cb, const void *cb_data, Eina_Bool allow_initial_call)
1398 {
1399    Eldbus_Connection_Name *cn;
1400    Eldbus_Connection_Context_NOC_Cb *ctx;
1401 
1402    ELDBUS_CONNECTION_CHECK(conn);
1403    EINA_SAFETY_ON_NULL_RETURN(bus);
1404    EINA_SAFETY_ON_NULL_RETURN(cb);
1405 
1406    cn = eldbus_connection_name_get(conn, bus);
1407    EINA_SAFETY_ON_NULL_RETURN(cn);
1408    ctx = calloc(1, sizeof(Eldbus_Connection_Context_NOC_Cb));
1409    EINA_SAFETY_ON_NULL_GOTO(ctx, cleanup);
1410    ctx->cb = cb;
1411    ctx->cb_data = cb_data;
1412    ctx->allow_initial = allow_initial_call;
1413 
1414    cn->event_handlers.list = eina_inlist_append(cn->event_handlers.list,
1415                                                 EINA_INLIST_GET(ctx));
1416    if (cn->unique_id && allow_initial_call)
1417      {
1418         dispatch_name_owner_data *dispatch_data;
1419         dispatch_data = malloc(sizeof(dispatch_name_owner_data));
1420         EINA_SAFETY_ON_NULL_RETURN(dispatch_data);
1421         dispatch_data->cn = cn;
1422         dispatch_data->ctx = ctx;
1423         ctx->idle_enterer = ecore_idle_enterer_add(dispach_name_owner_cb, dispatch_data);
1424      }
1425    return;
1426 
1427 cleanup:
1428    eldbus_connection_name_gc(conn, cn);
1429 }
1430 
1431 EAPI void
eldbus_name_owner_changed_callback_del(Eldbus_Connection * conn,const char * bus,Eldbus_Name_Owner_Changed_Cb cb,const void * cb_data)1432 eldbus_name_owner_changed_callback_del(Eldbus_Connection *conn, const char *bus, Eldbus_Name_Owner_Changed_Cb cb, const void *cb_data)
1433 {
1434    Eldbus_Connection_Name *cn;
1435    Eldbus_Connection_Context_NOC_Cb *iter, *found = NULL;
1436 
1437    ELDBUS_CONNECTION_CHECK(conn);
1438    EINA_SAFETY_ON_NULL_RETURN(bus);
1439    EINA_SAFETY_ON_NULL_RETURN(cb);
1440 
1441    cn = eina_hash_find(conn->names, bus);
1442    EINA_SAFETY_ON_NULL_RETURN(cn);
1443 
1444    EINA_INLIST_FOREACH(cn->event_handlers.list, iter)
1445      {
1446         if (cb != iter->cb) continue;
1447         if ((cb_data) && (cb_data != iter->cb_data)) continue;
1448 
1449         found = iter;
1450         break;
1451      }
1452 
1453    EINA_SAFETY_ON_NULL_RETURN(found);
1454    EINA_SAFETY_ON_TRUE_RETURN(found->deleted);
1455 
1456    if (cn->event_handlers.walking)
1457      {
1458         found->deleted = EINA_TRUE;
1459         cn->event_handlers.to_delete = eina_list_append
1460             (cn->event_handlers.to_delete, found);
1461         return;
1462      }
1463 
1464    cn->event_handlers.list = eina_inlist_remove(cn->event_handlers.list,
1465                                                 EINA_INLIST_GET(found));
1466    if (found->idle_enterer)
1467      {
1468         dispatch_name_owner_data *data;
1469         data = ecore_idle_enterer_del(found->idle_enterer);
1470         free(data);
1471      }
1472    free(found);
1473    eldbus_connection_name_gc(conn, cn);
1474 }
1475 
1476 EAPI void
eldbus_connection_event_callback_add(Eldbus_Connection * conn,Eldbus_Connection_Event_Type type,Eldbus_Connection_Event_Cb cb,const void * cb_data)1477 eldbus_connection_event_callback_add(Eldbus_Connection *conn, Eldbus_Connection_Event_Type type, Eldbus_Connection_Event_Cb cb, const void *cb_data)
1478 {
1479    Eldbus_Connection_Context_Event *ce;
1480    Eldbus_Connection_Context_Event_Cb *ctx;
1481 
1482    ELDBUS_CONNECTION_CHECK(conn);
1483    EINA_SAFETY_ON_NULL_RETURN(cb);
1484    EINA_SAFETY_ON_TRUE_RETURN(type >= ELDBUS_CONNECTION_EVENT_LAST);
1485 
1486    ce = conn->event_handlers + type;
1487 
1488    ctx = calloc(1, sizeof(Eldbus_Connection_Context_Event_Cb));
1489    EINA_SAFETY_ON_NULL_RETURN(ctx);
1490    ctx->cb = cb;
1491    ctx->cb_data = cb_data;
1492 
1493    ce->list = eina_inlist_append(ce->list, EINA_INLIST_GET(ctx));
1494 }
1495 
1496 static void
_eldbus_connection_context_event_cb_del(Eldbus_Connection_Context_Event * ce,Eldbus_Connection_Context_Event_Cb * ctx)1497 _eldbus_connection_context_event_cb_del(Eldbus_Connection_Context_Event *ce, Eldbus_Connection_Context_Event_Cb *ctx)
1498 {
1499    ce->list = eina_inlist_remove(ce->list, EINA_INLIST_GET(ctx));
1500    free(ctx);
1501 }
1502 
1503 EAPI void
eldbus_connection_event_callback_del(Eldbus_Connection * conn,Eldbus_Connection_Event_Type type,Eldbus_Connection_Event_Cb cb,const void * cb_data)1504 eldbus_connection_event_callback_del(Eldbus_Connection *conn, Eldbus_Connection_Event_Type type, Eldbus_Connection_Event_Cb cb, const void *cb_data)
1505 {
1506    Eldbus_Connection_Context_Event *ce;
1507    Eldbus_Connection_Context_Event_Cb *iter, *found = NULL;
1508 
1509    ELDBUS_CONNECTION_CHECK(conn);
1510    EINA_SAFETY_ON_NULL_RETURN(cb);
1511    EINA_SAFETY_ON_TRUE_RETURN(type >= ELDBUS_CONNECTION_EVENT_LAST);
1512 
1513    ce = conn->event_handlers + type;
1514 
1515    EINA_INLIST_FOREACH(ce->list, iter)
1516      {
1517         if (cb != iter->cb) continue;
1518         if ((cb_data) && (cb_data != iter->cb_data)) continue;
1519 
1520         found = iter;
1521         break;
1522      }
1523 
1524    EINA_SAFETY_ON_NULL_RETURN(found);
1525    EINA_SAFETY_ON_TRUE_RETURN(found->deleted);
1526 
1527    if (ce->walking)
1528      {
1529         found->deleted = EINA_TRUE;
1530         ce->to_delete = eina_list_append(ce->to_delete, found);
1531         return;
1532      }
1533 
1534    _eldbus_connection_context_event_cb_del(ce, found);
1535 }
1536 
1537 static void
_eldbus_connection_event_callback_call(Eldbus_Connection * conn,Eldbus_Connection_Event_Type type,const void * event_info)1538 _eldbus_connection_event_callback_call(Eldbus_Connection *conn, Eldbus_Connection_Event_Type type, const void *event_info)
1539 {
1540    Eldbus_Connection_Context_Event *ce;
1541    Eldbus_Connection_Context_Event_Cb *iter;
1542 
1543    ce = conn->event_handlers + type;
1544 
1545    ce->walking++;
1546    EINA_INLIST_FOREACH(ce->list, iter)
1547      {
1548         if (iter->deleted) continue;
1549         iter->cb((void *)iter->cb_data, conn, (void *)event_info);
1550      }
1551    ce->walking--;
1552    if (ce->walking > 0) return;
1553 
1554    EINA_LIST_FREE(ce->to_delete, iter)
1555      _eldbus_connection_context_event_cb_del(ce, iter);
1556 }
1557 
1558 void
eldbus_connection_event_callback_call(Eldbus_Connection * conn,Eldbus_Connection_Event_Type type,const void * event_info)1559 eldbus_connection_event_callback_call(Eldbus_Connection *conn, Eldbus_Connection_Event_Type type, const void *event_info)
1560 {
1561    ELDBUS_CONNECTION_CHECK(conn);
1562    EINA_SAFETY_ON_TRUE_RETURN(type >= ELDBUS_CONNECTION_EVENT_LAST);
1563    EINA_SAFETY_ON_TRUE_RETURN(type == ELDBUS_CONNECTION_EVENT_DEL);
1564 
1565    _eldbus_connection_event_callback_call(conn, type, event_info);
1566 }
1567 
1568 void
eldbus_connection_signal_handler_add(Eldbus_Connection * conn,Eldbus_Signal_Handler * handler)1569 eldbus_connection_signal_handler_add(Eldbus_Connection *conn, Eldbus_Signal_Handler *handler)
1570 {
1571    ELDBUS_CONNECTION_CHECK(conn);
1572    EINA_SAFETY_ON_NULL_RETURN(handler);
1573    conn->signal_handlers = eina_inlist_append(conn->signal_handlers,
1574                                               EINA_INLIST_GET(handler));
1575 }
1576 
1577 void
eldbus_connection_pending_add(Eldbus_Connection * conn,Eldbus_Pending * pending)1578 eldbus_connection_pending_add(Eldbus_Connection *conn, Eldbus_Pending *pending)
1579 {
1580    ELDBUS_CONNECTION_CHECK(conn);
1581    EINA_SAFETY_ON_NULL_RETURN(pending);
1582    conn->pendings = eina_inlist_append(conn->pendings,
1583                                        EINA_INLIST_GET(pending));
1584 }
1585 
1586 void
eldbus_connection_signal_handler_del(Eldbus_Connection * conn,Eldbus_Signal_Handler * handler)1587 eldbus_connection_signal_handler_del(Eldbus_Connection *conn, Eldbus_Signal_Handler *handler)
1588 {
1589    EINA_SAFETY_ON_NULL_RETURN(conn);
1590    EINA_SAFETY_ON_NULL_RETURN(handler);
1591    conn->signal_handlers = eina_inlist_remove(conn->signal_handlers,
1592                                               EINA_INLIST_GET(handler));
1593 }
1594 
1595 void
eldbus_connection_pending_del(Eldbus_Connection * conn,Eldbus_Pending * pending)1596 eldbus_connection_pending_del(Eldbus_Connection *conn, Eldbus_Pending *pending)
1597 {
1598    EINA_SAFETY_ON_NULL_RETURN(conn);
1599    EINA_SAFETY_ON_NULL_RETURN(pending);
1600    conn->pendings = eina_inlist_remove(conn->pendings,
1601                                        EINA_INLIST_GET(pending));
1602 }
1603 
1604 const char *
eldbus_connection_unique_name_get(Eldbus_Connection * conn)1605 eldbus_connection_unique_name_get(Eldbus_Connection *conn)
1606 {
1607    ELDBUS_CONNECTION_CHECK_RETVAL(conn, NULL);
1608    return dbus_bus_get_unique_name(conn->dbus_conn);
1609 }
1610