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