Imported Upstream version 1.7.5
[platform/upstream/edbus.git] / src / lib / dbus / e_dbus.c
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <string.h>
8 #include <stdbool.h>
9
10 #ifdef HAVE_EVIL
11 # include <Evil.h>
12 #endif
13
14 #include "e_dbus_private.h"
15
16 static E_DBus_Version _version = { VMAJ, VMIN, VMIC, VREV };
17 EAPI E_DBus_Version *e_dbus_version = &_version;
18
19 #define NUM_BUS_TYPES 3
20
21 /*
22  * TODO: 
23  *  listen for disconnected signal and clean up?
24  */
25 int _e_dbus_log_dom = -1;
26 static int connection_slot = -1;
27
28 static int _edbus_init_count = 0;
29 static int close_connection = 0;
30 EAPI int E_DBUS_DOMAIN_GLOBAL = 0;
31 EAPI int E_DBUS_EVENT_SIGNAL = 0;
32
33 static E_DBus_Connection *shared_connections[2] = {NULL, NULL};
34
35 typedef struct E_DBus_Handler_Data E_DBus_Handler_Data;
36 typedef struct E_DBus_Timeout_Data E_DBus_Timeout_Data;
37
38
39 struct E_DBus_Handler_Data
40 {
41   int fd;
42   Ecore_Fd_Handler *fd_handler;
43   E_DBus_Connection *cd;
44   DBusWatch *watch;
45   int enabled;
46 };
47
48 struct E_DBus_Timeout_Data
49 {
50   Ecore_Timer *handler;
51   DBusTimeout *timeout;
52   E_DBus_Connection *cd;
53   int interval;
54 };
55
56 static Eina_Bool e_dbus_idler(void *data);
57
58 static void
59 e_dbus_fd_handler_del(E_DBus_Handler_Data *hd)
60 {
61   if (!hd->fd_handler) return;
62
63   DBG("handler disabled");
64   hd->cd->fd_handlers = eina_list_remove(hd->cd->fd_handlers, hd->fd_handler);
65   ecore_main_fd_handler_del(hd->fd_handler);
66   hd->fd_handler = NULL;
67 }
68
69 static Eina_Bool
70 e_dbus_fd_handler(void *data, Ecore_Fd_Handler *fd_handler)
71 {
72   E_DBus_Handler_Data *hd;
73   unsigned int condition = 0;
74
75   DBG("fd handler (%p)!", fd_handler);
76
77   hd = data;
78
79   if (!hd->enabled)
80     {
81        e_dbus_fd_handler_del(hd);
82        return ECORE_CALLBACK_CANCEL;
83     }
84   if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ)) condition |= DBUS_WATCH_READABLE;
85   if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_WRITE)) condition |= DBUS_WATCH_WRITABLE;
86   if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_ERROR)) condition |= DBUS_WATCH_ERROR;
87   DBG("fdh || READ: %d, WRITE: %d",
88       (condition & DBUS_WATCH_READABLE) == DBUS_WATCH_READABLE,
89       (condition & DBUS_WATCH_WRITABLE) == DBUS_WATCH_WRITABLE);
90
91   if (condition & DBUS_WATCH_ERROR) DBG("DBUS watch error");
92   dbus_watch_handle(hd->watch, condition);
93   hd = NULL;
94
95   return ECORE_CALLBACK_RENEW;
96 }
97
98 static void
99 e_dbus_fd_handler_add(E_DBus_Handler_Data *hd)
100 {
101   unsigned int dflags;
102   Ecore_Fd_Handler_Flags eflags;
103   Eina_List *l;
104   Ecore_Fd_Handler *fdh;
105
106   if (hd->fd_handler) return;
107   dflags = dbus_watch_get_flags(hd->watch);
108   eflags = ECORE_FD_ERROR;
109   if (dflags & DBUS_WATCH_READABLE) eflags |= ECORE_FD_READ;
110   if (dflags & DBUS_WATCH_WRITABLE) eflags |= ECORE_FD_WRITE;
111
112   EINA_LIST_FOREACH(hd->cd->fd_handlers, l, fdh)
113     {
114        if (ecore_main_fd_handler_fd_get(fdh) == hd->fd) return;
115     }
116
117   DBG("fd handler add (%d)", hd->fd);
118   hd->fd_handler = ecore_main_fd_handler_add(hd->fd,
119                                              eflags,
120                                              e_dbus_fd_handler,
121                                              hd,
122                                              NULL,
123                                              NULL);
124
125   hd->cd->fd_handlers = eina_list_append(hd->cd->fd_handlers, hd->fd_handler);
126 }
127
128
129 static void
130 e_dbus_handler_data_free(void *data)
131 {
132   E_DBus_Handler_Data *hd = data;
133   
134   DBG("e_dbus_handler_data_free");
135   if (hd->fd_handler)
136   {
137     hd->cd->fd_handlers = eina_list_remove(hd->cd->fd_handlers, hd->fd_handler);
138     ecore_main_fd_handler_del(hd->fd_handler);
139   }
140   free(hd);
141 }
142
143 static void
144 e_dbus_connection_data_watch_add(E_DBus_Connection *cd, DBusWatch *watch)
145 {
146   E_DBus_Handler_Data *hd;
147
148   hd = calloc(1, sizeof(E_DBus_Handler_Data));
149   dbus_watch_set_data(watch, hd, e_dbus_handler_data_free);
150   hd->cd = cd;
151   hd->watch = watch;
152
153   hd->enabled = dbus_watch_get_enabled(watch);
154 #if (DBUS_VERSION_MAJOR == 1 && DBUS_VERSION_MINOR == 1 && DBUS_VERSION_MICRO>= 1) || (DBUS_VERSION_MAJOR == 1 && DBUS_VERSION_MINOR > 1) || (DBUS_VERSION_MAJOR > 1)
155   hd->fd = dbus_watch_get_unix_fd(hd->watch);
156 #else
157   hd->fd = dbus_watch_get_fd(hd->watch);
158 #endif
159   DBG("watch add (enabled: %d)", hd->enabled);
160   if (hd->enabled) e_dbus_fd_handler_add(hd);
161 }
162
163 static E_DBus_Connection *
164 e_dbus_connection_new(DBusConnection *conn)
165 {
166   E_DBus_Connection *cd;
167   const char *conn_name;
168
169   cd = calloc(1, sizeof(E_DBus_Connection));
170   if (!cd) return NULL;
171
172   cd->conn = conn;
173   conn_name = dbus_bus_get_unique_name(conn);
174   if (conn_name)
175   {
176     DBG("Connected! Name: %s", conn_name);
177     cd->conn_name = strdup(conn_name);
178   }
179   else
180     DBG("Not connected");
181
182   cd->shared_type = (unsigned int)-1;
183   cd->fd_handlers = NULL;
184   cd->timeouts = NULL;
185
186   return cd;
187 }
188
189 static void
190 e_dbus_connection_free(void *data)
191 {
192   E_DBus_Connection *cd = data;
193   Ecore_Fd_Handler *fd_handler;
194   Ecore_Timer *timer;
195   DBG("e_dbus_connection free!");
196
197   EINA_LIST_FREE(cd->fd_handlers, fd_handler)
198     ecore_main_fd_handler_del(fd_handler);
199
200   EINA_LIST_FREE(cd->timeouts, timer)
201     ecore_timer_del(timer);
202
203   if (cd->shared_type != (unsigned int)-1)
204     shared_connections[cd->shared_type] = NULL;
205
206   e_dbus_signal_handlers_free_all(cd);
207
208   if (cd->conn_name) free(cd->conn_name);
209
210   if (cd->idler) ecore_idler_del(cd->idler);
211
212   free(cd);
213 }
214
215 static void
216 cb_dispatch_status(DBusConnection *conn __UNUSED__, DBusDispatchStatus new_status, void *data)
217 {
218   E_DBus_Connection *cd;
219
220   DBG("dispatch status: %d!", new_status);
221   cd = data;
222
223   if (new_status == DBUS_DISPATCH_DATA_REMAINS && !cd->idler)
224      cd->idler = ecore_idler_add(e_dbus_idler, cd);
225   else if (new_status != DBUS_DISPATCH_DATA_REMAINS && cd->idler) 
226     {
227        ecore_idler_del(cd->idler);
228        cd->idler = NULL;
229     }
230 }
231
232 static Eina_Bool
233 e_dbus_timeout_handler(void *data)
234 {
235   E_DBus_Timeout_Data *td;
236
237   td = data;
238
239   if (!dbus_timeout_get_enabled(td->timeout))
240   {
241     DBG("timeout_handler (not enabled, ending)");
242     td->handler = NULL;
243     return ECORE_CALLBACK_CANCEL;
244   }
245
246   DBG("timeout handler!");
247   dbus_timeout_handle(td->timeout);
248   return ECORE_CALLBACK_CANCEL;
249 }
250
251 static void
252 e_dbus_timeout_data_free(void *timeout_data)
253 {
254   E_DBus_Timeout_Data *td = timeout_data;
255   DBG("e_dbus_timeout_data_free");
256   if (td->handler) ecore_timer_del(td->handler);
257   free(td);
258 }
259
260 static dbus_bool_t 
261 cb_timeout_add(DBusTimeout *timeout, void *data)
262 {
263   E_DBus_Connection *cd;
264   E_DBus_Timeout_Data *td;
265   
266   cd = data;
267   DBG("timeout add!");
268   td = calloc(1, sizeof(E_DBus_Timeout_Data));
269   td->cd = cd;
270   dbus_timeout_set_data(timeout, (void *)td, e_dbus_timeout_data_free);
271
272   td->interval = dbus_timeout_get_interval(timeout);
273   td->timeout = timeout;
274
275   if (dbus_timeout_get_enabled(timeout)) td->handler = ecore_timer_add(td->interval, e_dbus_timeout_handler, td);
276   td->cd->timeouts = eina_list_append(td->cd->timeouts, td->handler);
277
278   return true;
279 }
280
281 static void
282 cb_timeout_del(DBusTimeout *timeout, void *data __UNUSED__)
283 {
284   E_DBus_Timeout_Data *td;
285   DBG("timeout del!");
286
287   td = (E_DBus_Timeout_Data *)dbus_timeout_get_data(timeout);
288
289   if (td->handler) 
290   {
291     td->cd->timeouts = eina_list_remove(td->cd->timeouts, td->handler);
292     ecore_timer_del(td->handler);
293     td->handler = NULL;
294   }
295
296   /* Note: timeout data gets freed when the timeout itself is freed by dbus */
297 }
298
299 static void
300 cb_timeout_toggle(DBusTimeout *timeout, void *data __UNUSED__)
301 {
302   E_DBus_Timeout_Data *td;
303   DBG("timeout toggle!");
304
305   td = (E_DBus_Timeout_Data *)dbus_timeout_get_data(timeout);
306
307   if (dbus_timeout_get_enabled(td->timeout))
308   {
309     td->interval = dbus_timeout_get_interval(timeout);
310     td->handler = ecore_timer_add(td->interval, e_dbus_timeout_handler, td);
311   }
312   else
313   {
314     ecore_timer_del(td->handler);
315     td->handler = NULL;
316   }
317
318
319 }
320
321 static dbus_bool_t 
322 cb_watch_add(DBusWatch *watch, void *data)
323 {
324   E_DBus_Connection *cd;
325   cd = data;
326
327   DBG("cb_watch_add");
328   e_dbus_connection_data_watch_add(cd, watch);
329
330   return true;
331 }
332
333 static void
334 cb_watch_del(DBusWatch *watch, void *data __UNUSED__)
335 {
336   E_DBus_Handler_Data *hd;
337
338   DBG("cb_watch_del");
339   hd = (E_DBus_Handler_Data *)dbus_watch_get_data(watch);
340   e_dbus_fd_handler_del(hd);
341 }
342
343 static void
344 cb_watch_toggle(DBusWatch *watch, void *data __UNUSED__)
345 {
346   E_DBus_Handler_Data *hd;
347
348   DBG("cb_watch_toggle");
349   hd = dbus_watch_get_data(watch);
350
351   if (!hd) return;
352
353   hd->enabled = dbus_watch_get_enabled(watch);
354
355   INFO("watch %p is %sabled", hd, hd->enabled ? "en" : "dis");
356   if (hd->enabled) e_dbus_fd_handler_add(hd);
357   else e_dbus_fd_handler_del(hd);
358 }
359
360 static void
361 e_dbus_message_free(void *data __UNUSED__, void *message)
362 {
363   dbus_message_unref(message);
364 }
365
366 static DBusHandlerResult
367 e_dbus_filter(DBusConnection *conn __UNUSED__, DBusMessage *message, void *user_data)
368 {
369   E_DBus_Connection *cd = user_data;
370   DBG("-----------------");
371   DBG("Message!");
372
373   DBG("type: %s", dbus_message_type_to_string(dbus_message_get_type(message)));
374   DBG("path: %s", dbus_message_get_path(message));
375   DBG("interface: %s", dbus_message_get_interface(message));
376   DBG("member: %s", dbus_message_get_member(message));
377   DBG("sender: %s", dbus_message_get_sender(message));
378
379   switch (dbus_message_get_type(message))
380   {
381     case DBUS_MESSAGE_TYPE_METHOD_CALL:
382       DBG("signature: %s", dbus_message_get_signature(message));
383       break;
384     case DBUS_MESSAGE_TYPE_METHOD_RETURN:
385       DBG("reply serial %d", dbus_message_get_reply_serial(message));
386       break;
387     case DBUS_MESSAGE_TYPE_ERROR:
388       DBG("error: %s", dbus_message_get_error_name(message));
389       break;
390     case DBUS_MESSAGE_TYPE_SIGNAL:
391       dbus_message_ref(message);
392       if (cd->signal_dispatcher) cd->signal_dispatcher(cd, message);
393       ecore_event_add(E_DBUS_EVENT_SIGNAL, message, e_dbus_message_free, NULL);
394       break;
395     default:
396       break;
397   }
398   DBG("-----------------");
399
400   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
401 }
402
403 int e_dbus_idler_active = 0;
404
405 static Eina_Bool
406 e_dbus_idler(void *data)
407 {
408   E_DBus_Connection *cd;
409   cd = data;
410
411   if (DBUS_DISPATCH_COMPLETE == dbus_connection_get_dispatch_status(cd->conn))
412   {
413     DBG("done dispatching!");
414     cd->idler = NULL;
415     return ECORE_CALLBACK_CANCEL;
416   }
417   e_dbus_idler_active++;
418   dbus_connection_ref(cd->conn);
419   DBG("dispatch()");
420   dbus_connection_dispatch(cd->conn);
421   dbus_connection_unref(cd->conn);
422   e_dbus_idler_active--;
423   e_dbus_signal_handlers_clean(cd);
424   if (!e_dbus_idler_active && close_connection)
425   {
426     do
427     {
428       e_dbus_connection_close(cd);
429     } while (--close_connection);
430   }
431   return ECORE_CALLBACK_RENEW;
432 }
433
434 EAPI E_DBus_Connection *
435 e_dbus_bus_get(DBusBusType type)
436 {
437   DBusError err;
438   E_DBus_Connection *econn;
439   DBusConnection *conn;
440
441   /* each app only needs a single connection to either bus */
442   if (type == DBUS_BUS_SYSTEM || type == DBUS_BUS_SESSION)
443   {
444     if (shared_connections[type]) 
445     {
446       e_dbus_connection_ref(shared_connections[type]);
447       return shared_connections[type];
448     }
449   }
450
451   dbus_error_init(&err);
452
453   conn = dbus_bus_get_private(type, &err);
454   if (dbus_error_is_set(&err))
455   {
456     ERR("Error connecting to bus: %s", err.message);
457     dbus_error_free(&err);
458     return NULL;
459   }
460
461   econn = e_dbus_connection_setup(conn);
462   if (!econn)
463   {
464     ERR("Error setting up dbus connection.");
465     dbus_connection_close(conn);
466     dbus_connection_unref(conn);
467     return NULL;
468   }
469
470   if (type == DBUS_BUS_SYSTEM || type == DBUS_BUS_SESSION)
471   {
472     econn->shared_type = type;
473     shared_connections[type] = econn;
474   }
475   dbus_error_free(&err);
476   e_dbus_connection_ref(econn);
477   return econn;
478 }
479
480 EAPI E_DBus_Connection *
481 e_dbus_connection_setup(DBusConnection *conn)
482 {
483   E_DBus_Connection *cd;
484
485   cd = e_dbus_connection_new(conn);
486   if (!cd) return NULL;
487
488   /* connection_setup */
489   dbus_connection_set_exit_on_disconnect(cd->conn, EINA_FALSE);
490   dbus_connection_allocate_data_slot(&connection_slot);
491
492   dbus_connection_set_data(cd->conn, connection_slot, (void *)cd, e_dbus_connection_free);
493   dbus_connection_set_watch_functions(cd->conn,
494                                       cb_watch_add,
495                                       cb_watch_del,
496                                       cb_watch_toggle,
497                                       cd,
498                                       NULL);
499
500   dbus_connection_set_timeout_functions(cd->conn,
501                                       cb_timeout_add,
502                                       cb_timeout_del,
503                                       cb_timeout_toggle,
504                                       cd,
505                                       NULL);
506
507   dbus_connection_set_dispatch_status_function(cd->conn, cb_dispatch_status, cd, NULL);
508   dbus_connection_add_filter(cd->conn, e_dbus_filter, cd, NULL);
509
510   cb_dispatch_status(cd->conn, dbus_connection_get_dispatch_status(cd->conn), cd);
511
512   return cd;
513 }
514
515
516 EAPI void
517 e_dbus_connection_close(E_DBus_Connection *conn)
518 {
519   if (!conn) return;
520   DBG("e_dbus_connection_close");
521
522   if (e_dbus_idler_active)
523   {
524     close_connection++;
525     return;
526   }
527   if (--(conn->refcount) != 0) return;
528
529   dbus_connection_free_data_slot(&connection_slot);
530   dbus_connection_remove_filter(conn->conn, e_dbus_filter, conn);
531   dbus_connection_set_watch_functions (conn->conn,
532                                        NULL,
533                                        NULL,
534                                        NULL,
535                                        NULL, NULL);
536
537   dbus_connection_set_timeout_functions (conn->conn,
538                                          NULL,
539                                          NULL,
540                                          NULL,
541                                          NULL, NULL);
542
543   dbus_connection_set_dispatch_status_function (conn->conn, NULL, NULL, NULL);
544
545   /* Idler functin must be cancelled when dbus connection is  unreferenced */
546   if (conn->idler)
547     {
548       ecore_idler_del(conn->idler);
549       conn->idler = NULL;
550     }
551
552   dbus_connection_close(conn->conn);
553   dbus_connection_unref(conn->conn);
554
555   // Note: the E_DBus_Connection gets freed when the dbus_connection is cleaned up by the previous unref
556 }
557
558 EAPI void
559 e_dbus_connection_ref(E_DBus_Connection *conn)
560 {
561   EINA_SAFETY_ON_NULL_RETURN(conn);
562   conn->refcount++;
563 }
564
565 DBusConnection *
566 e_dbus_connection_dbus_connection_get(E_DBus_Connection *conn)
567 {
568   EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
569   return conn->conn;
570 }
571
572 EAPI int
573 e_dbus_init(void)
574 {
575   if (++_edbus_init_count != 1)
576     return _edbus_init_count;
577   
578   if (!eina_init())
579     {
580       fprintf(stderr,"E-dbus: Enable to initialize eina\n");
581       return --_edbus_init_count;
582     }
583
584   _e_dbus_log_dom = eina_log_domain_register("e_dbus", E_DBUS_COLOR_DEFAULT);
585   if (_e_dbus_log_dom < 0)
586     {
587       EINA_LOG_ERR("Unable to create an 'e_dbus' log domain");
588       eina_shutdown();
589       return --_edbus_init_count;
590     }
591   if (!ecore_init())
592     {
593       ERR("E-dbus: Unable to initialize ecore");
594       eina_log_domain_unregister(_e_dbus_log_dom);
595       _e_dbus_log_dom = -1;
596       eina_shutdown();
597       return --_edbus_init_count;
598     }
599
600   E_DBUS_DOMAIN_GLOBAL = _e_dbus_log_dom;
601   E_DBUS_EVENT_SIGNAL = ecore_event_type_new();
602   e_dbus_object_init();
603
604   return _edbus_init_count;
605 }
606
607 EAPI int
608 e_dbus_shutdown(void)
609 {
610    if (_edbus_init_count <= 0)
611      {
612         EINA_LOG_ERR("Init count not greater than 0 in shutdown.");
613         return 0;
614      }
615    if (--_edbus_init_count)
616     return _edbus_init_count;
617
618   e_dbus_object_shutdown();
619   ecore_shutdown();
620   eina_log_domain_unregister(_e_dbus_log_dom);
621   _e_dbus_log_dom = -1;
622   eina_shutdown();
623
624   return _edbus_init_count;
625 }