099b67fef11fb6e76fcebaddf5a17afb4f982b5a
[platform/upstream/connman.git] / gdbus / mainloop.c
1 /*
2  *
3  *  D-Bus helper library
4  *
5  *  Copyright (C) 2004-2011  Marcel Holtmann <marcel@holtmann.org>
6  *
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <glib.h>
29 #include <dbus/dbus.h>
30
31 #include "gdbus.h"
32
33 #define DISPATCH_TIMEOUT  0
34
35 #define info(fmt...)
36 #define error(fmt...)
37 #define debug(fmt...)
38
39 struct timeout_handler {
40         guint id;
41         DBusTimeout *timeout;
42 };
43
44 struct watch_info {
45         guint id;
46         DBusWatch *watch;
47         DBusConnection *conn;
48 };
49
50 struct disconnect_data {
51         GDBusWatchFunction function;
52         void *user_data;
53 };
54
55 static gboolean disconnected_signal(DBusConnection *conn,
56                                                 DBusMessage *msg, void *data)
57 {
58         struct disconnect_data *dc_data = data;
59
60         error("Got disconnected from the system message bus");
61
62         dc_data->function(conn, dc_data->user_data);
63
64         dbus_connection_unref(conn);
65
66         return TRUE;
67 }
68
69 static gboolean message_dispatch(void *data)
70 {
71         DBusConnection *conn = data;
72
73         dbus_connection_ref(conn);
74
75         /* Dispatch messages */
76         while (dbus_connection_dispatch(conn) == DBUS_DISPATCH_DATA_REMAINS);
77
78         dbus_connection_unref(conn);
79
80         return FALSE;
81 }
82
83 static inline void queue_dispatch(DBusConnection *conn,
84                                                 DBusDispatchStatus status)
85 {
86         if (status == DBUS_DISPATCH_DATA_REMAINS)
87                 g_timeout_add(DISPATCH_TIMEOUT, message_dispatch, conn);
88 }
89
90 static gboolean watch_func(GIOChannel *chan, GIOCondition cond, gpointer data)
91 {
92         struct watch_info *info = data;
93         unsigned int flags = 0;
94         DBusDispatchStatus status;
95         DBusConnection *conn;
96
97         conn = dbus_connection_ref(info->conn);
98
99         if (cond & G_IO_IN)  flags |= DBUS_WATCH_READABLE;
100         if (cond & G_IO_OUT) flags |= DBUS_WATCH_WRITABLE;
101         if (cond & G_IO_HUP) flags |= DBUS_WATCH_HANGUP;
102         if (cond & G_IO_ERR) flags |= DBUS_WATCH_ERROR;
103
104         dbus_watch_handle(info->watch, flags);
105
106         status = dbus_connection_get_dispatch_status(conn);
107         queue_dispatch(conn, status);
108
109         dbus_connection_unref(conn);
110
111         return TRUE;
112 }
113
114 static void watch_info_free(void *data)
115 {
116         struct watch_info *info = data;
117
118         if (info->id > 0) {
119                 g_source_remove(info->id);
120                 info->id = 0;
121         }
122
123         dbus_connection_unref(info->conn);
124
125         g_free(info);
126 }
127
128 static dbus_bool_t add_watch(DBusWatch *watch, void *data)
129 {
130         DBusConnection *conn = data;
131         GIOCondition cond = G_IO_HUP | G_IO_ERR;
132         GIOChannel *chan;
133         struct watch_info *info;
134         unsigned int flags;
135         int fd;
136
137         if (!dbus_watch_get_enabled(watch))
138                 return TRUE;
139
140         info = g_new0(struct watch_info, 1);
141
142         fd = dbus_watch_get_unix_fd(watch);
143         chan = g_io_channel_unix_new(fd);
144
145         info->watch = watch;
146         info->conn = dbus_connection_ref(conn);
147
148         dbus_watch_set_data(watch, info, watch_info_free);
149
150         flags = dbus_watch_get_flags(watch);
151
152         if (flags & DBUS_WATCH_READABLE) cond |= G_IO_IN;
153         if (flags & DBUS_WATCH_WRITABLE) cond |= G_IO_OUT;
154
155         info->id = g_io_add_watch(chan, cond, watch_func, info);
156
157         g_io_channel_unref(chan);
158
159         return TRUE;
160 }
161
162 static void remove_watch(DBusWatch *watch, void *data)
163 {
164         if (dbus_watch_get_enabled(watch))
165                 return;
166
167         /* will trigger watch_info_free() */
168         dbus_watch_set_data(watch, NULL, NULL);
169 }
170
171 static void watch_toggled(DBusWatch *watch, void *data)
172 {
173         /* Because we just exit on OOM, enable/disable is
174          * no different from add/remove */
175         if (dbus_watch_get_enabled(watch))
176                 add_watch(watch, data);
177         else
178                 remove_watch(watch, data);
179 }
180
181 static gboolean timeout_handler_dispatch(gpointer data)
182 {
183         struct timeout_handler *handler = data;
184
185         handler->id = 0;
186
187         /* if not enabled should not be polled by the main loop */
188         if (!dbus_timeout_get_enabled(handler->timeout))
189                 return FALSE;
190
191         dbus_timeout_handle(handler->timeout);
192
193         return FALSE;
194 }
195
196 static void timeout_handler_free(void *data)
197 {
198         struct timeout_handler *handler = data;
199
200         if (handler->id > 0) {
201                 g_source_remove(handler->id);
202                 handler->id = 0;
203         }
204
205         g_free(handler);
206 }
207
208 static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data)
209 {
210         int interval = dbus_timeout_get_interval(timeout);
211         struct timeout_handler *handler;
212
213         if (!dbus_timeout_get_enabled(timeout))
214                 return TRUE;
215
216         handler = g_new0(struct timeout_handler, 1);
217
218         handler->timeout = timeout;
219
220         dbus_timeout_set_data(timeout, handler, timeout_handler_free);
221
222         handler->id = g_timeout_add(interval, timeout_handler_dispatch,
223                                                                 handler);
224
225         return TRUE;
226 }
227
228 static void remove_timeout(DBusTimeout *timeout, void *data)
229 {
230         /* will trigger timeout_handler_free() */
231         dbus_timeout_set_data(timeout, NULL, NULL);
232 }
233
234 static void timeout_toggled(DBusTimeout *timeout, void *data)
235 {
236         if (dbus_timeout_get_enabled(timeout))
237                 add_timeout(timeout, data);
238         else
239                 remove_timeout(timeout, data);
240 }
241
242 static void dispatch_status(DBusConnection *conn,
243                                         DBusDispatchStatus status, void *data)
244 {
245         if (!dbus_connection_get_is_connected(conn))
246                 return;
247
248         queue_dispatch(conn, status);
249 }
250
251 static inline void setup_dbus_with_main_loop(DBusConnection *conn)
252 {
253         dbus_connection_set_watch_functions(conn, add_watch, remove_watch,
254                                                 watch_toggled, conn, NULL);
255
256         dbus_connection_set_timeout_functions(conn, add_timeout, remove_timeout,
257                                                 timeout_toggled, NULL, NULL);
258
259         dbus_connection_set_dispatch_status_function(conn, dispatch_status,
260                                                                 NULL, NULL);
261 }
262
263 static gboolean setup_bus(DBusConnection *conn, const char *name,
264                                                 DBusError *error)
265 {
266         gboolean result;
267         DBusDispatchStatus status;
268
269         if (name != NULL) {
270                 result = g_dbus_request_name(conn, name, error);
271
272                 if (error != NULL) {
273                         if (dbus_error_is_set(error) == TRUE)
274                                 return FALSE;
275                 }
276
277                 if (result == FALSE)
278                         return FALSE;
279         }
280
281         setup_dbus_with_main_loop(conn);
282
283         status = dbus_connection_get_dispatch_status(conn);
284         queue_dispatch(conn, status);
285
286         return TRUE;
287 }
288
289 DBusConnection *g_dbus_setup_bus(DBusBusType type, const char *name,
290                                                         DBusError *error)
291 {
292         DBusConnection *conn;
293
294         conn = dbus_bus_get(type, error);
295
296         if (error != NULL) {
297                 if (dbus_error_is_set(error) == TRUE)
298                         return NULL;
299         }
300
301         if (conn == NULL)
302                 return NULL;
303
304         if (setup_bus(conn, name, error) == FALSE) {
305                 dbus_connection_unref(conn);
306                 return NULL;
307         }
308
309         return conn;
310 }
311
312 DBusConnection *g_dbus_setup_private(DBusBusType type, const char *name,
313                                                         DBusError *error)
314 {
315         DBusConnection *conn;
316
317         conn = dbus_bus_get_private(type, error);
318
319         if (error != NULL) {
320                 if (dbus_error_is_set(error) == TRUE)
321                         return NULL;
322         }
323
324         if (conn == NULL)
325                 return NULL;
326
327         if (setup_bus(conn, name, error) == FALSE) {
328                 dbus_connection_unref(conn);
329                 return NULL;
330         }
331
332         return conn;
333 }
334
335 gboolean g_dbus_request_name(DBusConnection *connection, const char *name,
336                                                         DBusError *error)
337 {
338         int result;
339
340         result = dbus_bus_request_name(connection, name,
341                                         DBUS_NAME_FLAG_DO_NOT_QUEUE, error);
342
343         if (error != NULL) {
344                 if (dbus_error_is_set(error) == TRUE)
345                         return FALSE;
346         }
347
348         if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
349                 if (error != NULL)
350                         dbus_set_error(error, name, "Name already in use");
351
352                 return FALSE;
353         }
354
355         return TRUE;
356 }
357
358 gboolean g_dbus_set_disconnect_function(DBusConnection *connection,
359                                 GDBusWatchFunction function,
360                                 void *user_data, DBusFreeFunction destroy)
361 {
362         struct disconnect_data *dc_data;
363
364         dc_data = g_new0(struct disconnect_data, 1);
365
366         dc_data->function = function;
367         dc_data->user_data = user_data;
368
369         dbus_connection_set_exit_on_disconnect(connection, FALSE);
370
371         if (g_dbus_add_signal_watch(connection, NULL, NULL,
372                                 DBUS_INTERFACE_LOCAL, "Disconnected",
373                                 disconnected_signal, dc_data, g_free) == 0) {
374                 error("Failed to add watch for D-Bus Disconnected signal");
375                 g_free(dc_data);
376                 return FALSE;
377         }
378
379         return TRUE;
380 }