client: Fix various memory leaks in monitor and services parts
[platform/upstream/connman.git] / client / services.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 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 #include <stdio.h>
23 #include <stdlib.h>
24 #include <stdint.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <errno.h>
28
29 #include "client/services.h"
30 #include "src/connman.h"
31
32 static void append_property_array(DBusMessageIter *iter, char *property,
33                                                 char **data, int num_args)
34 {
35         DBusMessageIter value, array;
36         int i;
37
38         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &property);
39
40         connman_dbus_array_open(iter, &value);
41         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
42                                          DBUS_TYPE_STRING_AS_STRING, &array);
43
44         for (i = 0; i < num_args; i++) {
45                 dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING,
46                                                 &data[i]);
47                 printf("Added: %s\n", data[i]);
48         }
49         dbus_message_iter_close_container(&value, &array);
50         dbus_message_iter_close_container(iter, &value);
51 }
52
53 static void append_property_dict(DBusMessageIter *iter, char *property,
54                                         char **keys, char **data, int num_args)
55 {
56         DBusMessageIter value, dict, entry, dict_key;
57         int i;
58         unsigned char prefix;
59
60         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &property);
61
62         /* Top most level is a{sv} */
63         connman_dbus_dict_open_variant(iter, &value);
64
65         connman_dbus_dict_open(&value, &dict);
66
67         for (i = 0; i < num_args; i++) {
68                 dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY,
69                                                         NULL, &entry);
70                 dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING,
71                                                         &keys[i]);
72
73                 if (strcmp(property, "IPv6.Configuration") == 0 &&
74                                            g_strcmp0(keys[i], "PrefixLength")) {
75                         if (data[i] == NULL) {
76                                 fprintf(stderr, "No values entered!\n");
77                                 exit(EXIT_FAILURE);
78                         }
79                         prefix = atoi(data[i]);
80
81                         dbus_message_iter_open_container(&entry,
82                                                 DBUS_TYPE_VARIANT,
83                                                 DBUS_TYPE_BYTE_AS_STRING,
84                                                 &dict_key);
85                         dbus_message_iter_append_basic(&dict_key,
86                                                        DBUS_TYPE_BYTE, &prefix);
87                 } else {
88                         dbus_message_iter_open_container(&entry,
89                                                  DBUS_TYPE_VARIANT,
90                                                  DBUS_TYPE_STRING_AS_STRING,
91                                                  &dict_key);
92                         dbus_message_iter_append_basic(&dict_key,
93                                                         DBUS_TYPE_STRING,
94                                                         &data[i]);
95                 }
96                 dbus_message_iter_close_container(&entry, &dict_key);
97                 dbus_message_iter_close_container(&dict, &entry);
98         }
99         /* Close {sv}, then close a{sv} */
100         connman_dbus_dict_close(&value, &dict);
101         connman_dbus_dict_close(iter, &value);
102 }
103
104 void iterate_array(DBusMessageIter *iter)
105 {
106         DBusMessageIter array_item;
107         dbus_bool_t key_bool;
108         char *key_str;
109
110         dbus_message_iter_recurse(iter, &array_item);
111         /* Make sure the entry is not NULL! */
112         printf("[ ");
113         while (dbus_message_iter_get_arg_type(&array_item) !=
114                                         DBUS_TYPE_INVALID) {
115                 if (dbus_message_iter_get_arg_type(&array_item) ==
116                                         DBUS_TYPE_STRING) {
117                         dbus_message_iter_get_basic(&array_item,
118                                                 &key_str);
119                         printf("%s ", key_str);
120                 } else if (dbus_message_iter_get_arg_type(&array_item) ==
121                                         DBUS_TYPE_BOOLEAN) {
122                         dbus_message_iter_get_basic(&array_item, &key_bool);
123                         printf("%s ", key_bool == TRUE ? "True"
124                                                 : "False");
125                 }
126                 dbus_message_iter_next(&array_item);
127         }
128         if (dbus_message_iter_get_arg_type(&array_item) ==
129                                         DBUS_TYPE_INVALID)
130                 printf("] ");
131 }
132
133 void iterate_dict(DBusMessageIter *dict, char *string, uint16_t key_int)
134 {
135         DBusMessageIter dict_entry, sub_dict_entry;
136
137         printf("{ ");
138         while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
139                 dbus_message_iter_recurse(dict, &dict_entry);
140                 dbus_message_iter_get_basic(&dict_entry, &string);
141                 printf("%s=", string);
142                 dbus_message_iter_next(&dict_entry);
143                 while (dbus_message_iter_get_arg_type(&dict_entry)
144                                                         != DBUS_TYPE_INVALID) {
145                         dbus_message_iter_recurse(&dict_entry, &sub_dict_entry);
146                         if (dbus_message_iter_get_arg_type(&sub_dict_entry)
147                                                         == DBUS_TYPE_UINT16) {
148                                 dbus_message_iter_get_basic(&sub_dict_entry,
149                                                                 &key_int);
150                                 printf("%d ", key_int);
151                         } else if (dbus_message_iter_get_arg_type(&sub_dict_entry)
152                                                         == DBUS_TYPE_STRING) {
153                                 dbus_message_iter_get_basic(&sub_dict_entry,
154                                                                 &string);
155                                 printf("%s ", string);
156                         } else if (dbus_message_iter_get_arg_type(&sub_dict_entry)
157                                                         == DBUS_TYPE_ARRAY) {
158                                 iterate_array(&sub_dict_entry);
159                         }
160                         dbus_message_iter_next(&dict_entry);
161                 }
162                 dbus_message_iter_next(dict);
163         }
164         printf("}");
165 }
166
167 /* Get dictionary info about the current service and store it */
168 static void extract_service_properties(DBusMessageIter *dict,
169                                 struct service_data *service)
170 {
171         DBusMessageIter entry, value, array_item;
172         char *key;
173         char *key_str;
174         uint16_t key_uint16;
175         dbus_bool_t key_bool;
176
177         while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
178                 dbus_message_iter_recurse(dict, &entry);
179                 dbus_message_iter_get_basic(&entry, &key);
180                 printf("\n  %s = ", key);
181                 if (strcmp(key, "Name") == 0 && strlen(key) < 5)
182                         service->name = key;
183
184                 dbus_message_iter_next(&entry);
185                 dbus_message_iter_recurse(&entry, &value);
186                 /* Check if entry is a dictionary itself */
187                 if (strcmp(key, "Ethernet") == 0 ||
188                         /* if just strcmp, the .Configuration names don't match
189                          * and they are iterated with iterate_array instead*/
190                                 strncmp(key, "IPv4", 4) == 0 ||
191                                 strncmp(key, "IPv6", 4) == 0 ||
192                                 strncmp(key, "Proxy", 5) == 0 ||
193                                 strcmp(key, "Provider") == 0) {
194                         dbus_message_iter_recurse(&value, &array_item);
195                         iterate_dict(&array_item, key_str, key_uint16);
196                 } else
197                 switch (dbus_message_iter_get_arg_type(&value)) {
198                 case DBUS_TYPE_ARRAY:
199                         iterate_array(&value);
200                         break;
201                 case DBUS_TYPE_BOOLEAN:
202                         dbus_message_iter_get_basic(&value, &key_bool);
203                         printf("%s", key_bool == TRUE ? "True" : "False");
204                         break;
205                 case DBUS_TYPE_BYTE:
206                         dbus_message_iter_get_basic(&value, &key_uint16);
207                         printf("%d", key_uint16);
208                         break;
209                 case DBUS_TYPE_STRING:
210                         dbus_message_iter_get_basic(&value, &key_str);
211                         printf("%s", key_str);
212                         break;
213                 }
214                 dbus_message_iter_next(dict);
215         }
216         printf("\n\n");
217 }
218
219 static void match_service_name(DBusMessage *message, char *service_name,
220                                                 struct service_data *service)
221 {
222         DBusMessageIter iter, array;
223
224         dbus_message_iter_init(message, &iter);
225         dbus_message_iter_recurse(&iter, &array);
226
227         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRUCT) {
228                 DBusMessageIter entry, dict;
229                 char *path;
230
231                 dbus_message_iter_recurse(&array, &entry);
232                 dbus_message_iter_get_basic(&entry, &path);
233
234                 service->path = strip_service_path(path);
235                 dbus_message_iter_next(&entry);
236                 dbus_message_iter_recurse(&entry, &dict);
237                 extract_service_name(&dict, service);
238                 if (g_strcmp0(service_name, service->name) == 0) {
239                         printf("    Matched %s with %s\n\n", service->name,
240                                                                 service->path);
241                         break;
242                 }
243                 dbus_message_iter_next(&array);
244         }
245 }
246
247 void extract_service_name(DBusMessageIter *dict, struct service_data *service)
248 {
249         DBusMessageIter dict_entry, value;
250         const char *key;
251         const char *state;
252
253         while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
254                 dbus_message_iter_recurse(dict, &dict_entry);
255                 dbus_message_iter_get_basic(&dict_entry, &key);
256                 if (strcmp(key, "Name") == 0) {
257                         dbus_message_iter_next(&dict_entry);
258                         dbus_message_iter_recurse(&dict_entry, &value);
259                         dbus_message_iter_get_basic(&value, &service->name);
260                 }
261                 if (strcmp(key, "AutoConnect") == 0) {
262                         dbus_message_iter_next(&dict_entry);
263                         dbus_message_iter_recurse(&dict_entry, &value);
264                         dbus_message_iter_get_basic(&value, &service->autoconn);
265                 }
266                 if (strcmp(key, "State") == 0) {
267                         dbus_message_iter_next(&dict_entry);
268                         dbus_message_iter_recurse(&dict_entry, &value);
269                         dbus_message_iter_get_basic(&value, &state);
270                         if (strcmp(state, "ready") == 0) {
271                                 service->connected = TRUE;
272                                 service->online = FALSE;
273                         } else if (strcmp(state, "online") == 0) {
274                                 service->connected = FALSE;
275                                 service->online = TRUE;
276                         } else {
277                                 service->connected = FALSE;
278                                 service->online = FALSE;
279                         }
280                 }
281                 if (strcmp(key, "Favorite") == 0) {
282                         dbus_message_iter_next(&dict_entry);
283                         dbus_message_iter_recurse(&dict_entry, &value);
284                         dbus_message_iter_get_basic(&value, &service->favorite);
285                 }
286                 dbus_message_iter_next(dict);
287         }
288 }
289
290 /* Show detailed information about a service */
291 void extract_services(DBusMessage *message, char *service_name)
292 {
293         DBusMessageIter iter, array;
294
295         dbus_message_iter_init(message, &iter);
296         dbus_message_iter_recurse(&iter, &array);
297
298         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRUCT) {
299                 DBusMessageIter entry, dict;
300                 struct service_data service;
301                 char *path;
302
303                 dbus_message_iter_recurse(&array, &entry);
304                 dbus_message_iter_get_basic(&entry, &path);
305
306                 service.path = strip_service_path(path);
307                 if (g_strcmp0(service.path, service_name) == 0) {
308                         printf("[ %s ]\n", service.path);
309                         dbus_message_iter_next(&entry);
310                         dbus_message_iter_recurse(&entry, &dict);
311                         extract_service_properties(&dict, &service);
312                 }
313                 dbus_message_iter_next(&array);
314         }
315 }
316
317 /* Support both string names and path names for connecting to services */
318 char *strip_service_path(char *service)
319 {
320         char *service_name;
321         service_name = strrchr(service, '/');
322         if (service_name == NULL)
323                 return service;
324         else
325                 return service_name + 1;
326 }
327
328 /* Show a simple list of service names only */
329 void get_services(DBusMessage *message)
330 {
331         DBusMessageIter iter, array;
332
333         dbus_message_iter_init(message, &iter);
334         dbus_message_iter_recurse(&iter, &array);
335
336         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRUCT) {
337                 DBusMessageIter entry, dict;
338                 struct service_data service;
339                 char *path;
340
341                 dbus_message_iter_recurse(&array, &entry);
342                 dbus_message_iter_get_basic(&entry, &path);
343
344                 service.path = strip_service_path(path);
345                 dbus_message_iter_next(&entry);
346                 dbus_message_iter_recurse(&entry, &dict);
347                 extract_service_name(&dict, &service);
348                 printf("%-1s%-1s%-1s %-20s { %s }\n",
349                         service.favorite ? "*" : "",
350                         service.autoconn ? "A" : "",
351                         service.online ? "O" : (service.connected ? "R" : ""),
352                         service.name, service.path);
353                 dbus_message_iter_next(&array);
354         }
355 }
356
357 const char *find_service(DBusConnection *connection, DBusMessage *message,
358                           char *service_name, struct service_data *service)
359 {
360         DBusMessageIter iter, array, entry;
361         char *path;
362
363         service_name = strip_service_path(service_name);
364         match_service_name(message, service_name, service);
365         /* Service name did not match, so check if entry is a path */
366         if (g_strcmp0(service_name, service->name)) {
367                 dbus_message_iter_init(message, &iter);
368                 dbus_message_iter_recurse(&iter, &array);
369
370                 while (dbus_message_iter_get_arg_type(&array) ==
371                                                         DBUS_TYPE_STRUCT) {
372                         dbus_message_iter_recurse(&array, &entry);
373                         dbus_message_iter_get_basic(&entry, &path);
374
375                         service->path = strip_service_path(path);
376                         if (g_strcmp0(service->path, service_name) == 0)
377                                 return service->path;
378                         dbus_message_iter_next(&array);
379                 }
380                 fprintf(stderr, "'%s' is not a valid service name or path.\n",
381                                                                 service_name);
382                 fprintf(stderr, "Use the 'services' command to find available "
383                                                         "services.\n");
384                 return NULL;
385         } else
386                 return service->path;
387 }
388
389 int set_proxy_manual(DBusConnection *connection, DBusMessage *message,
390                                 char *name, char **servers, char **excludes,
391                                 int num_servers, int num_excludes)
392 {
393         DBusMessage *message_send;
394         DBusMessageIter iter, value, dict, entry, data;
395         struct service_data service;
396         char *path;
397         const char *path_name;
398         char *property = "Proxy.Configuration";
399         char *method = "Method";
400         char *manual = "manual";
401
402         path_name = find_service(connection, message, name, &service);
403         if (path_name == NULL)
404                 return -ENXIO;
405
406         path = g_strdup_printf("/net/connman/service/%s", path_name);
407         message_send = dbus_message_new_method_call("net.connman", path,
408                                                         "net.connman.Service",
409                                                         "SetProperty");
410
411         if (message_send == NULL) {
412                 g_free(path);
413                 return -ENOMEM;
414         }
415
416         dbus_message_iter_init_append(message_send, &iter);
417         dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &property);
418         connman_dbus_dict_open_variant(&iter, &value);
419         connman_dbus_dict_open(&value, &dict);
420         dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, NULL,
421                                                         &entry);
422         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &method);
423         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
424                                                 DBUS_TYPE_STRING_AS_STRING,
425                                                 &data);
426         dbus_message_iter_append_basic(&data, DBUS_TYPE_STRING, &manual);
427         dbus_message_iter_close_container(&entry, &data);
428         dbus_message_iter_close_container(&dict, &entry);
429         dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, NULL,
430                                                         &entry);
431         append_property_array(&entry, "Servers", servers, num_servers);
432         dbus_message_iter_close_container(&dict, &entry);
433
434         if (num_excludes != 0) {
435                 dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY,
436                                                         NULL, &entry);
437                 append_property_array(&entry, "Excludes", excludes,
438                                                         num_excludes);
439                 dbus_message_iter_close_container(&dict, &entry);
440         }
441
442         dbus_message_iter_close_container(&value, &dict);
443         dbus_message_iter_close_container(&iter, &value);
444         dbus_connection_send(connection, message_send, NULL);
445         dbus_connection_flush(connection);
446         dbus_message_unref(message_send);
447
448         g_free(path);
449
450         return 0;
451 }
452
453 int set_service_property(DBusConnection *connection, DBusMessage *message,
454                                 char *name, char *property, char **keys,
455                                 void *data, int num_args)
456 {
457         DBusMessage *message_send;
458         DBusMessageIter iter;
459         struct service_data service;
460         char *path;
461         const char *path_name;
462
463         path_name = find_service(connection, message, name, &service);
464         if (path_name == NULL)
465                 return -ENXIO;
466
467         path = g_strdup_printf("/net/connman/service/%s", path_name);
468         message_send = dbus_message_new_method_call("net.connman", path,
469                                                         "net.connman.Service",
470                                                         "SetProperty");
471
472         if (message_send == NULL) {
473                 g_free(path);
474                 return -ENOMEM;
475         }
476
477         dbus_message_iter_init_append(message_send, &iter);
478
479         if (strcmp(property, "AutoConnect") == 0)
480                 connman_dbus_property_append_basic(&iter,
481                                                 (const char *) property,
482                                                 DBUS_TYPE_BOOLEAN, data);
483         else if ((strcmp(property, "Domains.Configuration") == 0)
484                         || (strcmp(property, "Timeservers.Configuration") == 0)
485                         || (strcmp(property, "Nameservers.Configuration") == 0))
486                 append_property_array(&iter, property, data, num_args);
487         else if ((strcmp(property, "IPv4.Configuration") == 0)
488                         || (strcmp(property, "IPv6.Configuration") == 0)
489                         || (strcmp(property, "Proxy.Configuration") == 0))
490                 append_property_dict(&iter, property, keys, data, num_args);
491
492         dbus_connection_send(connection, message_send, NULL);
493         dbus_connection_flush(connection);
494         dbus_message_unref(message_send);
495         g_free(path);
496
497         return 0;
498 }