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