diff options
author | Marcel Holtmann <marcel@holtmann.org> | 2009-08-04 15:46:48 -0700 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2009-08-04 15:46:48 -0700 |
commit | 426befc5c790fb87a82e42647fb56d1ae831fcac (patch) | |
tree | 92e465b35a2f335316c138cf2d40467392dd771a | |
parent | aac35324deb8c0b57f881338d87cb36b0979e7df (diff) | |
download | connman-426befc5c790fb87a82e42647fb56d1ae831fcac.tar.gz connman-426befc5c790fb87a82e42647fb56d1ae831fcac.tar.bz2 connman-426befc5c790fb87a82e42647fb56d1ae831fcac.zip |
Add support for creating, modifying and removing profiles
-rw-r--r-- | doc/manager-api.txt | 9 | ||||
-rw-r--r-- | doc/profile-api.txt | 6 | ||||
-rw-r--r-- | include/Makefile.am | 5 | ||||
-rw-r--r-- | include/profile.h | 41 | ||||
-rw-r--r-- | include/storage.h | 15 | ||||
-rw-r--r-- | src/connman.h | 55 | ||||
-rw-r--r-- | src/device.c | 16 | ||||
-rw-r--r-- | src/element.c | 4 | ||||
-rw-r--r-- | src/error.c | 16 | ||||
-rw-r--r-- | src/manager.c | 111 | ||||
-rw-r--r-- | src/profile.c | 525 | ||||
-rw-r--r-- | src/service.c | 10 | ||||
-rw-r--r-- | src/storage.c | 108 | ||||
-rw-r--r-- | test/Makefile.am | 2 | ||||
-rwxr-xr-x | test/test-profile | 102 |
15 files changed, 827 insertions, 198 deletions
diff --git a/doc/manager-api.txt b/doc/manager-api.txt index e83ac10d..18efc15b 100644 --- a/doc/manager-api.txt +++ b/doc/manager-api.txt @@ -29,13 +29,10 @@ Methods dict GetProperties() Possible Errors: [service].Error.InvalidArguments - object AddProfile(string name) + object CreateProfile(string name) - Add a new profile with the specified name. - - It is possible to create two profiles with the same - name. The identification is done via the object path - and not the name of the profile. + Create and add new profile with the specified + identifier name. Possible Errors: [service].Error.InvalidArguments diff --git a/doc/profile-api.txt b/doc/profile-api.txt index f807070e..b30f4187 100644 --- a/doc/profile-api.txt +++ b/doc/profile-api.txt @@ -21,6 +21,12 @@ Properties string Name [readonly] Name of this profile. + boolean OfflineMode [readwrite] + + The offline mode indicates the setting for switching + all radios on or off. Changing offline mode to true + results in powering down all devices. + array{object} Services [readonly] List of service objects. diff --git a/include/Makefile.am b/include/Makefile.am index 53e991d9..6f2218c8 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -6,8 +6,9 @@ include_HEADERS = types.h log.h plugin.h security.h notifier.h \ nodist_include_HEADERS = version.h -noinst_HEADERS = driver.h element.h property.h rtnl.h wifi.h dbus.h \ - rfkill.h resolver.h ipconfig.h service.h option.h +noinst_HEADERS = driver.h element.h property.h rtnl.h wifi.h \ + dbus.h rfkill.h option.h resolver.h ipconfig.h \ + profile.h service.h MAINTAINERCLEANFILES = Makefile.in diff --git a/include/profile.h b/include/profile.h new file mode 100644 index 00000000..a225c46b --- /dev/null +++ b/include/profile.h @@ -0,0 +1,41 @@ +/* + * + * Connection Manager + * + * Copyright (C) 2007-2009 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __CONNMAN_PROFILE_H +#define __CONNMAN_PROFILE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * SECTION:profile + * @title: Profile premitives + * @short_description: Functions for handling profiles + */ + +struct connman_profile; + +#ifdef __cplusplus +} +#endif + +#endif /* __CONNMAN_PROFILE_H */ diff --git a/include/storage.h b/include/storage.h index 437d72b8..4cee7614 100644 --- a/include/storage.h +++ b/include/storage.h @@ -22,9 +22,9 @@ #ifndef __CONNMAN_STORAGE_H #define __CONNMAN_STORAGE_H -#include <connman/device.h> -#include <connman/network.h> +#include <connman/profile.h> #include <connman/service.h> +#include <connman/device.h> #ifdef __cplusplus extern "C" { @@ -43,14 +43,15 @@ extern "C" { struct connman_storage { const char *name; int priority; - int (*global_load) (void); - int (*global_save) (void); - enum connman_device_type device_type; - int (*device_load) (struct connman_device *device); - int (*device_save) (struct connman_device *device); + int (*profile_init) (void); + int (*profile_load) (struct connman_profile *profile); + int (*profile_save) (struct connman_profile *profile); enum connman_service_type service_type; int (*service_load) (struct connman_service *service); int (*service_save) (struct connman_service *service); + enum connman_device_type device_type; + int (*device_load) (struct connman_device *device); + int (*device_save) (struct connman_device *device); }; int connman_storage_register(struct connman_storage *storage); diff --git a/src/connman.h b/src/connman.h index 38e78ec8..80134dbf 100644 --- a/src/connman.h +++ b/src/connman.h @@ -38,8 +38,10 @@ DBusMessage *__connman_error_permission_denied(DBusMessage *msg); DBusMessage *__connman_error_passphrase_required(DBusMessage *msg); DBusMessage *__connman_error_not_supported(DBusMessage *msg); DBusMessage *__connman_error_not_implemented(DBusMessage *msg); +DBusMessage *__connman_error_not_found(DBusMessage *msg); DBusMessage *__connman_error_no_carrier(DBusMessage *msg); DBusMessage *__connman_error_in_progress(DBusMessage *msg); +DBusMessage *__connman_error_already_exists(DBusMessage *msg); DBusMessage *__connman_error_already_enabled(DBusMessage *msg); DBusMessage *__connman_error_already_disabled(DBusMessage *msg); DBusMessage *__connman_error_already_connected(DBusMessage *msg); @@ -56,23 +58,12 @@ int __connman_selftest(void); int __connman_manager_init(DBusConnection *conn, gboolean compat); void __connman_manager_cleanup(void); -connman_bool_t __connman_manager_get_offlinemode(void); - int __connman_agent_init(DBusConnection *conn); void __connman_agent_cleanup(void); int __connman_agent_register(const char *sender, const char *path); int __connman_agent_unregister(const char *sender, const char *path); -int __connman_profile_init(DBusConnection *conn); -void __connman_profile_cleanup(void); - -void __connman_profile_list(DBusMessageIter *iter); -const char *__connman_profile_active_ident(void); -const char *__connman_profile_active_path(void); - -void __connman_profile_changed(gboolean delayed); - #include <connman/log.h> int __connman_log_init(gboolean detach, gboolean debug); @@ -131,18 +122,18 @@ int __connman_resolver_selftest(void); int __connman_storage_init(void); void __connman_storage_cleanup(void); -GKeyFile *__connman_storage_open(void); -void __connman_storage_close(GKeyFile *keyfile, gboolean save); - -int __connman_storage_load_global(); -int __connman_storage_save_global(); +GKeyFile *__connman_storage_open(const char *ident); +void __connman_storage_close(const char *ident, + GKeyFile *keyfile, gboolean save); +void __connman_storage_delete(const char *ident); -int __connman_storage_init_device(); -int __connman_storage_load_device(struct connman_device *device); -int __connman_storage_save_device(struct connman_device *device); -int __connman_storage_init_service(); +int __connman_storage_init_profile(void); +int __connman_storage_load_profile(struct connman_profile *profile); +int __connman_storage_save_profile(struct connman_profile *profile); int __connman_storage_load_service(struct connman_service *service); int __connman_storage_save_service(struct connman_service *service); +int __connman_storage_load_device(struct connman_device *device); +int __connman_storage_save_device(struct connman_device *device); #include <connman/driver.h> @@ -246,9 +237,6 @@ const char *__connman_device_get_ident(struct connman_device *device); int __connman_device_set_offlinemode(connman_bool_t offlinemode); -int __connman_profile_add_device(struct connman_device *device); -int __connman_profile_remove_device(struct connman_device *device); - #include <connman/network.h> int __connman_network_init(void); @@ -267,6 +255,27 @@ const char *__connman_network_get_group(struct connman_network *network); const char *__connman_network_get_ident(struct connman_network *network); connman_bool_t __connman_network_get_weakness(struct connman_network *network); +#include <connman/profile.h> + +int __connman_profile_init(DBusConnection *conn); +void __connman_profile_cleanup(void); + +connman_bool_t __connman_profile_get_offlinemode(void); +int __connman_profile_set_offlinemode(connman_bool_t offlinemode); +int __connman_profile_save_default(void); + +void __connman_profile_list(DBusMessageIter *iter); +const char *__connman_profile_active_ident(void); +const char *__connman_profile_active_path(void); + +int __connman_profile_create(const char *name, const char **path); +int __connman_profile_remove(const char *path); + +void __connman_profile_changed(gboolean delayed); + +int __connman_profile_add_device(struct connman_device *device); +int __connman_profile_remove_device(struct connman_device *device); + int __connman_profile_add_network(struct connman_network *network); int __connman_profile_update_network(struct connman_network *network); int __connman_profile_remove_network(struct connman_network *network); diff --git a/src/device.c b/src/device.c index 01141cfa..984f55f5 100644 --- a/src/device.c +++ b/src/device.c @@ -331,7 +331,9 @@ static int set_powered(struct connman_device *device, connman_bool_t powered) if (err == 0) { device->powered = powered; - powered_changed(device); + + if (device->registered == TRUE) + powered_changed(device); } return err; @@ -1748,7 +1750,7 @@ int connman_device_register(struct connman_device *device) { __connman_storage_load_device(device); - device->offlinemode = __connman_manager_get_offlinemode(); + device->offlinemode = __connman_profile_get_offlinemode(); return connman_element_register(&device->element, NULL); } @@ -1857,6 +1859,7 @@ static struct connman_driver device_driver = { static int device_load(struct connman_device *device) { + const char *ident = __connman_profile_active_ident(); GKeyFile *keyfile; GError *error = NULL; gchar *identifier; @@ -1865,7 +1868,7 @@ static int device_load(struct connman_device *device) DBG("device %p", device); - keyfile = __connman_storage_open(); + keyfile = __connman_storage_open(ident); if (keyfile == NULL) return 0; @@ -1896,19 +1899,20 @@ static int device_load(struct connman_device *device) done: g_free(identifier); - __connman_storage_close(keyfile, FALSE); + __connman_storage_close(ident, keyfile, FALSE); return 0; } static int device_save(struct connman_device *device) { + const char *ident = __connman_profile_active_ident(); GKeyFile *keyfile; gchar *identifier; DBG("device %p", device); - keyfile = __connman_storage_open(); + keyfile = __connman_storage_open(ident); if (keyfile == NULL) return 0; @@ -1934,7 +1938,7 @@ static int device_save(struct connman_device *device) done: g_free(identifier); - __connman_storage_close(keyfile, TRUE); + __connman_storage_close(ident, keyfile, TRUE); return 0; } diff --git a/src/element.c b/src/element.c index 7a456274..3b774944 100644 --- a/src/element.c +++ b/src/element.c @@ -1584,7 +1584,7 @@ void __connman_element_start(void) { DBG(""); - __connman_storage_load_global(); + __connman_storage_init_profile(); g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1, probe_node, NULL); @@ -1606,8 +1606,6 @@ void __connman_element_stop(void) __connman_rfkill_cleanup(); __connman_ipv4_cleanup(); __connman_connection_cleanup(); - - __connman_storage_save_global(); } static gboolean free_driver(GNode *node, gpointer data) diff --git a/src/error.c b/src/error.c index c250d257..4217091e 100644 --- a/src/error.c +++ b/src/error.c @@ -35,8 +35,12 @@ DBusMessage *__connman_error_failed(DBusMessage *msg, int errnum) const char *str = strerror(errnum); switch (errnum) { + case ENXIO: + return __connman_error_not_found(msg); case EACCES: return __connman_error_permission_denied(msg); + case EEXIST: + return __connman_error_already_exists(msg); case EINVAL: return __connman_error_invalid_arguments(msg); case ENOSYS: @@ -93,6 +97,12 @@ DBusMessage *__connman_error_not_implemented(DBusMessage *msg) ".NotImplemented", "Not implemented"); } +DBusMessage *__connman_error_not_found(DBusMessage *msg) +{ + return g_dbus_create_error(msg, CONNMAN_ERROR_INTERFACE + ".NotFound", "Not found"); +} + DBusMessage *__connman_error_no_carrier(DBusMessage *msg) { return g_dbus_create_error(msg, CONNMAN_ERROR_INTERFACE @@ -105,6 +115,12 @@ DBusMessage *__connman_error_in_progress(DBusMessage *msg) ".InProgress", "In progress"); } +DBusMessage *__connman_error_already_exists(DBusMessage *msg) +{ + return g_dbus_create_error(msg, CONNMAN_ERROR_INTERFACE + ".AlreadyExists", "Already exists"); +} + DBusMessage *__connman_error_already_enabled(DBusMessage *msg) { return g_dbus_create_error(msg, CONNMAN_ERROR_INTERFACE diff --git a/src/manager.c b/src/manager.c index 8e34791e..30a24e81 100644 --- a/src/manager.c +++ b/src/manager.c @@ -27,13 +27,6 @@ #include "connman.h" -static connman_bool_t global_offlinemode = FALSE; - -connman_bool_t __connman_manager_get_offlinemode(void) -{ - return global_offlinemode; -} - static void append_profiles(DBusMessageIter *dict) { DBusMessageIter entry, value, iter; @@ -207,6 +200,7 @@ static DBusMessage *get_properties(DBusConnection *conn, { DBusMessage *reply; DBusMessageIter array, dict; + connman_bool_t offlinemode; const char *str; DBG("conn %p", conn); @@ -245,8 +239,9 @@ static DBusMessage *get_properties(DBusConnection *conn, connman_dbus_dict_append_variant(&dict, "State", DBUS_TYPE_STRING, &str); + offlinemode = __connman_profile_get_offlinemode(); connman_dbus_dict_append_variant(&dict, "OfflineMode", - DBUS_TYPE_BOOLEAN, &global_offlinemode); + DBUS_TYPE_BOOLEAN, &offlinemode); append_available_technologies(&dict); append_enabled_technologies(&dict); @@ -267,6 +262,7 @@ static DBusMessage *set_property(DBusConnection *conn, { DBusMessageIter iter, value; const char *name; + int type; DBG("conn %p", conn); @@ -281,19 +277,19 @@ static DBusMessage *set_property(DBusConnection *conn, CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0) return __connman_error_permission_denied(msg); + type = dbus_message_iter_get_arg_type(&value); + if (g_str_equal(name, "OfflineMode") == TRUE) { connman_bool_t offlinemode; - dbus_message_iter_get_basic(&value, &offlinemode); - - if (global_offlinemode == offlinemode) - return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); + if (type != DBUS_TYPE_BOOLEAN) + return __connman_error_invalid_arguments(msg); - global_offlinemode = offlinemode; + dbus_message_iter_get_basic(&value, &offlinemode); - __connman_storage_save_global(); + __connman_profile_set_offlinemode(offlinemode); - __connman_device_set_offlinemode(offlinemode); + __connman_profile_save_default(); } else if (g_str_equal(name, "ActiveProfile") == TRUE) { const char *str; @@ -326,30 +322,49 @@ static DBusMessage *get_state(DBusConnection *conn, DBUS_TYPE_INVALID); } -static DBusMessage *add_profile(DBusConnection *conn, +static DBusMessage *create_profile(DBusConnection *conn, DBusMessage *msg, void *data) { - const char *name; + const char *name, *path; + int err; DBG("conn %p", conn); dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID); - return __connman_error_not_supported(msg); + if (__connman_security_check_privilege(msg, + CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0) + return __connman_error_permission_denied(msg); + + err = __connman_profile_create(name, &path); + if (err < 0) + return __connman_error_failed(msg, -err); + + return g_dbus_create_reply(msg, DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_INVALID); } static DBusMessage *remove_profile(DBusConnection *conn, DBusMessage *msg, void *data) { const char *path; + int err; DBG("conn %p", conn); dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID); - return __connman_error_not_supported(msg); + if (__connman_security_check_privilege(msg, + CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0) + return __connman_error_permission_denied(msg); + + err = __connman_profile_remove(path); + if (err < 0) + return __connman_error_failed(msg, -err); + + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } static DBusMessage *request_scan(DBusConnection *conn, @@ -613,7 +628,7 @@ static GDBusMethodTable manager_methods[] = { { "GetProperties", "", "a{sv}", get_properties }, { "SetProperty", "sv", "", set_property }, { "GetState", "", "s", get_state }, - { "AddProfile", "s", "o", add_profile }, + { "CreateProfile", "s", "o", create_profile }, { "RemoveProfile", "o", "", remove_profile }, { "RequestScan", "s", "", request_scan }, { "EnableTechnology", "s", "", enable_technology, @@ -703,57 +718,6 @@ static GDBusMethodTable nm_methods[] = { { }, }; -static int manager_load(void) -{ - GKeyFile *keyfile; - GError *error = NULL; - connman_bool_t offlinemode; - - DBG(""); - - keyfile = __connman_storage_open(); - if (keyfile == NULL) - return -EIO; - - offlinemode = g_key_file_get_boolean(keyfile, "global", - "OfflineMode", &error); - if (error == NULL) { - global_offlinemode = offlinemode; - - __connman_device_set_offlinemode(offlinemode); - } - g_clear_error(&error); - - __connman_storage_close(keyfile, FALSE); - - return 0; -} - -static int manager_save(void) -{ - GKeyFile *keyfile; - - DBG(""); - - keyfile = __connman_storage_open(); - if (keyfile == NULL) - return -EIO; - - g_key_file_set_boolean(keyfile, "global", - "OfflineMode", global_offlinemode); - - __connman_storage_close(keyfile, TRUE); - - return 0; -} - -static struct connman_storage manager_storage = { - .name = "manager", - .priority = CONNMAN_STORAGE_PRIORITY_LOW, - .global_load = manager_load, - .global_save = manager_save, -}; - static gboolean nm_compat = FALSE; int __connman_manager_init(DBusConnection *conn, gboolean compat) @@ -764,9 +728,6 @@ int __connman_manager_init(DBusConnection *conn, gboolean compat) if (connection == NULL) return -1; - if (connman_storage_register(&manager_storage) < 0) - connman_error("Failed to register manager storage"); - if (connman_notifier_register(&technology_notifier) < 0) connman_error("Failed to register technology notifier"); @@ -791,8 +752,6 @@ void __connman_manager_cleanup(void) connman_notifier_unregister(&technology_notifier); - connman_storage_unregister(&manager_storage); - if (nm_compat == TRUE) { g_dbus_unregister_interface(connection, NM_PATH, NM_INTERFACE); } diff --git a/src/profile.c b/src/profile.c index 63c2f44e..edddd20b 100644 --- a/src/profile.c +++ b/src/profile.c @@ -23,6 +23,8 @@ #include <config.h> #endif +#include <string.h> + #include <glib.h> #include <gdbus.h> @@ -30,8 +32,160 @@ #define PROFILE_DEFAULT_IDENT "default" +struct connman_profile { + char *ident; + char *path; + char *name; + connman_bool_t offlinemode; +}; + +static GHashTable *profiles = NULL; +static struct connman_profile *default_profile = NULL; + static DBusConnection *connection = NULL; +static void append_path(gpointer key, gpointer value, gpointer user_data) +{ + struct connman_profile *profile = value; + DBusMessageIter *iter = user_data; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, + &profile->path); +} + +void __connman_profile_list(DBusMessageIter *iter) +{ + DBG(""); + + g_hash_table_foreach(profiles, append_path, iter); +} + +static void append_profiles(DBusMessageIter *entry) +{ + DBusMessageIter value, iter; + const char *key = "Profiles"; + + dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key); + + dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT, + DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING, + &value); + + dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY, + DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter); + __connman_profile_list(&iter); + dbus_message_iter_close_container(&value, &iter); + + dbus_message_iter_close_container(entry, &value); +} + +static void profiles_changed(void) +{ + DBusMessage *signal; + DBusMessageIter entry; + + DBG(""); + + signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH, + CONNMAN_MANAGER_INTERFACE, "PropertyChanged"); + if (signal == NULL) + return; + + dbus_message_iter_init_append(signal, &entry); + append_profiles(&entry); + g_dbus_send_message(connection, signal); +} + +static void name_changed(struct connman_profile *profile) +{ + DBusMessage *signal; + DBusMessageIter entry, value; + const char *key = "Name"; + + DBG("profile %p", profile); + + signal = dbus_message_new_signal(profile->path, + CONNMAN_PROFILE_INTERFACE, "PropertyChanged"); + if (signal == NULL) + return; + + dbus_message_iter_init_append(signal, &entry); + + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key); + + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, + DBUS_TYPE_STRING_AS_STRING, &value); + dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, + &profile->name); + dbus_message_iter_close_container(&entry, &value); + + g_dbus_send_message(connection, signal); +} + +static void offlinemode_changed(struct connman_profile *profile) +{ + DBusMessage *signal; + DBusMessageIter entry, value; + const char *key = "OfflineMode"; + + DBG("profile %p", profile); + + signal = dbus_message_new_signal(profile->path, + CONNMAN_PROFILE_INTERFACE, "PropertyChanged"); + if (signal == NULL) + return; + + dbus_message_iter_init_append(signal, &entry); + + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key); + + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, + DBUS_TYPE_BOOLEAN_AS_STRING, &value); + dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, + &profile->offlinemode); + dbus_message_iter_close_container(&entry, &value); + + g_dbus_send_message(connection, signal); +} + +connman_bool_t __connman_profile_get_offlinemode(void) +{ + if (default_profile == NULL) + return FALSE; + + DBG("offlinemode %d", default_profile->offlinemode); + + return default_profile->offlinemode; +} + +int __connman_profile_set_offlinemode(connman_bool_t offlinemode) +{ + DBG("offlinemode %d", offlinemode); + + if (default_profile == NULL) + return -EINVAL; + + if (default_profile->offlinemode == offlinemode) + return -EALREADY; + + default_profile->offlinemode = offlinemode; + offlinemode_changed(default_profile); + + __connman_device_set_offlinemode(offlinemode); + + return 0; +} + +int __connman_profile_save_default(void) +{ + DBG(""); + + if (default_profile != NULL) + __connman_storage_save_profile(default_profile); + + return 0; +} + const char *__connman_profile_active_ident(void) { DBG(""); @@ -43,10 +197,14 @@ const char *__connman_profile_active_path(void) { DBG(""); - return "/profile/" PROFILE_DEFAULT_IDENT; + if (default_profile == NULL) + return NULL; + + return default_profile->path; } -static void append_services(DBusMessageIter *entry) +static void append_services(struct connman_profile *profile, + DBusMessageIter *entry) { DBusMessageIter value, iter; const char *key = "Services"; @@ -59,7 +217,10 @@ static void append_services(DBusMessageIter *entry) dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter); - __connman_service_list(&iter); + + if (g_strcmp0(profile->ident, PROFILE_DEFAULT_IDENT) == 0) + __connman_service_list(&iter); + dbus_message_iter_close_container(&value, &iter); dbus_message_iter_close_container(entry, &value); @@ -69,28 +230,34 @@ static guint changed_timeout = 0; static gboolean services_changed(gpointer user_data) { - const char *path = __connman_profile_active_path(); + struct connman_profile *profile = default_profile; DBusMessage *signal; DBusMessageIter entry; changed_timeout = 0; - signal = dbus_message_new_signal(path, + if (profile == NULL) + return FALSE; + + signal = dbus_message_new_signal(profile->path, CONNMAN_PROFILE_INTERFACE, "PropertyChanged"); if (signal == NULL) return FALSE; dbus_message_iter_init_append(signal, &entry); - append_services(&entry); + append_services(profile, &entry); g_dbus_send_message(connection, signal); + if (g_strcmp0(profile->ident, PROFILE_DEFAULT_IDENT) != 0) + return FALSE; + signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH, CONNMAN_MANAGER_INTERFACE, "PropertyChanged"); if (signal == NULL) return FALSE; dbus_message_iter_init_append(signal, &entry); - append_services(&entry); + append_services(profile, &entry); g_dbus_send_message(connection, signal); return FALSE; @@ -171,19 +338,10 @@ int __connman_profile_remove_network(struct connman_network *network) return 0; } -void __connman_profile_list(DBusMessageIter *iter) -{ - const char *path = __connman_profile_active_path(); - - DBG(""); - - dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path); -} - static DBusMessage *get_properties(DBusConnection *conn, DBusMessage *msg, void *data) { - const char *name = "Default"; + struct connman_profile *profile = data; DBusMessage *reply; DBusMessageIter array, dict, entry; @@ -200,12 +358,16 @@ static DBusMessage *get_properties(DBusConnection *conn, DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); - connman_dbus_dict_append_variant(&dict, "Name", - DBUS_TYPE_STRING, &name); + if (profile->name != NULL) + connman_dbus_dict_append_variant(&dict, "Name", + DBUS_TYPE_STRING, &profile->name); + + connman_dbus_dict_append_variant(&dict, "OfflineMode", + DBUS_TYPE_BOOLEAN, &profile->offlinemode); dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, NULL, &entry); - append_services(&entry); + append_services(profile, &entry); dbus_message_iter_close_container(&dict, &entry); dbus_message_iter_close_container(&array, &dict); @@ -213,8 +375,68 @@ static DBusMessage *get_properties(DBusConnection *conn, return reply; } +static DBusMessage *set_property(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct connman_profile *profile = data; + DBusMessageIter iter, value; + const char *name; + int type; + + DBG("conn %p", conn); + + if (dbus_message_iter_init(msg, &iter) == FALSE) + return __connman_error_invalid_arguments(msg); + + dbus_message_iter_get_basic(&iter, &name); + dbus_message_iter_next(&iter); + dbus_message_iter_recurse(&iter, &value); + + if (__connman_security_check_privilege(msg, + CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0) + return __connman_error_permission_denied(msg); + + type = dbus_message_iter_get_arg_type(&value); + + if (g_str_equal(name, "Name") == TRUE) { + const char *name; + + if (type != DBUS_TYPE_STRING) + return __connman_error_invalid_arguments(msg); + + dbus_message_iter_get_basic(&value, &name); + + g_free(profile->name); + profile->name = g_strdup(name); + + if (profile->name != NULL) + name_changed(profile); + + __connman_storage_save_profile(profile); + } else if (g_str_equal(name, "OfflineMode") == TRUE) { + connman_bool_t offlinemode; + + if (type != DBUS_TYPE_BOOLEAN) + return __connman_error_invalid_arguments(msg); + + dbus_message_iter_get_basic(&value, &offlinemode); + + if (profile->offlinemode == offlinemode) + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); + + profile->offlinemode = offlinemode; + offlinemode_changed(profile); + + __connman_storage_save_profile(profile); + } else + return __connman_error_invalid_property(msg); + + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); +} + static GDBusMethodTable profile_methods[] = { - { "GetProperties", "", "a{sv}", get_properties }, + { "GetProperties", "", "a{sv}", get_properties }, + { "SetProperty", "sv", "", set_property }, { }, }; @@ -223,32 +445,273 @@ static GDBusSignalTable profile_signals[] = { { }, }; -int __connman_profile_init(DBusConnection *conn) +static void free_profile(struct connman_profile *profile) +{ + g_free(profile->name); + g_free(profile->path); + g_free(profile); +} + +static void unregister_profile(gpointer data) +{ + struct connman_profile *profile = data; + + DBG("profile %p", profile); + + connman_info("Removing profile %s", profile->ident); + + g_dbus_unregister_interface(connection, profile->path, + CONNMAN_PROFILE_INTERFACE); + + if (g_strcmp0(profile->ident, PROFILE_DEFAULT_IDENT) == 0) + default_profile = NULL; + + free_profile(profile); +} + +static int create_profile(const char *ident, const char *name, + const char **path) +{ + struct connman_profile *profile; + + DBG("ident %s name %s", ident, name); + + profile = g_try_new0(struct connman_profile, 1); + if (profile == NULL) + return -ENOMEM; + + profile->ident = g_strdup(ident); + profile->path = g_strdup_printf("/profile/%s", ident); + + if (profile->ident == NULL || profile->path == NULL) { + free_profile(profile); + return -ENOMEM; + } + + if (g_hash_table_lookup(profiles, profile->path) != NULL) { + free_profile(profile); + return -EEXIST; + } + + profile->name = g_strdup(name); + + __connman_storage_load_profile(profile); + + g_hash_table_insert(profiles, g_strdup(profile->path), profile); + + connman_info("Adding profile %s", ident); + + if (g_strcmp0(ident, PROFILE_DEFAULT_IDENT) == 0) + default_profile = profile; + + g_dbus_register_interface(connection, profile->path, + CONNMAN_PROFILE_INTERFACE, + profile_methods, profile_signals, + NULL, profile, NULL); + + if (path != NULL) + *path = profile->path; + + DBG("profile %p path %s", profile, profile->path); + + return 0; +} + +static gboolean validate_ident(const char *ident) +{ + unsigned int i; + + for (i = 0; i < strlen(ident); i++) { + if (ident[i] >= '0' && ident[i] <= '9') + continue; + if (ident[i] >= 'a' && ident[i] <= 'z') + continue; + if (ident[i] >= 'A' && ident[i] <= 'Z') + continue; + return FALSE; + } + + return TRUE; +} + +int __connman_profile_create(const char *name, const char **path) +{ + struct connman_profile *profile; + int err; + + DBG("name %s", name); + + if (validate_ident(name) == FALSE) + return -EINVAL; + + err = create_profile(name, NULL, path); + if (err < 0) + return err; + + profile = g_hash_table_lookup(profiles, *path); + if (profile == NULL) + return -EIO; + + __connman_storage_save_profile(profile); + + profiles_changed(); + + return 0; +} + +int __connman_profile_remove(const char *path) +{ + struct connman_profile *profile; + + DBG("path %s", path); + + if (default_profile != NULL && + g_strcmp0(path, default_profile->path) == 0) + return -EINVAL; + + profile = g_hash_table_lookup(profiles, path); + if (profile == NULL) + return -ENXIO; + + __connman_storage_delete(profile->ident); + + g_hash_table_remove(profiles, path); + + profiles_changed(); + + return 0; +} + +static int profile_init(void) +{ + GDir *dir; + const gchar *file; + + DBG(""); + + dir = g_dir_open(STORAGEDIR, 0, NULL); + if (dir != NULL) { + while ((file = g_dir_read_name(dir)) != NULL) { + GString *str; + gchar *ident; + + if (g_str_has_suffix(file, ".profile") == FALSE) + continue; + + ident = g_strrstr(file, ".profile"); + if (ident == NULL) + continue; + + str = g_string_new_len(file, ident - file); + if (str == NULL) + continue; + + ident = g_string_free(str, FALSE); + + if (validate_ident(ident) == TRUE) + create_profile(ident, NULL, NULL); + + g_free(ident); + } + + g_dir_close(dir); + } + + if (g_hash_table_size(profiles) == 0) + create_profile(PROFILE_DEFAULT_IDENT, "Default", NULL); + + profiles_changed(); + + return 0; +} + +static int profile_load(struct connman_profile *profile) +{ + GKeyFile *keyfile; + GError *error = NULL; + connman_bool_t offlinemode; + char *name; + + DBG("profile %p", profile); + + keyfile = __connman_storage_open(profile->ident); + if (keyfile == NULL) + return -EIO; + + name = g_key_file_get_string(keyfile, "global", "Name", NULL); + if (name != NULL) { + g_free(profile->name); + profile->name = name; + } + + offlinemode = g_key_file_get_boolean(keyfile, "global", + "OfflineMode", &error); + if (error == NULL) + profile->offlinemode = offlinemode; + g_clear_error(&error); + + __connman_storage_close(profile->ident, keyfile, FALSE); + + return 0; +} + +static int profile_save(struct connman_profile *profile) { - const char *path = __connman_profile_active_path(); + GKeyFile *keyfile; + + DBG("profile %p", profile); + + keyfile = __connman_storage_open(profile->ident); + if (keyfile == NULL) + return -EIO; + + if (profile->name != NULL) + g_key_file_set_string(keyfile, "global", + "Name", profile->name); + + g_key_file_set_boolean(keyfile, "global", + "OfflineMode", profile->offlinemode); + __connman_storage_close(profile->ident, keyfile, TRUE); + + return 0; +} + +static struct connman_storage profile_storage = { + .name = "profile", + .priority = CONNMAN_STORAGE_PRIORITY_LOW, + .profile_init = profile_init, + .profile_load = profile_load, + .profile_save = profile_save, +}; + +int __connman_profile_init(DBusConnection *conn) +{ DBG("conn %p", conn); connection = dbus_connection_ref(conn); if (connection == NULL) return -1; - g_dbus_register_interface(connection, path, - CONNMAN_PROFILE_INTERFACE, - profile_methods, profile_signals, - NULL, NULL, NULL); + if (connman_storage_register(&profile_storage) < 0) + connman_error("Failed to register profile storage"); + + profiles = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, unregister_profile); return 0; } void __connman_profile_cleanup(void) { - const char *path = __connman_profile_active_path(); - DBG("conn %p", connection); - g_dbus_unregister_interface(connection, path, - CONNMAN_PROFILE_INTERFACE); + if (profiles != NULL) { + g_hash_table_destroy(profiles); + profiles = NULL; + } + + connman_storage_unregister(&profile_storage); if (connection == NULL) return; diff --git a/src/service.c b/src/service.c index b7784720..1d52afef 100644 --- a/src/service.c +++ b/src/service.c @@ -1874,6 +1874,7 @@ void __connman_service_remove_from_network(struct connman_network *network) static int service_load(struct connman_service *service) { + const char *ident = service->profile; GKeyFile *keyfile; gchar *pathname, *data = NULL; gsize length; @@ -1883,10 +1884,10 @@ static int service_load(struct connman_service *service) DBG("service %p", service); - if (service->profile == NULL) + if (ident == NULL) return -EINVAL; - pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR, service->profile); + pathname = g_strdup_printf("%s/%s.profile", STORAGEDIR, ident); if (pathname == NULL) return -ENOMEM; @@ -2001,6 +2002,7 @@ done: static int service_save(struct connman_service *service) { + const char *ident = service->profile; GKeyFile *keyfile; gchar *pathname, *data = NULL; gsize length; @@ -2009,10 +2011,10 @@ static int service_save(struct connman_service *service) DBG("service %p", service); - if (service->profile == NULL) + if (ident == NULL) return -EINVAL; - pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR, service->profile); + pathname = g_strdup_printf("%s/%s.profile", STORAGEDIR, ident); if (pathname == NULL) return -ENOMEM; diff --git a/src/storage.c b/src/storage.c index 34df8625..04721692 100644 --- a/src/storage.c +++ b/src/storage.c @@ -23,6 +23,8 @@ #include <config.h> #endif +#include <unistd.h> + #include "connman.h" static GSList *storage_list = NULL; @@ -66,17 +68,16 @@ void connman_storage_unregister(struct connman_storage *storage) storage_list = g_slist_remove(storage_list, storage); } -GKeyFile *__connman_storage_open(void) +GKeyFile *__connman_storage_open(const char *ident) { GKeyFile *keyfile; gchar *pathname, *data = NULL; gboolean result; gsize length; - DBG(""); + DBG("ident %s", ident); - pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR, - __connman_profile_active_ident()); + pathname = g_strdup_printf("%s/%s.profile", STORAGEDIR, ident); if (pathname == NULL) return NULL; @@ -84,39 +85,36 @@ GKeyFile *__connman_storage_open(void) g_free(pathname); - if (result == FALSE) - return NULL; - keyfile = g_key_file_new(); - if (length > 0) { - if (g_key_file_load_from_data(keyfile, data, length, - 0, NULL) == FALSE) - goto done; - } + if (result == FALSE) + goto done; + + if (length > 0) + g_key_file_load_from_data(keyfile, data, length, 0, NULL); -done: g_free(data); +done: DBG("keyfile %p", keyfile); return keyfile; } -void __connman_storage_close(GKeyFile *keyfile, gboolean save) +void __connman_storage_close(const char *ident, + GKeyFile *keyfile, gboolean save) { gchar *pathname, *data = NULL; gsize length = 0; - DBG("keyfile %p save %d", keyfile, save); + DBG("ident %s keyfile %p save %d", ident, keyfile, save); if (save == FALSE) { g_key_file_free(keyfile); return; } - pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR, - __connman_profile_active_ident()); + pathname = g_strdup_printf("%s/%s.profile", STORAGEDIR, ident); if (pathname == NULL) return; @@ -132,7 +130,21 @@ void __connman_storage_close(GKeyFile *keyfile, gboolean save) g_key_file_free(keyfile); } -int __connman_storage_load_global(void) +void __connman_storage_delete(const char *ident) +{ + gchar *pathname; + + DBG("ident %s", ident); + + pathname = g_strdup_printf("%s/%s.profile", STORAGEDIR, ident); + if (pathname == NULL) + return; + + if (unlink(pathname) < 0) + connman_error("Failed to remove %s", pathname); +} + +int __connman_storage_init_profile(void) { GSList *list; @@ -141,8 +153,8 @@ int __connman_storage_load_global(void) for (list = storage_list; list; list = list->next) { struct connman_storage *storage = list->data; - if (storage->global_load) { - if (storage->global_load() == 0) + if (storage->profile_init) { + if (storage->profile_init() == 0) return 0; } } @@ -150,17 +162,17 @@ int __connman_storage_load_global(void) return -ENOENT; } -int __connman_storage_save_global(void) +int __connman_storage_load_profile(struct connman_profile *profile) { GSList *list; - DBG(""); + DBG("profile %p", profile); for (list = storage_list; list; list = list->next) { struct connman_storage *storage = list->data; - if (storage->global_save) { - if (storage->global_save() == 0) + if (storage->profile_load) { + if (storage->profile_load(profile) == 0) return 0; } } @@ -168,17 +180,17 @@ int __connman_storage_save_global(void) return -ENOENT; } -int __connman_storage_load_device(struct connman_device *device) +int __connman_storage_save_profile(struct connman_profile *profile) { GSList *list; - DBG("device %p", device); + DBG("profile %p", profile); for (list = storage_list; list; list = list->next) { struct connman_storage *storage = list->data; - if (storage->device_load) { - if (storage->device_load(device) == 0) + if (storage->profile_save) { + if (storage->profile_save(profile) == 0) return 0; } } @@ -186,17 +198,17 @@ int __connman_storage_load_device(struct connman_device *device) return -ENOENT; } -int __connman_storage_save_device(struct connman_device *device) +int __connman_storage_load_service(struct connman_service *service) { GSList *list; - DBG("device %p", device); + DBG("service %p", service); for (list = storage_list; list; list = list->next) { struct connman_storage *storage = list->data; - if (storage->device_save) { - if (storage->device_save(device) == 0) + if (storage->service_load) { + if (storage->service_load(service) == 0) return 0; } } @@ -204,7 +216,7 @@ int __connman_storage_save_device(struct connman_device *device) return -ENOENT; } -int __connman_storage_load_service(struct connman_service *service) +int __connman_storage_save_service(struct connman_service *service) { GSList *list; @@ -213,8 +225,8 @@ int __connman_storage_load_service(struct connman_service *service) for (list = storage_list; list; list = list->next) { struct connman_storage *storage = list->data; - if (storage->service_load) { - if (storage->service_load(service) == 0) + if (storage->service_save) { + if (storage->service_save(service) == 0) return 0; } } @@ -222,17 +234,35 @@ int __connman_storage_load_service(struct connman_service *service) return -ENOENT; } -int __connman_storage_save_service(struct connman_service *service) +int __connman_storage_load_device(struct connman_device *device) { GSList *list; - DBG("service %p", service); + DBG("device %p", device); for (list = storage_list; list; list = list->next) { struct connman_storage *storage = list->data; - if (storage->service_save) { - if (storage->service_save(service) == 0) + if (storage->device_load) { + if (storage->device_load(device) == 0) + return 0; + } + } + + return -ENOENT; +} + +int __connman_storage_save_device(struct connman_device *device) +{ + GSList *list; + + DBG("device %p", device); + + for (list = storage_list; list; list = list->next) { + struct connman_storage *storage = list->data; + + if (storage->device_save) { + if (storage->device_save(device) == 0) return 0; } } diff --git a/test/Makefile.am b/test/Makefile.am index 32bc04c0..1840a01b 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -2,7 +2,7 @@ EXTRA_DIST = get-state list-profiles list-services connect-service \ list-connections select-connection \ list-devices enable-device disable-device start-scanning \ - list-networks set-passphrase set-address \ + list-networks set-passphrase set-address test-profile \ simple-agent show-introspection test-compat test-manager \ test-connman monitor-connman monitor-services debug-connman diff --git a/test/test-profile b/test/test-profile new file mode 100755 index 00000000..8f659551 --- /dev/null +++ b/test/test-profile @@ -0,0 +1,102 @@ +#!/usr/bin/python + +import sys +import dbus + +bus = dbus.SystemBus() + +manager = dbus.Interface(bus.get_object("org.moblin.connman", "/"), + "org.moblin.connman.Manager") + +if len(sys.argv) < 2: + print "Usage: %s <command>" % (sys.argv[0]) + print "" + print " list" + print " name <profile> [name]" + print "" + print " create <profile> [name]" + print " remove <profile>" + sys.exit(1) + +def print_profiles(profiles, active): + for path in profiles: + profile = dbus.Interface(bus.get_object("org.moblin.connman", path), + "org.moblin.connman.Profile") + + properties = profile.GetProperties() + + identifier = path[path.rfind("/") + 1:] + + if (path == active): + default = "*" + else: + default = " " + + if "Name" in properties.keys(): + name = properties["Name"] + else: + name = "<unnamed>" + + print "%s %-12s %s" % (default, identifier, name) + +if sys.argv[1] in ["list", "show"]: + properties = manager.GetProperties() + + print_profiles(properties["Profiles"], properties["ActiveProfile"]) + +elif sys.argv[1] in ["name"]: + if (len(sys.argv) < 3): + print "Need at least profile parameter" + sys.exit(1) + + path = "/profile/" + sys.argv[2] + + profile = dbus.Interface(bus.get_object("org.moblin.connman", path), + "org.moblin.connman.Profile") + + if (len(sys.argv) > 3): + name = sys.argv[3] + + profile.SetProperty("Name", name); + + print "Name \"%s\" set for %s" % (name, sys.argv[2]) + else: + properties = profile.GetProperties() + + if "Name" in properties.keys(): + name = "\"" + properties["Name"] + "\"" + else: + name = "<unnamed>" + + print "Name for %s is %s" % (sys.argv[2], name) + +elif sys.argv[1] in ["create", "add"]: + if (len(sys.argv) < 3): + print "Profile parameter required" + sys.exit(1) + + path = manager.CreateProfile(sys.argv[2]) + + print "New profile created at %s" % (path) + + profile = dbus.Interface(bus.get_object("org.moblin.connman", path), + "org.moblin.connman.Profile") + + if (len(sys.argv) > 3): + name = sys.argv[3] + + profile.SetProperty("Name", name); + + print "Name \"%s\" set for %s" % (name, sys.argv[2]) + +elif sys.argv[1] in ["remove", "delete", "del"]: + if (len(sys.argv) < 3): + print "Profile parameter required" + sys.exit(1) + + path = "/profile/" + sys.argv[2] + + manager.RemoveProfile(path) + +else: + print "Unknown command" |