Don't use default for enum based switch statements
[framework/connectivity/connman.git] / gdbus / mainloop.c
1 /*
2  *
3  *  D-Bus helper library
4  *
5  *  Copyright (C) 2004-2009  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 <stdint.h>
29
30 #include <glib.h>
31 #include <dbus/dbus.h>
32
33 #ifdef NEED_DBUS_WATCH_GET_UNIX_FD
34 #define dbus_watch_get_unix_fd dbus_watch_get_fd
35 #endif
36
37 #include "gdbus.h"
38
39 #define DISPATCH_TIMEOUT  0
40
41 #define info(fmt...)
42 #define error(fmt...)
43 #define debug(fmt...)
44
45 typedef struct {
46         uint32_t id;
47         DBusTimeout *timeout;
48 } timeout_handler_t;
49
50 struct watch_info {
51         guint watch_id;
52         GIOChannel *io;
53         DBusConnection *conn;
54 };
55
56 struct server_info {
57         guint watch_id;
58         GIOChannel *io;
59         DBusServer *server;
60 };
61
62 struct disconnect_data {
63         GDBusWatchFunction disconnect_cb;
64         void *user_data;
65 };
66
67 static DBusHandlerResult disconnect_filter(DBusConnection *conn,
68                                                 DBusMessage *msg, void *data)
69 {
70         struct disconnect_data *dc_data = data;
71
72         if (dbus_message_is_signal(msg,
73                         DBUS_INTERFACE_LOCAL, "Disconnected") == TRUE) {
74                 error("Got disconnected from the system message bus");
75                 dc_data->disconnect_cb(conn, dc_data->user_data);
76                 dbus_connection_unref(conn);
77         }
78
79         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
80 }
81
82 static gboolean message_dispatch_cb(void *data)
83 {
84         DBusConnection *connection = data;
85
86         dbus_connection_ref(connection);
87
88         /* Dispatch messages */
89         while (dbus_connection_dispatch(connection) == DBUS_DISPATCH_DATA_REMAINS);
90
91         dbus_connection_unref(connection);
92
93         return FALSE;
94 }
95
96 static gboolean watch_func(GIOChannel *chan, GIOCondition cond, gpointer data)
97 {
98         DBusWatch *watch = data;
99         struct watch_info *info = dbus_watch_get_data(watch);
100         int flags = 0;
101
102         if (cond & G_IO_IN)  flags |= DBUS_WATCH_READABLE;
103         if (cond & G_IO_OUT) flags |= DBUS_WATCH_WRITABLE;
104         if (cond & G_IO_HUP) flags |= DBUS_WATCH_HANGUP;
105         if (cond & G_IO_ERR) flags |= DBUS_WATCH_ERROR;
106
107         dbus_watch_handle(watch, flags);
108
109         if (dbus_connection_get_dispatch_status(info->conn) == DBUS_DISPATCH_DATA_REMAINS)
110                 g_timeout_add(DISPATCH_TIMEOUT, message_dispatch_cb, info->conn);
111
112         return TRUE;
113 }
114
115 static dbus_bool_t add_watch(DBusWatch *watch, void *data)
116 {
117         GIOCondition cond = G_IO_HUP | G_IO_ERR;
118         DBusConnection *conn = data;
119         struct watch_info *info;
120         int fd, flags;
121
122         if (!dbus_watch_get_enabled(watch))
123                 return TRUE;
124
125         info = g_new(struct watch_info, 1);
126
127         fd = dbus_watch_get_unix_fd(watch);
128         info->io = g_io_channel_unix_new(fd);
129         info->conn = dbus_connection_ref(conn);
130
131         dbus_watch_set_data(watch, info, NULL);
132
133         flags = dbus_watch_get_flags(watch);
134
135         if (flags & DBUS_WATCH_READABLE) cond |= G_IO_IN;
136         if (flags & DBUS_WATCH_WRITABLE) cond |= G_IO_OUT;
137
138         info->watch_id = g_io_add_watch(info->io, cond, watch_func, watch);
139
140         return TRUE;
141 }
142
143 static void remove_watch(DBusWatch *watch, void *data)
144 {
145         struct watch_info *info = dbus_watch_get_data(watch);
146
147         dbus_watch_set_data(watch, NULL, NULL);
148
149         if (info) {
150                 g_source_remove(info->watch_id);
151                 g_io_channel_unref(info->io);
152                 dbus_connection_unref(info->conn);
153                 g_free(info);
154         }
155 }
156
157 static void watch_toggled(DBusWatch *watch, void *data)
158 {
159         /* Because we just exit on OOM, enable/disable is
160          * no different from add/remove */
161         if (dbus_watch_get_enabled(watch))
162                 add_watch(watch, data);
163         else
164                 remove_watch(watch, data);
165 }
166
167 static gboolean timeout_handler_dispatch(gpointer data)
168 {
169         timeout_handler_t *handler = data;
170
171         /* if not enabled should not be polled by the main loop */
172         if (dbus_timeout_get_enabled(handler->timeout) != TRUE)
173                 return FALSE;
174
175         dbus_timeout_handle(handler->timeout);
176
177         return FALSE;
178 }
179
180 static void timeout_handler_free(void *data)
181 {
182         timeout_handler_t *handler = data;
183         if (!handler)
184                 return;
185
186         g_source_remove(handler->id);
187         g_free(handler);
188 }
189
190 static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data)
191 {
192         timeout_handler_t *handler;
193
194         if (!dbus_timeout_get_enabled(timeout))
195                 return TRUE;
196
197         handler = g_new0(timeout_handler_t, 1);
198
199         handler->timeout = timeout;
200         handler->id = g_timeout_add(dbus_timeout_get_interval(timeout),
201                                         timeout_handler_dispatch, handler);
202
203         dbus_timeout_set_data(timeout, handler, timeout_handler_free);
204
205         return TRUE;
206 }
207
208 static void remove_timeout(DBusTimeout *timeout, void *data)
209 {
210 }
211
212 static void timeout_toggled(DBusTimeout *timeout, void *data)
213 {
214         if (dbus_timeout_get_enabled(timeout))
215                 add_timeout(timeout, data);
216         else
217                 remove_timeout(timeout, data);
218 }
219
220 static void dispatch_status_cb(DBusConnection *conn,
221                                 DBusDispatchStatus new_status, void *data)
222 {
223         if (!dbus_connection_get_is_connected(conn))
224                 return;
225
226         if (new_status == DBUS_DISPATCH_DATA_REMAINS)
227                 g_timeout_add(DISPATCH_TIMEOUT, message_dispatch_cb, data);
228 }
229
230 static void setup_dbus_with_main_loop(DBusConnection *conn)
231 {
232         dbus_connection_set_watch_functions(conn, add_watch, remove_watch,
233                                                 watch_toggled, conn, NULL);
234
235         dbus_connection_set_timeout_functions(conn, add_timeout, remove_timeout,
236                                                 timeout_toggled, conn, NULL);
237
238         dbus_connection_set_dispatch_status_function(conn, dispatch_status_cb,
239                                                                 conn, NULL);
240 }
241
242 DBusConnection *g_dbus_setup_bus(DBusBusType type, const char *name,
243                                                         DBusError *error)
244 {
245         DBusConnection *conn;
246
247         conn = dbus_bus_get(type, error);
248
249         if (error != NULL) {
250                 if (dbus_error_is_set(error) == TRUE)
251                         return NULL;
252         }
253
254         if (conn == NULL)
255                 return NULL;
256
257         if (name != NULL) {
258                 if (dbus_bus_request_name(conn, name,
259                                 DBUS_NAME_FLAG_DO_NOT_QUEUE, error) !=
260                                 DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER ) {
261                         dbus_connection_unref(conn);
262                         return NULL;
263                 }
264
265                 if (error != NULL) {
266                         if (dbus_error_is_set(error) == TRUE) {
267                                 dbus_connection_unref(conn);
268                                 return NULL;
269                         }
270                 }
271         }
272
273         setup_dbus_with_main_loop(conn);
274
275         return conn;
276 }
277
278 gboolean g_dbus_request_name(DBusConnection *connection, const char *name,
279                                                         DBusError *error)
280 {
281         return TRUE;
282 }
283
284 gboolean g_dbus_check_service(DBusConnection *connection, const char *name)
285 {
286         DBusMessage *message, *reply;
287         const char **names;
288         int i, count;
289         gboolean result = FALSE;
290
291         message = dbus_message_new_method_call(DBUS_SERVICE_DBUS,
292                         DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "ListNames");
293         if (message == NULL) {
294                 error("Can't allocate new message");
295                 return FALSE;
296         }
297
298         reply = dbus_connection_send_with_reply_and_block(connection,
299                                                         message, -1, NULL);
300
301         dbus_message_unref(message);
302
303         if (reply == NULL) {
304                 error("Failed to execute method call");
305                 return FALSE;
306         }
307
308         if (dbus_message_get_args(reply, NULL,
309                                 DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
310                                 &names, &count, DBUS_TYPE_INVALID) == FALSE) {
311                 error("Failed to read name list");
312                 goto done;
313         }
314
315         for (i = 0; i < count; i++)
316                 if (g_str_equal(names[i], name) == TRUE) {
317                         result = TRUE;
318                         break;
319                 }
320
321 done:
322         dbus_message_unref(reply);
323
324         return result;
325 }
326
327 gboolean g_dbus_set_disconnect_function(DBusConnection *connection,
328                                 GDBusWatchFunction function,
329                                 void *user_data, DBusFreeFunction destroy)
330 {
331         struct disconnect_data *dc_data;
332
333         dc_data = g_new(struct disconnect_data, 1);
334
335         dc_data->disconnect_cb = function;
336         dc_data->user_data = user_data;
337
338         dbus_connection_set_exit_on_disconnect(connection, FALSE);
339
340         if (dbus_connection_add_filter(connection, disconnect_filter,
341                                                 dc_data, g_free) == FALSE) {
342                 error("Can't add D-Bus disconnect filter");
343                 g_free(dc_data);
344                 return FALSE;
345         }
346
347         return TRUE;
348 }