Add simple GetState method for really simple applications
[platform/upstream/connman.git] / src / manager.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2009  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 <gdbus.h>
27
28 #include "connman.h"
29
30 static connman_bool_t global_offlinemode = FALSE;
31
32 static void append_profiles(DBusMessageIter *dict)
33 {
34         DBusMessageIter entry, value, iter;
35         const char *key = "Profiles";
36
37         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
38                                                                 NULL, &entry);
39
40         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
41
42         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
43                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
44                                                                 &value);
45
46         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
47                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
48         __connman_profile_list(&iter);
49         dbus_message_iter_close_container(&value, &iter);
50
51         dbus_message_iter_close_container(&entry, &value);
52
53         dbus_message_iter_close_container(dict, &entry);
54 }
55
56 static void append_services(DBusMessageIter *dict)
57 {
58         DBusMessageIter entry, value, iter;
59         const char *key = "Services";
60
61         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
62                                                                 NULL, &entry);
63
64         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
65
66         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
67                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
68                                                                 &value);
69
70         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
71                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
72         __connman_service_list(&iter);
73         dbus_message_iter_close_container(&value, &iter);
74
75         dbus_message_iter_close_container(&entry, &value);
76
77         dbus_message_iter_close_container(dict, &entry);
78 }
79
80 static void append_devices(DBusMessageIter *dict)
81 {
82         DBusMessageIter entry, value, iter;
83         const char *key = "Devices";
84
85         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
86                                                                 NULL, &entry);
87
88         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
89
90         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
91                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
92                                                                 &value);
93
94         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
95                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
96         __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_DEVICE, &iter);
97         dbus_message_iter_close_container(&value, &iter);
98
99         dbus_message_iter_close_container(&entry, &value);
100
101         dbus_message_iter_close_container(dict, &entry);
102 }
103
104 static void append_connections(DBusMessageIter *dict)
105 {
106         DBusMessageIter entry, value, iter;
107         const char *key = "Connections";
108
109         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
110                                                                 NULL, &entry);
111
112         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
113
114         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
115                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
116                                                                 &value);
117
118         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
119                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
120         __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION, &iter);
121         dbus_message_iter_close_container(&value, &iter);
122
123         dbus_message_iter_close_container(&entry, &value);
124
125         dbus_message_iter_close_container(dict, &entry);
126 }
127
128 static void append_available_technologies(DBusMessageIter *dict)
129 {
130         DBusMessageIter entry, value, iter;
131         const char *key = "AvailableTechnologies";
132
133         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
134                                                                 NULL, &entry);
135
136         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
137
138         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
139                         DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING,
140                                                                 &value);
141
142         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
143                                         DBUS_TYPE_STRING_AS_STRING, &iter);
144         __connman_notifier_list_registered(&iter);
145         dbus_message_iter_close_container(&value, &iter);
146
147         dbus_message_iter_close_container(&entry, &value);
148
149         dbus_message_iter_close_container(dict, &entry);
150 }
151
152 static void append_enabled_technologies(DBusMessageIter *dict)
153 {
154         DBusMessageIter entry, value, iter;
155         const char *key = "EnabledTechnologies";
156
157         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
158                                                                 NULL, &entry);
159
160         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
161
162         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
163                         DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING,
164                                                                 &value);
165
166         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
167                                         DBUS_TYPE_STRING_AS_STRING, &iter);
168         __connman_notifier_list_enabled(&iter);
169         dbus_message_iter_close_container(&value, &iter);
170
171         dbus_message_iter_close_container(&entry, &value);
172
173         dbus_message_iter_close_container(dict, &entry);
174 }
175
176 static void append_connected_technologies(DBusMessageIter *dict)
177 {
178         DBusMessageIter entry, value, iter;
179         const char *key = "ConnectedTechnologies";
180
181         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
182                                                                 NULL, &entry);
183
184         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
185
186         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
187                         DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING,
188                                                                 &value);
189
190         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
191                                         DBUS_TYPE_STRING_AS_STRING, &iter);
192         __connman_notifier_list_connected(&iter);
193         dbus_message_iter_close_container(&value, &iter);
194
195         dbus_message_iter_close_container(&entry, &value);
196
197         dbus_message_iter_close_container(dict, &entry);
198 }
199
200 static DBusMessage *get_properties(DBusConnection *conn,
201                                         DBusMessage *msg, void *data)
202 {
203         DBusMessage *reply;
204         DBusMessageIter array, dict;
205         const char *str;
206
207         DBG("conn %p", conn);
208
209         if (__connman_security_check_privilege(msg,
210                                         CONNMAN_SECURITY_PRIVILEGE_PUBLIC) < 0)
211                 return __connman_error_permission_denied(msg);
212
213         reply = dbus_message_new_method_return(msg);
214         if (reply == NULL)
215                 return NULL;
216
217         dbus_message_iter_init_append(reply, &array);
218
219         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
220                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
221                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
222                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
223
224         str = __connman_profile_active_path();
225         if (str != NULL)
226                 connman_dbus_dict_append_variant(&dict, "ActiveProfile",
227                                                 DBUS_TYPE_OBJECT_PATH, &str);
228
229         append_profiles(&dict);
230         append_services(&dict);
231
232         append_devices(&dict);
233         append_connections(&dict);
234
235         if (__connman_element_count(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION) > 0)
236                 str = "online";
237         else
238                 str = "offline";
239
240         connman_dbus_dict_append_variant(&dict, "State",
241                                                 DBUS_TYPE_STRING, &str);
242
243         connman_dbus_dict_append_variant(&dict, "OfflineMode",
244                                 DBUS_TYPE_BOOLEAN, &global_offlinemode);
245
246         append_available_technologies(&dict);
247         append_enabled_technologies(&dict);
248         append_connected_technologies(&dict);
249
250         dbus_message_iter_close_container(&array, &dict);
251
252         return reply;
253 }
254
255 static DBusMessage *set_property(DBusConnection *conn,
256                                         DBusMessage *msg, void *data)
257 {
258         DBusMessageIter iter, value;
259         const char *name;
260
261         DBG("conn %p", conn);
262
263         if (dbus_message_iter_init(msg, &iter) == FALSE)
264                 return __connman_error_invalid_arguments(msg);
265
266         dbus_message_iter_get_basic(&iter, &name);
267         dbus_message_iter_next(&iter);
268         dbus_message_iter_recurse(&iter, &value);
269
270         if (__connman_security_check_privilege(msg,
271                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
272                 return __connman_error_permission_denied(msg);
273
274         if (g_str_equal(name, "OfflineMode") == TRUE) {
275                 connman_bool_t offlinemode;
276
277                 dbus_message_iter_get_basic(&value, &offlinemode);
278
279                 if (global_offlinemode == offlinemode)
280                         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
281
282                 global_offlinemode = offlinemode;
283
284                 __connman_device_set_offlinemode(offlinemode);
285         } else if (g_str_equal(name, "ActiveProfile") == TRUE) {
286                 const char *str;
287
288                 dbus_message_iter_get_basic(&value, &str);
289
290                 return __connman_error_not_supported(msg);
291         } else
292                 return __connman_error_invalid_property(msg);
293
294         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
295 }
296
297 static DBusMessage *get_state(DBusConnection *conn,
298                                         DBusMessage *msg, void *data)
299 {
300         const char *str;
301
302         DBG("conn %p", conn);
303
304         if (__connman_security_check_privilege(msg,
305                                         CONNMAN_SECURITY_PRIVILEGE_PUBLIC) < 0)
306                 return __connman_error_permission_denied(msg);
307
308         if (__connman_element_count(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION) > 0)
309                 str = "online";
310         else
311                 str = "offline";
312
313         return g_dbus_create_reply(msg, DBUS_TYPE_STRING, &str,
314                                                 DBUS_TYPE_INVALID);
315 }
316
317 static DBusMessage *add_profile(DBusConnection *conn,
318                                         DBusMessage *msg, void *data)
319 {
320         const char *name;
321
322         DBG("conn %p", conn);
323
324         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &name,
325                                                         DBUS_TYPE_INVALID);
326
327         return __connman_error_not_supported(msg);
328 }
329
330 static DBusMessage *remove_profile(DBusConnection *conn,
331                                         DBusMessage *msg, void *data)
332 {
333         const char *path;
334
335         DBG("conn %p", conn);
336
337         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
338                                                         DBUS_TYPE_INVALID);
339
340         return __connman_error_not_supported(msg);
341 }
342
343 static DBusMessage *request_scan(DBusConnection *conn,
344                                         DBusMessage *msg, void *data)
345 {
346         enum connman_device_type type;
347         const char *str;
348         int err;
349
350         DBG("conn %p", conn);
351
352         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &str,
353                                                         DBUS_TYPE_INVALID);
354
355         if (g_strcmp0(str, "") == 0)
356                 type = CONNMAN_DEVICE_TYPE_UNKNOWN;
357         else if (g_strcmp0(str, "wifi") == 0)
358                 type = CONNMAN_DEVICE_TYPE_WIFI;
359         else if (g_strcmp0(str, "wimax") == 0)
360                 type = CONNMAN_DEVICE_TYPE_WIMAX;
361         else
362                 return __connman_error_invalid_arguments(msg);
363
364         err = __connman_element_request_scan(type);
365         if (err < 0) {
366                 if (err == -EINPROGRESS) {
367                         connman_error("Invalid return code from scan");
368                         err = -EINVAL;
369                 }
370
371                 return __connman_error_failed(msg, -err);
372         }
373
374         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
375 }
376
377 static DBusMessage *enable_technology(DBusConnection *conn,
378                                         DBusMessage *msg, void *data)
379 {
380         enum connman_device_type type;
381         const char *str;
382         int err;
383
384         DBG("conn %p", conn);
385
386         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &str,
387                                                         DBUS_TYPE_INVALID);
388
389         if (g_strcmp0(str, "ethernet") == 0)
390                 type = CONNMAN_DEVICE_TYPE_ETHERNET;
391         else if (g_strcmp0(str, "wifi") == 0)
392                 type = CONNMAN_DEVICE_TYPE_WIFI;
393         else if (g_strcmp0(str, "wimax") == 0)
394                 type = CONNMAN_DEVICE_TYPE_WIMAX;
395         else if (g_strcmp0(str, "bluetooth") == 0)
396                 type = CONNMAN_DEVICE_TYPE_BLUETOOTH;
397         else if (g_strcmp0(str, "gps") == 0)
398                 type = CONNMAN_DEVICE_TYPE_GPS;
399         else
400                 return __connman_error_invalid_arguments(msg);
401
402         err = __connman_element_enable_technology(type);
403         if (err < 0) {
404                 if (err == -EINPROGRESS) {
405                         connman_error("Invalid return code from enable");
406                         err = -EINVAL;
407                 }
408
409                 return __connman_error_failed(msg, -err);
410         }
411
412         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
413 }
414
415 static DBusMessage *disable_technology(DBusConnection *conn,
416                                         DBusMessage *msg, void *data)
417 {
418         enum connman_device_type type;
419         const char *str;
420         int err;
421
422         DBG("conn %p", conn);
423
424         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &str,
425                                                         DBUS_TYPE_INVALID);
426
427         if (g_strcmp0(str, "ethernet") == 0)
428                 type = CONNMAN_DEVICE_TYPE_ETHERNET;
429         else if (g_strcmp0(str, "wifi") == 0)
430                 type = CONNMAN_DEVICE_TYPE_WIFI;
431         else if (g_strcmp0(str, "wimax") == 0)
432                 type = CONNMAN_DEVICE_TYPE_WIMAX;
433         else if (g_strcmp0(str, "bluetooth") == 0)
434                 type = CONNMAN_DEVICE_TYPE_BLUETOOTH;
435         else if (g_strcmp0(str, "gps") == 0)
436                 type = CONNMAN_DEVICE_TYPE_GPS;
437         else
438                 return __connman_error_invalid_arguments(msg);
439
440         err = __connman_element_disable_technology(type);
441         if (err < 0) {
442                 if (err == -EINPROGRESS) {
443                         connman_error("Invalid return code from disable");
444                         err = -EINVAL;
445                 }
446
447                 return __connman_error_failed(msg, -err);
448         }
449
450         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
451 }
452
453 static DBusMessage *connect_service(DBusConnection *conn,
454                                         DBusMessage *msg, void *data)
455 {
456         int err;
457
458         DBG("conn %p", conn);
459
460         if (__connman_security_check_privilege(msg,
461                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
462                 return __connman_error_permission_denied(msg);
463
464         err = __connman_service_create_and_connect(msg);
465         if (err < 0) {
466                 if (err == -EINPROGRESS) {
467                         connman_error("Invalid return code from connect");
468                         err = -EINVAL;
469                 }
470
471                 return __connman_error_failed(msg, -err);
472         }
473
474         return NULL;
475 }
476
477 static DBusMessage *register_agent(DBusConnection *conn,
478                                         DBusMessage *msg, void *data)
479 {
480         DBusMessage *reply;
481         const char *sender, *path;
482
483         DBG("conn %p", conn);
484
485         sender = dbus_message_get_sender(msg);
486
487         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
488                                                         DBUS_TYPE_INVALID);
489
490         reply = dbus_message_new_method_return(msg);
491         if (reply == NULL)
492                 return NULL;
493
494         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
495
496         __connman_agent_register(sender, path);
497
498         return reply;
499 }
500
501 static DBusMessage *unregister_agent(DBusConnection *conn,
502                                         DBusMessage *msg, void *data)
503 {
504         DBusMessage *reply;
505         const char *sender, *path;
506
507         DBG("conn %p", conn);
508
509         sender = dbus_message_get_sender(msg);
510
511         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
512                                                         DBUS_TYPE_INVALID);
513
514         reply = dbus_message_new_method_return(msg);
515         if (reply == NULL)
516                 return NULL;
517
518         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
519
520         __connman_agent_unregister(sender, path);
521
522         return reply;
523 }
524
525 static GDBusMethodTable manager_methods[] = {
526         { "GetProperties",     "",      "a{sv}", get_properties     },
527         { "SetProperty",       "sv",    "",      set_property       },
528         { "GetState",          "",      "s",     get_state          },
529         { "AddProfile",        "s",     "o",     add_profile        },
530         { "RemoveProfile",     "o",     "",      remove_profile     },
531         { "RequestScan",       "s",     "",      request_scan       },
532         { "EnableTechnology",  "s",     "",      enable_technology  },
533         { "DisableTechnology", "s",     "",      disable_technology },
534         { "ConnectService",    "a{sv}", "o",     connect_service,
535                                                 G_DBUS_METHOD_FLAG_ASYNC },
536         { "RegisterAgent",     "o",     "",      register_agent     },
537         { "UnregisterAgent",   "o",     "",      unregister_agent   },
538         { },
539 };
540
541 static GDBusSignalTable manager_signals[] = {
542         { "PropertyChanged", "sv" },
543         { "StateChanged",    "s"  },
544         { },
545 };
546
547 static DBusMessage *nm_sleep(DBusConnection *conn,
548                                         DBusMessage *msg, void *data)
549 {
550         DBusMessage *reply;
551
552         DBG("conn %p", conn);
553
554         reply = dbus_message_new_method_return(msg);
555         if (reply == NULL)
556                 return NULL;
557
558         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
559
560         return reply;
561 }
562
563 static DBusMessage *nm_wake(DBusConnection *conn,
564                                         DBusMessage *msg, void *data)
565 {
566         DBusMessage *reply;
567
568         DBG("conn %p", conn);
569
570         reply = dbus_message_new_method_return(msg);
571         if (reply == NULL)
572                 return NULL;
573
574         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
575
576         return reply;
577 }
578
579 enum {
580         NM_STATE_UNKNOWN = 0,
581         NM_STATE_ASLEEP,
582         NM_STATE_CONNECTING,
583         NM_STATE_CONNECTED,
584         NM_STATE_DISCONNECTED
585 };
586
587 static DBusMessage *nm_state(DBusConnection *conn,
588                                         DBusMessage *msg, void *data)
589 {
590         DBusMessage *reply;
591         dbus_uint32_t state;
592
593         DBG("conn %p", conn);
594
595         reply = dbus_message_new_method_return(msg);
596         if (reply == NULL)
597                 return NULL;
598
599         state = NM_STATE_DISCONNECTED;
600
601         dbus_message_append_args(reply, DBUS_TYPE_UINT32, &state,
602                                                         DBUS_TYPE_INVALID);
603
604         return reply;
605 }
606
607 static GDBusMethodTable nm_methods[] = {
608         { "sleep", "",  "",   nm_sleep        },
609         { "wake",  "",  "",   nm_wake         },
610         { "state", "",  "u",  nm_state        },
611         { },
612 };
613
614 static DBusConnection *connection = NULL;
615 static gboolean nm_compat = FALSE;
616
617 int __connman_manager_init(DBusConnection *conn, gboolean compat)
618 {
619         DBG("conn %p", conn);
620
621         connection = dbus_connection_ref(conn);
622         if (connection == NULL)
623                 return -1;
624
625         g_dbus_register_interface(connection, CONNMAN_MANAGER_PATH,
626                                         CONNMAN_MANAGER_INTERFACE,
627                                         manager_methods,
628                                         manager_signals, NULL, NULL, NULL);
629
630         if (compat == TRUE) {
631                 g_dbus_register_interface(connection, NM_PATH, NM_INTERFACE,
632                                         nm_methods, NULL, NULL, NULL, NULL);
633
634                 nm_compat = TRUE;
635         }
636
637         return 0;
638 }
639
640 void __connman_manager_cleanup(void)
641 {
642         DBG("conn %p", connection);
643
644         if (nm_compat == TRUE) {
645                 g_dbus_unregister_interface(connection, NM_PATH, NM_INTERFACE);
646         }
647
648         g_dbus_unregister_interface(connection, CONNMAN_MANAGER_PATH,
649                                                 CONNMAN_MANAGER_INTERFACE);
650
651         dbus_connection_unref(connection);
652 }