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