Fix PASSED_TO_PROC_AFTER_FREE.EX
[platform/upstream/connman.git] / tools / supplicant-dbus.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2012  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <errno.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <dbus/dbus.h>
30
31 #include "supplicant-dbus.h"
32
33 #define TIMEOUT 5000
34
35 static DBusConnection *connection = NULL;
36
37 void supplicant_dbus_setup(DBusConnection *conn)
38 {
39         connection = conn;
40 }
41
42 void supplicant_dbus_array_foreach(DBusMessageIter *iter,
43                                 supplicant_dbus_array_function function,
44                                                         void *user_data)
45 {
46         DBusMessageIter entry;
47
48         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
49                 return;
50
51         dbus_message_iter_recurse(iter, &entry);
52
53         while (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_INVALID) {
54                 if (function)
55                         function(&entry, user_data);
56
57                 dbus_message_iter_next(&entry);
58         }
59 }
60
61 void supplicant_dbus_property_foreach(DBusMessageIter *iter,
62                                 supplicant_dbus_property_function function,
63                                                         void *user_data)
64 {
65         DBusMessageIter dict;
66
67         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
68                 return;
69
70         dbus_message_iter_recurse(iter, &dict);
71
72         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
73                 DBusMessageIter entry, value;
74                 const char *key;
75
76                 dbus_message_iter_recurse(&dict, &entry);
77
78                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
79                         return;
80
81                 dbus_message_iter_get_basic(&entry, &key);
82                 dbus_message_iter_next(&entry);
83
84                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
85                         return;
86
87                 dbus_message_iter_recurse(&entry, &value);
88
89                 if (key) {
90                         if (strcmp(key, "Properties") == 0)
91                                 supplicant_dbus_property_foreach(&value,
92                                                         function, user_data);
93                         else if (function)
94                                 function(key, &value, user_data);
95                 }
96
97                 dbus_message_iter_next(&dict);
98         }
99 }
100
101 struct property_get_data {
102         supplicant_dbus_property_function function;
103         void *user_data;
104 };
105
106 static void property_get_all_reply(DBusPendingCall *call, void *user_data)
107 {
108         struct property_get_data *data = user_data;
109         DBusMessage *reply;
110         DBusMessageIter iter;
111
112         reply = dbus_pending_call_steal_reply(call);
113
114         if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR)
115                 goto done;
116
117         if (!dbus_message_iter_init(reply, &iter))
118                 goto done;
119
120         supplicant_dbus_property_foreach(&iter, data->function,
121                                                         data->user_data);
122
123         if (data->function)
124                 data->function(NULL, NULL, data->user_data);
125
126 done:
127         dbus_message_unref(reply);
128
129         dbus_pending_call_unref(call);
130 }
131
132 int supplicant_dbus_property_get_all(const char *path, const char *interface,
133                                 supplicant_dbus_property_function function,
134                                                         void *user_data)
135 {
136         struct property_get_data *data;
137         DBusMessage *message;
138         DBusPendingCall *call;
139
140         if (!connection)
141                 return -EINVAL;
142
143         if (!path || !interface)
144                 return -EINVAL;
145
146         data = dbus_malloc0(sizeof(*data));
147         if (!data)
148                 return -ENOMEM;
149
150         message = dbus_message_new_method_call(SUPPLICANT_SERVICE, path,
151                                         DBUS_INTERFACE_PROPERTIES, "GetAll");
152         if (!message) {
153                 dbus_free(data);
154                 return -ENOMEM;
155         }
156
157         dbus_message_set_auto_start(message, FALSE);
158
159         dbus_message_append_args(message, DBUS_TYPE_STRING, &interface, NULL);
160
161         if (!dbus_connection_send_with_reply(connection, message,
162                                                         &call, TIMEOUT)) {
163                 dbus_message_unref(message);
164                 dbus_free(data);
165                 return -EIO;
166         }
167
168         if (!call) {
169                 dbus_message_unref(message);
170                 dbus_free(data);
171                 return -EIO;
172         }
173
174         data->function = function;
175         data->user_data = user_data;
176
177         dbus_pending_call_set_notify(call, property_get_all_reply,
178                                                         data, dbus_free);
179
180         dbus_message_unref(message);
181
182         return 0;
183 }
184
185 struct property_set_data {
186         supplicant_dbus_result_function function;
187         void *user_data;
188 };
189
190 static void property_set_reply(DBusPendingCall *call, void *user_data)
191 {
192         struct property_set_data *data = user_data;
193         DBusMessage *reply;
194         DBusMessageIter iter;
195         const char *error;
196
197         reply = dbus_pending_call_steal_reply(call);
198
199         if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR)
200                 error = dbus_message_get_error_name(reply);
201         else
202                 error = NULL;
203
204         if (!dbus_message_iter_init(reply, &iter))
205                 goto done;
206
207         if (data->function)
208                 data->function(error, &iter, data->user_data);
209
210 done:
211         dbus_message_unref(reply);
212
213         dbus_pending_call_unref(call);
214 }
215
216 int supplicant_dbus_property_set(const char *path, const char *interface,
217                                 const char *key, const char *signature,
218                                 supplicant_dbus_setup_function setup,
219                                 supplicant_dbus_result_function function,
220                                                         void *user_data)
221 {
222         struct property_set_data *data;
223         DBusMessage *message;
224         DBusMessageIter iter, value;
225         DBusPendingCall *call;
226
227         if (!connection)
228                 return -EINVAL;
229
230         if (!path || !interface)
231                 return -EINVAL;
232
233         if (!key || !signature || !setup)
234                 return -EINVAL;
235
236         data = dbus_malloc0(sizeof(*data));
237         if (!data)
238                 return -ENOMEM;
239
240         message = dbus_message_new_method_call(SUPPLICANT_SERVICE, path,
241                                         DBUS_INTERFACE_PROPERTIES, "Set");
242         if (!message) {
243                 dbus_free(data);
244                 return -ENOMEM;
245         }
246
247         dbus_message_set_auto_start(message, FALSE);
248
249         dbus_message_iter_init_append(message, &iter);
250         dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &interface);
251         dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key);
252
253         dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
254                                                         signature, &value);
255         setup(&value, user_data);
256         dbus_message_iter_close_container(&iter, &value);
257
258         if (!dbus_connection_send_with_reply(connection, message,
259                                                 &call, TIMEOUT)) {
260                 dbus_message_unref(message);
261                 dbus_free(data);
262                 return -EIO;
263         }
264
265         if (!call) {
266                 dbus_message_unref(message);
267                 dbus_free(data);
268                 return -EIO;
269         }
270
271         data->function = function;
272         data->user_data = user_data;
273
274         dbus_pending_call_set_notify(call, property_set_reply,
275                                                         data, dbus_free);
276
277         dbus_message_unref(message);
278
279         return 0;
280 }
281
282 struct method_call_data {
283         supplicant_dbus_result_function function;
284         void *user_data;
285 };
286
287 static void method_call_reply(DBusPendingCall *call, void *user_data)
288 {
289         struct method_call_data *data = user_data;
290         DBusMessage *reply;
291         DBusMessageIter iter;
292         const char *error;
293
294         reply = dbus_pending_call_steal_reply(call);
295
296         if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR)
297                 error = dbus_message_get_error_name(reply);
298         else
299                 error = NULL;
300
301         dbus_message_iter_init(reply, &iter);
302
303         if (data->function)
304                 data->function(error, &iter, data->user_data);
305
306         dbus_message_unref(reply);
307
308         dbus_pending_call_unref(call);
309 }
310
311 int supplicant_dbus_method_call(const char *path,
312                                 const char *interface, const char *method,
313                                 supplicant_dbus_setup_function setup,
314                                 supplicant_dbus_result_function function,
315                                                         void *user_data)
316 {
317         struct method_call_data *data;
318         DBusMessage *message;
319         DBusMessageIter iter;
320         DBusPendingCall *call;
321
322         if (!connection)
323                 return -EINVAL;
324
325         if (!path || !interface || !method)
326                 return -EINVAL;
327
328         data = dbus_malloc0(sizeof(*data));
329         if (!data)
330                 return -ENOMEM;
331
332         message = dbus_message_new_method_call(SUPPLICANT_SERVICE, path,
333                                                         interface, method);
334         if (!message) {
335                 dbus_free(data);
336                 return -ENOMEM;
337         }
338
339         dbus_message_set_auto_start(message, FALSE);
340
341         dbus_message_iter_init_append(message, &iter);
342         if (setup)
343                 setup(&iter, user_data);
344
345         if (!dbus_connection_send_with_reply(connection, message,
346                                                 &call, TIMEOUT)) {
347                 dbus_message_unref(message);
348                 dbus_free(data);
349                 return -EIO;
350         }
351
352         if (!call) {
353                 dbus_message_unref(message);
354                 dbus_free(data);
355                 return -EIO;
356         }
357
358         data->function = function;
359         data->user_data = user_data;
360
361         dbus_pending_call_set_notify(call, method_call_reply,
362                                                         data, dbus_free);
363
364         dbus_message_unref(message);
365
366         return 0;
367 }
368
369 void supplicant_dbus_property_append_basic(DBusMessageIter *iter,
370                                         const char *key, int type, void *val)
371 {
372         DBusMessageIter value;
373         const char *signature;
374
375         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &key);
376
377         switch (type) {
378         case DBUS_TYPE_BOOLEAN:
379                 signature = DBUS_TYPE_BOOLEAN_AS_STRING;
380                 break;
381         case DBUS_TYPE_STRING:
382                 signature = DBUS_TYPE_STRING_AS_STRING;
383                 break;
384         case DBUS_TYPE_BYTE:
385                 signature = DBUS_TYPE_BYTE_AS_STRING;
386                 break;
387         case DBUS_TYPE_UINT16:
388                 signature = DBUS_TYPE_UINT16_AS_STRING;
389                 break;
390         case DBUS_TYPE_INT16:
391                 signature = DBUS_TYPE_INT16_AS_STRING;
392                 break;
393         case DBUS_TYPE_UINT32:
394                 signature = DBUS_TYPE_UINT32_AS_STRING;
395                 break;
396         case DBUS_TYPE_INT32:
397                 signature = DBUS_TYPE_INT32_AS_STRING;
398                 break;
399         case DBUS_TYPE_OBJECT_PATH:
400                 signature = DBUS_TYPE_OBJECT_PATH_AS_STRING;
401                 break;
402         default:
403                 signature = DBUS_TYPE_VARIANT_AS_STRING;
404                 break;
405         }
406
407         dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
408                                                         signature, &value);
409         dbus_message_iter_append_basic(&value, type, val);
410         dbus_message_iter_close_container(iter, &value);
411 }