[connman] Added DBus method to get scanning status.
[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_idle_add(message_dispatch, dbus_connection_ref(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         if (cond & G_IO_IN)  flags |= DBUS_WATCH_READABLE;
98         if (cond & G_IO_OUT) flags |= DBUS_WATCH_WRITABLE;
99         if (cond & G_IO_HUP) flags |= DBUS_WATCH_HANGUP;
100         if (cond & G_IO_ERR) flags |= DBUS_WATCH_ERROR;
101
102         /* Protect connection from being destroyed by dbus_watch_handle */
103         conn = dbus_connection_ref(info->conn);
104
105         dbus_watch_handle(info->watch, flags);
106
107         status = dbus_connection_get_dispatch_status(conn);
108         queue_dispatch(conn, status);
109
110         dbus_connection_unref(conn);
111
112         return TRUE;
113 }
114
115 static void watch_info_free(void *data)
116 {
117         struct watch_info *info = data;
118
119         if (info->id > 0) {
120                 g_source_remove(info->id);
121                 info->id = 0;
122         }
123
124         dbus_connection_unref(info->conn);
125
126         g_free(info);
127 }
128
129 static dbus_bool_t add_watch(DBusWatch *watch, void *data)
130 {
131         DBusConnection *conn = data;
132         GIOCondition cond = G_IO_HUP | G_IO_ERR;
133         GIOChannel *chan;
134         struct watch_info *info;
135         unsigned int flags;
136         int fd;
137
138         if (!dbus_watch_get_enabled(watch))
139                 return TRUE;
140
141         info = g_new0(struct watch_info, 1);
142
143         fd = dbus_watch_get_unix_fd(watch);
144         chan = g_io_channel_unix_new(fd);
145
146         info->watch = watch;
147         info->conn = dbus_connection_ref(conn);
148
149         dbus_watch_set_data(watch, info, watch_info_free);
150
151         flags = dbus_watch_get_flags(watch);
152
153         if (flags & DBUS_WATCH_READABLE) cond |= G_IO_IN;
154         if (flags & DBUS_WATCH_WRITABLE) cond |= G_IO_OUT;
155
156         info->id = g_io_add_watch(chan, cond, watch_func, info);
157
158         g_io_channel_unref(chan);
159
160         return TRUE;
161 }
162
163 static void remove_watch(DBusWatch *watch, void *data)
164 {
165         if (dbus_watch_get_enabled(watch))
166                 return;
167
168         /* will trigger watch_info_free() */
169         dbus_watch_set_data(watch, NULL, NULL);
170 }
171
172 static void watch_toggled(DBusWatch *watch, void *data)
173 {
174         /* Because we just exit on OOM, enable/disable is
175          * no different from add/remove */
176         if (dbus_watch_get_enabled(watch))
177                 add_watch(watch, data);
178         else
179                 remove_watch(watch, data);
180 }
181
182 static gboolean timeout_handler_dispatch(gpointer data)
183 {
184         struct timeout_handler *handler = data;
185
186         handler->id = 0;
187
188         /* if not enabled should not be polled by the main loop */
189         if (!dbus_timeout_get_enabled(handler->timeout))
190                 return FALSE;
191
192         dbus_timeout_handle(handler->timeout);
193
194         return FALSE;
195 }
196
197 static void timeout_handler_free(void *data)
198 {
199         struct timeout_handler *handler = data;
200
201         if (handler->id > 0) {
202                 g_source_remove(handler->id);
203                 handler->id = 0;
204         }
205
206         g_free(handler);
207 }
208
209 static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data)
210 {
211         int interval = dbus_timeout_get_interval(timeout);
212         struct timeout_handler *handler;
213
214         if (!dbus_timeout_get_enabled(timeout))
215                 return TRUE;
216
217         handler = g_new0(struct timeout_handler, 1);
218
219         handler->timeout = timeout;
220
221         dbus_timeout_set_data(timeout, handler, timeout_handler_free);
222
223         handler->id = g_timeout_add(interval, timeout_handler_dispatch,
224                                                                 handler);
225
226         return TRUE;
227 }
228
229 static void remove_timeout(DBusTimeout *timeout, void *data)
230 {
231         /* will trigger timeout_handler_free() */
232         dbus_timeout_set_data(timeout, NULL, NULL);
233 }
234
235 static void timeout_toggled(DBusTimeout *timeout, void *data)
236 {
237         if (dbus_timeout_get_enabled(timeout))
238                 add_timeout(timeout, data);
239         else
240                 remove_timeout(timeout, data);
241 }
242
243 static void dispatch_status(DBusConnection *conn,
244                                         DBusDispatchStatus status, void *data)
245 {
246         if (!dbus_connection_get_is_connected(conn))
247                 return;
248
249         queue_dispatch(conn, status);
250 }
251
252 static inline void setup_dbus_with_main_loop(DBusConnection *conn)
253 {
254         dbus_connection_set_watch_functions(conn, add_watch, remove_watch,
255                                                 watch_toggled, conn, NULL);
256
257         dbus_connection_set_timeout_functions(conn, add_timeout, remove_timeout,
258                                                 timeout_toggled, NULL, NULL);
259
260         dbus_connection_set_dispatch_status_function(conn, dispatch_status,
261                                                                 NULL, NULL);
262 }
263
264 static gboolean setup_bus(DBusConnection *conn, const char *name,
265                                                 DBusError *error)
266 {
267         gboolean result;
268         DBusDispatchStatus status;
269
270         if (name != NULL) {
271                 result = g_dbus_request_name(conn, name, error);
272
273                 if (error != NULL) {
274                         if (dbus_error_is_set(error) == TRUE)
275                                 return FALSE;
276                 }
277
278                 if (result == FALSE)
279                         return FALSE;
280         }
281
282         setup_dbus_with_main_loop(conn);
283
284         status = dbus_connection_get_dispatch_status(conn);
285         queue_dispatch(conn, status);
286
287         return TRUE;
288 }
289
290 DBusConnection *g_dbus_setup_bus(DBusBusType type, const char *name,
291                                                         DBusError *error)
292 {
293         DBusConnection *conn;
294
295         conn = dbus_bus_get(type, error);
296
297         if (error != NULL) {
298                 if (dbus_error_is_set(error) == TRUE)
299                         return NULL;
300         }
301
302         if (conn == NULL)
303                 return NULL;
304
305         if (setup_bus(conn, name, error) == FALSE) {
306                 dbus_connection_unref(conn);
307                 return NULL;
308         }
309
310         return conn;
311 }
312
313 DBusConnection *g_dbus_setup_private(DBusBusType type, const char *name,
314                                                         DBusError *error)
315 {
316         DBusConnection *conn;
317
318         conn = dbus_bus_get_private(type, error);
319
320         if (error != NULL) {
321                 if (dbus_error_is_set(error) == TRUE)
322                         return NULL;
323         }
324
325         if (conn == NULL)
326                 return NULL;
327
328         if (setup_bus(conn, name, error) == FALSE) {
329                 dbus_connection_close(conn);
330                 dbus_connection_unref(conn);
331                 return NULL;
332         }
333
334         return conn;
335 }
336
337 gboolean g_dbus_request_name(DBusConnection *connection, const char *name,
338                                                         DBusError *error)
339 {
340         int result;
341
342         result = dbus_bus_request_name(connection, name,
343                                         DBUS_NAME_FLAG_DO_NOT_QUEUE, error);
344
345         if (error != NULL) {
346                 if (dbus_error_is_set(error) == TRUE)
347                         return FALSE;
348         }
349
350         if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
351                 if (error != NULL)
352                         dbus_set_error(error, name, "Name already in use");
353
354                 return FALSE;
355         }
356
357         return TRUE;
358 }
359
360 gboolean g_dbus_set_disconnect_function(DBusConnection *connection,
361                                 GDBusWatchFunction function,
362                                 void *user_data, DBusFreeFunction destroy)
363 {
364         struct disconnect_data *dc_data;
365
366         dc_data = g_new0(struct disconnect_data, 1);
367
368         dc_data->function = function;
369         dc_data->user_data = user_data;
370
371         dbus_connection_set_exit_on_disconnect(connection, FALSE);
372
373         if (g_dbus_add_signal_watch(connection, NULL, NULL,
374                                 DBUS_INTERFACE_LOCAL, "Disconnected",
375                                 disconnected_signal, dc_data, g_free) == 0) {
376                 error("Failed to add watch for D-Bus Disconnected signal");
377                 g_free(dc_data);
378                 return FALSE;
379         }
380
381         return TRUE;
382 }