Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(151)

Unified Diff: src/profile.c

Issue 6731067: flimflam: revise multi-profile support to pin objects to a profile (Closed) Base URL: ssh://gitrw.chromium.org:9222/flimflam.git@master
Patch Set: fix diff Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/notifier.c ('k') | src/service.c » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/profile.c
diff --git a/src/profile.c b/src/profile.c
index 30fb5cec27866ff5844c5f24e2094c3664dc31f3..80ba988c122a1f2cdece5452545b94db45d890b9 100644
--- a/src/profile.c
+++ b/src/profile.c
@@ -39,6 +39,7 @@
struct connman_profile {
struct connman_storage_ident ident;
+ guint changed_timeout;
char *path;
char *name;
connman_bool_t offlinemode;
@@ -54,8 +55,42 @@ static struct connman_storage_ident default_ident = {
};
static struct connman_profile *default_profile = NULL;
+static guint changed_timeout = 0; /* for NULL profile handling */
+
static DBusConnection *connection = NULL;
+/*
+ * Loading/Saving objects.
+ *
+ * Service objects go to the profile they are pinned to (typically
+ * the active profile at the time they were created but this can be
+ * changed, e.g. from private -> global).
+ *
+ * Device and ipconfig objects go in the global profile (if any).
+ * This ensures that enable/disable state is maintained between
+ * users (and reboots); or possibly discarded (e.g. for testing).
+ *
+ * Likewise global state like offline mode is stored in the global
+ * profile (see above).
+ */
+
+/*
+ * Return the active profile; it's on the top of the stack.
+ */
+static inline struct connman_profile *active_profile(void)
+{
+ return cur_profile >= 0 ? profile_stack[cur_profile] : NULL;
+}
+
+/*
+ * Return the global profile; it's top-most non-user profile.
+ */
+static struct connman_profile *global_profile(void)
+{
+ /* TODO(sleffler) cheat for now */
+ return default_profile != NULL ? default_profile : NULL;
+}
+
static int ident_equal(const struct connman_storage_ident *a,
const struct connman_storage_ident *b)
{
@@ -86,63 +121,72 @@ static void profiles_changed(void)
connman_bool_t __connman_profile_get_offlinemode(void)
{
- return (default_profile == NULL) ? FALSE : default_profile->offlinemode;
+ struct connman_profile *profile = global_profile();
+ return (profile == NULL) ? FALSE : profile->offlinemode;
}
int __connman_profile_set_offlinemode(connman_bool_t offlinemode)
{
- _DBG_PROFILE("offlinemode %d", offlinemode);
+ struct connman_profile *profile = global_profile();
+ int ret;
+
+ _DBG_PROFILE("offlinemode %d profile %p", offlinemode, profile);
- /* TODO(sleffler) disallow if no default profile? */
- if (default_profile != NULL) {
+ /* NB: always succeeds (ATM) */
+ ret = __connman_device_set_offlinemode(offlinemode);
+ if (ret != 0)
+ return ret;
+
+ /* TODO(sleffler) sallow even if no global profile? */
+ if (profile != NULL) {
/*
* OfflineMode is only saved to the default profile;
* this ensures it is preserved across user changes.
*/
- if (default_profile->offlinemode == offlinemode)
+ if (profile->offlinemode == offlinemode)
return -EALREADY;
- default_profile->offlinemode = offlinemode;
+ profile->offlinemode = offlinemode;
connman_dbus_send_property_changed_variant(
- default_profile->path,
+ profile->path,
CONNMAN_PROFILE_INTERFACE, "OfflineMode",
DBUS_TYPE_BOOLEAN, &offlinemode);
- }
- return __connman_device_set_offlinemode(offlinemode);
-}
-/*
- * Return the active profile; it's on the top of the stack.
- */
-static inline struct connman_profile *active_profile(void)
-{
- return cur_profile >= 0 ? profile_stack[cur_profile] : NULL;
+ __connman_storage_save_profile(profile);
+ }
+ return 0;
}
-/*
- * Load/Save objects. When loading we walk the stack of profiles
- * until we find a successful load. Saving always happens to the
- * top-most/active profile.
- */
-
static inline int load_continue(int err)
{
- /* NB: ENXIO for no file, ESRCH for no group/key */
+ /* NB: ENXIO for no file, ESRCH for no entry */
return (err == -ENXIO || err == -ESRCH);
}
int __connman_profile_load_service(struct connman_service *service)
{
- int i, err;
+ struct connman_profile *profile =
+ __connman_service_get_profile(service);
+ int err, i;
- _DBG_PROFILE("service %p", service);
+ _DBG_PROFILE("service %p profile %p", service, profile);
+ if (profile != NULL)
+ return __connman_storage_load_service(service, &profile->ident);
+ /*
+ * Not bound to a profile yet, search the stack for an
+ * entry and if found bind the profile to the service.
+ */
err = 0;
for (i = cur_profile; i >= 0; i--) {
- const struct connman_profile *profile = profile_stack[i];
-
+ profile = profile_stack[i];
err = __connman_storage_load_service(service, &profile->ident);
+ if (err == 0) {
+ _DBG_PROFILE("bind to profile %p", profile);
+ __connman_service_set_profile(service, profile);
+ return 0;
+ }
if (!load_continue(err))
break;
}
@@ -151,34 +195,34 @@ int __connman_profile_load_service(struct connman_service *service)
int __connman_profile_save_service(struct connman_service *service)
{
- struct connman_profile *profile = active_profile();
+ struct connman_profile *profile =
+ __connman_service_get_profile(service);
_DBG_PROFILE("service %p profile %p", service, profile);
+ if (profile == NULL) {
+ /* not bound yet, bind to the active profile */
+ profile = active_profile();
+ _DBG_PROFILE("bind to profile %p", profile);
+ __connman_service_set_profile(service, profile);
+ }
return (profile == NULL) ? 0 :
__connman_storage_save_service(service, &profile->ident);
}
int __connman_profile_load_device(struct connman_device *device)
{
- int i, err;
-
- _DBG_PROFILE("device %p", device);
+ struct connman_profile *profile = global_profile();
- err = 0;
- for (i = cur_profile; i >= 0; i--) {
- const struct connman_profile *profile = profile_stack[i];
+ _DBG_PROFILE("device %p profile %p", device, profile);
- err = __connman_storage_load_device(device, &profile->ident);
- if (!load_continue(err))
- break;
- }
- return err;
+ return (profile == NULL) ? 0 :
+ __connman_storage_load_device(device, &profile->ident);
}
int __connman_profile_save_device(struct connman_device *device)
{
- struct connman_profile *profile = active_profile();
+ struct connman_profile *profile = global_profile();
_DBG_PROFILE("device %p profile %p", device, profile);
@@ -188,25 +232,17 @@ int __connman_profile_save_device(struct connman_device *device)
int __connman_profile_load_ipconfig(struct connman_ipconfig *ipconfig)
{
- int i, err;
+ struct connman_profile *profile = global_profile();
- _DBG_PROFILE("ipconfig %p", ipconfig);
-
- err = 0;
- for (i = cur_profile; i >= 0; i--) {
- const struct connman_profile *profile = profile_stack[i];
+ _DBG_PROFILE("ipconfig %p profile %p", ipconfig, profile);
- err = __connman_storage_load_ipconfig(ipconfig,
- &profile->ident);
- if (!load_continue(err))
- break;
- }
- return err;
+ return (profile == NULL) ? 0:
+ __connman_storage_load_ipconfig(ipconfig, &profile->ident);
}
int __connman_profile_save_ipconfig(const struct connman_ipconfig *ipconfig)
{
- struct connman_profile *profile = active_profile();
+ struct connman_profile *profile = global_profile();
_DBG_PROFILE("ipconfig %p profile %p", ipconfig, profile);
@@ -236,29 +272,29 @@ int __connman_profile_append_hidden_ssids(GSList **hidden_ssids,
}
/*
- * Save the default profile if registered.
+ * Return the object path for the specified profile.
*/
-int __connman_profile_save_default(void)
+const char *__connman_profile_get_path(const struct connman_profile *profile)
{
- if (default_profile != NULL)
- __connman_storage_save_profile(default_profile);
- return 0;
+ return profile != NULL ? profile->path : NULL;
}
/*
- * Save the active profile (if any).
+ * Return the profile given an object path.
*/
-int __connman_profile_save_active(void)
+struct connman_profile *__connman_profile_lookup_profile(const char *path)
{
- struct connman_profile *profile = active_profile();
- return (profile == NULL) ? -EINVAL :
- __connman_storage_save_profile(profile);
+ return g_hash_table_lookup(profile_hash, path);
}
/*
- * Return the identifier for the active profile or NULL
- * if there is none.
+ * Return the active profile or NULL
*/
+struct connman_profile *__connman_profile_active_profile(void)
+{
+ return active_profile();
+}
+
const struct connman_storage_ident *__connman_profile_active_ident(void)
{
struct connman_profile *profile = active_profile();
@@ -275,31 +311,65 @@ const char *__connman_profile_active_path(void)
return profile != NULL ? profile->path : NULL;
}
-static guint changed_timeout = 0;
+/*
+ * Delete an entry in the specified profile.
+ */
+int __connman_profile_delete_entry(struct connman_profile *profile,
+ const char *group)
+{
+ GKeyFile *keyfile;
+ gboolean status;
-static void clear_timeout(void)
+ _DBG_PROFILE("profile %p group %s", profile, group);
+
+ keyfile = __connman_storage_open(&profile->ident);
+ if (keyfile == NULL) {
+ _DBG_PROFILE("cannot open key file");
+ return -EINVAL;
+ }
+
+ status = g_key_file_remove_group(keyfile, group, NULL);
+ __connman_storage_close(&profile->ident, keyfile, status);
+
+ if (status == FALSE) {
+ _DBG_PROFILE("cannot remove %s", group);
+ return -ENXIO;
+ }
+ return 0;
+}
+
+static void __clear_timeout(guint *pchanged_timeout)
{
- if (changed_timeout > 0) {
- g_source_remove(changed_timeout);
- changed_timeout = 0;
+ if (*pchanged_timeout > 0) {
+ g_source_remove(*pchanged_timeout);
+ *pchanged_timeout = 0;
}
}
+static void clear_timeout(struct connman_profile *profile)
+{
+ if (profile != NULL)
+ __clear_timeout(&profile->changed_timeout);
+ else
+ __clear_timeout(&changed_timeout);
+}
+
static void append_services(DBusMessageIter *iter, void *arg)
{
__connman_service_list(iter, arg);
}
static gboolean services_changed(gpointer user_data)
{
- struct connman_profile *profile = active_profile();
-
- changed_timeout = 0;
+ struct connman_profile *profile = user_data;
if (profile != NULL) {
+ profile->changed_timeout = 0;
+
connman_dbus_send_property_changed_array(profile->path,
CONNMAN_PROFILE_INTERFACE, "Services",
DBUS_TYPE_OBJECT_PATH, append_services, NULL);
- }
+ } else
+ changed_timeout = 0;
connman_dbus_send_property_changed_array(CONNMAN_MANAGER_PATH,
CONNMAN_MANAGER_INTERFACE, "Services",
@@ -308,22 +378,29 @@ static gboolean services_changed(gpointer user_data)
}
/*
- * Handle changes to the profile. Generate PropertyChanged signals
+ * Handle changes to a profile. Generate PropertyChanged signals
* on Manager.Services and Profile.Services for the currently active
* profile. To minimize overhead requests may be coalesced using a
* 1 second delay on the signals.
*/
-void __connman_profile_changed(gboolean delayed)
+void __connman_profile_changed(struct connman_profile *profile,
+ gboolean delayed)
{
- _DBG_PROFILE("delayed %d changed_timeout %d", delayed, changed_timeout);
+ _DBG_PROFILE("profile %p delayed %d changed_timeout %d",
+ profile, delayed, profile != NULL ?
+ profile->changed_timeout : changed_timeout);
- clear_timeout();
+ clear_timeout(profile);
if (delayed == TRUE) {
- changed_timeout = g_timeout_add_seconds(1, services_changed,
- NULL);
+ guint timeout = g_timeout_add_seconds(1,
+ services_changed, profile);
+ if (profile != NULL)
+ profile->changed_timeout = timeout;
+ else
+ changed_timeout = timeout;
} else
- services_changed(NULL);
+ services_changed(profile);
}
int __connman_profile_add_device(struct connman_device *device)
@@ -461,7 +538,7 @@ static DBusMessage *get_properties(DBusConnection *conn,
connman_dbus_dict_append_variant(&dict, "Name",
DBUS_TYPE_STRING, &profile->name);
- if (profile == default_profile)
+ if (profile == global_profile())
connman_dbus_dict_append_variant(&dict, "OfflineMode",
DBUS_TYPE_BOOLEAN, &profile->offlinemode);
@@ -650,8 +727,7 @@ static DBusMessage *delete_entry(DBusConnection *conn,
DBusMessageIter iter;
const char *identifier;
struct connman_service *service;
- GKeyFile *keyfile;
- gboolean status;
+ int err;
_DBG_PROFILE("profile %s:%s", profile->ident.user,
profile->ident.ident);
@@ -672,19 +748,9 @@ static DBusMessage *delete_entry(DBusConnection *conn,
}
/* Remove directly from profile */
- keyfile = __connman_storage_open(&profile->ident);
- if (keyfile == NULL) {
- _DBG_PROFILE("cannot open key file");
- return __connman_error_invalid_arguments(msg);
- }
-
- status = g_key_file_remove_group(keyfile, identifier, NULL);
- __connman_storage_close(&profile->ident, keyfile, status);
-
- if (status == FALSE) {
- _DBG_PROFILE("cannot remove %s", identifier);
- return __connman_error_not_found(msg);
- }
+ err = __connman_profile_delete_entry(profile, identifier);
+ if (err)
+ return __connman_error_failed(msg, -err);
return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
}
@@ -731,6 +797,8 @@ static void unregister_profile(gpointer data)
g_dbus_unregister_interface(connection, profile->path,
CONNMAN_PROFILE_INTERFACE);
+ clear_timeout(profile);
+
if (profile == default_profile)
default_profile = NULL;
@@ -950,8 +1018,7 @@ int __connman_profile_push(const char *ident, const char *name,
profiles_changed();
- /* NB: this is a noop if we are online (or trying to get online) */
- __connman_service_auto_connect_any();
+ __connman_notifier_profile_push(profile);
return 0;
}
@@ -998,15 +1065,20 @@ int __connman_profile_pop(const char *ident)
free_ident(&sid);
}
- __connman_service_invalidate_profile(&profile->ident);
+ /*
+ * Pop the stack, invalidate all objects holding references
+ * to the profile, then remove it from the in-memory table.
+ * We do the reclaim after notification in case anyone holding
+ * a reference tries to use it.
+ */
+ cur_profile--;
+
+ __connman_notifier_profile_pop(profile);
g_hash_table_remove(profile_hash, profile->path);
- cur_profile--;
profiles_changed();
- /* NB: no need to kick auto-connect; it will happen due to invalidate */
-
return 0;
}
@@ -1219,11 +1291,11 @@ void __connman_profile_cleanup(void)
while (cur_profile >= 0)
__connman_profile_pop(NULL);
+ clear_timeout(NULL); /* NB: clear global timer */
+
g_hash_table_destroy(profile_hash);
profile_hash = NULL;
- clear_timeout(); /* cancel any pending timer */
-
connman_storage_unregister(&profile_storage);
dbus_connection_unref(connection);
« no previous file with comments | « src/notifier.c ('k') | src/service.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698