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

Side by Side Diff: src/profile.c

Issue 6659006: flimflam: add support for multiple profiles (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/flimflam.git@master
Patch Set: more ers comments 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/manager.c ('k') | src/service.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * 2 *
3 * Connection Manager 3 * Connection Manager
4 * 4 *
5 * Copyright (C) 2007-2009 Intel Corporation. All rights reserved. 5 * Copyright (C) 2007-2009 Intel Corporation. All rights reserved.
6 * 6 *
7 * This program is free software; you can redistribute it and/or modify 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 8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation. 9 * published by the Free Software Foundation.
10 * 10 *
(...skipping 10 matching lines...) Expand all
21 21
22 #ifdef HAVE_CONFIG_H 22 #ifdef HAVE_CONFIG_H
23 #include <config.h> 23 #include <config.h>
24 #endif 24 #endif
25 25
26 #include <string.h> 26 #include <string.h>
27 27
28 #include <glib.h> 28 #include <glib.h>
29 #include <gdbus.h> 29 #include <gdbus.h>
30 30
31 #include <connman/assert.h>
32
31 #include "connman.h" 33 #include "connman.h"
32 34
33 #define PROFILE_DEFAULT_IDENT "default" 35 #define PROFILE_DEFAULT_IDENT "default"
36 #define PROFILE_MAX 3 /* 2 is probably sufficient */
34 37
35 #define _DBG_PROFILE(fmt, arg...) DBG(DBG_PROFILE, fmt, ## arg) 38 #define _DBG_PROFILE(fmt, arg...) DBG(DBG_PROFILE, fmt, ## arg)
36 39
37 struct connman_profile { 40 struct connman_profile {
38 » char *ident; 41 » struct connman_storage_ident ident;
39 char *path; 42 char *path;
40 char *name; 43 char *name;
41 connman_bool_t offlinemode; 44 connman_bool_t offlinemode;
42 }; 45 };
43 46
44 static GHashTable *profile_hash = NULL; 47 static GHashTable *profile_hash = NULL;
48
49 static struct connman_profile *profile_stack[PROFILE_MAX];
50 static int cur_profile = -1;
51
52 static struct connman_storage_ident default_ident = {
53 .ident = PROFILE_DEFAULT_IDENT
54 };
45 static struct connman_profile *default_profile = NULL; 55 static struct connman_profile *default_profile = NULL;
46 56
47 static DBusConnection *connection = NULL; 57 static DBusConnection *connection = NULL;
48 58
59 static int ident_equal(const struct connman_storage_ident *a,
60 const struct connman_storage_ident *b)
61 {
62 return (g_strcmp0(a->user, b->user) == 0 &&
63 g_strcmp0(a->ident, b->ident) == 0);
64 }
65
49 static void append_path(gpointer key, gpointer value, gpointer user_data) 66 static void append_path(gpointer key, gpointer value, gpointer user_data)
50 { 67 {
51 struct connman_profile *profile = value; 68 struct connman_profile *profile = value;
52 DBusMessageIter *iter = user_data; 69 DBusMessageIter *iter = user_data;
53 70
54 dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, 71 dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
55 &profile->path); 72 &profile->path);
56 } 73 }
57 74
58 void __connman_profile_list(DBusMessageIter *iter, void *arg) 75 void __connman_profile_list(DBusMessageIter *iter, void *arg)
59 { 76 {
60 _DBG_PROFILE("");
61
62 g_hash_table_foreach(profile_hash, append_path, iter); 77 g_hash_table_foreach(profile_hash, append_path, iter);
63 } 78 }
64 79
65 static void profiles_changed(void) 80 static void profiles_changed(void)
66 { 81 {
67 _DBG_PROFILE("");
68
69 connman_dbus_send_property_changed_array(CONNMAN_MANAGER_PATH, 82 connman_dbus_send_property_changed_array(CONNMAN_MANAGER_PATH,
70 CONNMAN_MANAGER_INTERFACE, "Profiles", 83 CONNMAN_MANAGER_INTERFACE, "Profiles",
71 DBUS_TYPE_OBJECT_PATH, __connman_profile_list, NULL); 84 DBUS_TYPE_OBJECT_PATH, __connman_profile_list, NULL);
72 } 85 }
73 86
74 static void name_changed(struct connman_profile *profile)
75 {
76 _DBG_PROFILE("profile %p", profile);
77
78 connman_dbus_send_property_changed_variant(profile->path,
79 CONNMAN_PROFILE_INTERFACE, "Name",
80 DBUS_TYPE_STRING, &profile->name);
81 }
82
83 static void offlinemode_changed(struct connman_profile *profile)
84 {
85 _DBG_PROFILE("profile %p", profile);
86
87 connman_dbus_send_property_changed_variant(profile->path,
88 CONNMAN_PROFILE_INTERFACE, "OfflineMode",
89 DBUS_TYPE_BOOLEAN, &profile->offlinemode);
90 }
91
92 connman_bool_t __connman_profile_get_offlinemode(void) 87 connman_bool_t __connman_profile_get_offlinemode(void)
93 { 88 {
94 » if (default_profile == NULL) 89 » return (default_profile == NULL) ? FALSE : default_profile->offlinemode;
95 » » return FALSE;
96
97 » _DBG_PROFILE("offlinemode %d", default_profile->offlinemode);
98
99 » return default_profile->offlinemode;
100 } 90 }
101 91
102 int __connman_profile_set_offlinemode(connman_bool_t offlinemode) 92 int __connman_profile_set_offlinemode(connman_bool_t offlinemode)
103 { 93 {
104 _DBG_PROFILE("offlinemode %d", offlinemode); 94 _DBG_PROFILE("offlinemode %d", offlinemode);
105 95
106 » if (default_profile == NULL) 96 » /* TODO(sleffler) disallow if no default profile? */
107 » » return -EINVAL; 97 » if (default_profile != NULL) {
108 98 » » /*
109 » if (default_profile->offlinemode == offlinemode) 99 » » * OfflineMode is only saved to the default profile;
110 » » return -EALREADY; 100 » » * this ensures it is preserved across user changes.
111 101 » » */
112 » default_profile->offlinemode = offlinemode; 102 » » if (default_profile->offlinemode == offlinemode)
113 » offlinemode_changed(default_profile); 103 » » » return -EALREADY;
114 104
115 » __connman_device_set_offlinemode(offlinemode); 105 » » default_profile->offlinemode = offlinemode;
116 106
107 » » connman_dbus_send_property_changed_variant(
108 » » default_profile->path,
109 » » CONNMAN_PROFILE_INTERFACE, "OfflineMode",
110 » » DBUS_TYPE_BOOLEAN, &offlinemode);
111 » }
112 » return __connman_device_set_offlinemode(offlinemode);
113 }
114
115 /*
116 * Return the active profile; it's on the top of the stack.
117 */
118 static inline struct connman_profile *active_profile(void)
119 {
120 » return cur_profile >= 0 ? profile_stack[cur_profile] : NULL;
121 }
122
123 /*
124 * Load/Save objects. When loading we walk the stack of profiles
125 * until we find a successful load. Saving always happens to the
126 * top-most/active profile.
127 */
128
129 static inline int load_continue(int err)
130 {
131 » /* NB: ENXIO for no file, ESRCH for no group/key */
132 » return (err == -ENXIO || err == -ESRCH);
133 }
134
135 int __connman_profile_load_service(struct connman_service *service)
136 {
137 » int i, err;
138
139 » _DBG_PROFILE("service %p", service);
140
141 » err = 0;
142 » for (i = cur_profile; i >= 0; i--) {
143 » » const struct connman_profile *profile = profile_stack[i];
144
145 » » err = __connman_storage_load_service(service, &profile->ident);
146 » » if (!load_continue(err))
147 » » » break;
148 » }
149 » return err;
150 }
151
152 int __connman_profile_save_service(struct connman_service *service)
153 {
154 » struct connman_profile *profile = active_profile();
155
156 » _DBG_PROFILE("service %p profile %p", service, profile);
157
158 » return (profile == NULL) ? 0 :
159 » __connman_storage_save_service(service, &profile->ident);
160 }
161
162 int __connman_profile_load_device(struct connman_device *device)
163 {
164 » int i, err;
165
166 » _DBG_PROFILE("device %p", device);
167
168 » err = 0;
169 » for (i = cur_profile; i >= 0; i--) {
170 » » const struct connman_profile *profile = profile_stack[i];
171
172 » » err = __connman_storage_load_device(device, &profile->ident);
173 » » if (!load_continue(err))
174 » » » break;
175 » }
176 » return err;
177 }
178
179 int __connman_profile_save_device(struct connman_device *device)
180 {
181 » struct connman_profile *profile = active_profile();
182
183 » _DBG_PROFILE("device %p profile %p", device, profile);
184
185 » return (profile == NULL) ? 0:
186 » __connman_storage_save_device(device, &profile->ident);
187 }
188
189 int __connman_profile_load_ipconfig(struct connman_ipconfig *ipconfig)
190 {
191 » int i, err;
192
193 » _DBG_PROFILE("ipconfig %p", ipconfig);
194
195 » err = 0;
196 » for (i = cur_profile; i >= 0; i--) {
197 » » const struct connman_profile *profile = profile_stack[i];
198
199 » » err = __connman_storage_load_ipconfig(ipconfig,
200 » » &profile->ident);
201 » » if (!load_continue(err))
202 » » » break;
203 » }
204 » return err;
205 }
206
207 int __connman_profile_save_ipconfig(const struct connman_ipconfig *ipconfig)
208 {
209 » struct connman_profile *profile = active_profile();
210
211 » _DBG_PROFILE("ipconfig %p profile %p", ipconfig, profile);
212
213 » return (profile == NULL) ? 0 :
214 » __connman_storage_save_ipconfig(ipconfig, &profile->ident);
215 }
216
217 int __connman_profile_append_hidden_ssids(GSList **hidden_ssids,
218 void (*append_hidden_ssids)(GKeyFile *keyfile, GSList **hidden_ssids))
219 {
220 » int i;
221
222 » _DBG_PROFILE("");
223
224 » for (i = cur_profile; i >= 0; i--) {
225 » » const struct connman_profile *profile = profile_stack[i];
226 » » GKeyFile *keyfile;
227
228 » » keyfile = __connman_storage_open(&profile->ident);
229 » » if (keyfile != NULL) {
230 » » » append_hidden_ssids(keyfile, hidden_ssids);
231 » » » __connman_storage_close(&profile->ident, keyfile,
232 » » » FALSE);
233 » » }
234 » }
117 return 0; 235 return 0;
118 } 236 }
119 237
238 /*
239 * Save the default profile if registered.
240 */
120 int __connman_profile_save_default(void) 241 int __connman_profile_save_default(void)
121 { 242 {
122 _DBG_PROFILE("");
123
124 if (default_profile != NULL) 243 if (default_profile != NULL)
125 __connman_storage_save_profile(default_profile); 244 __connman_storage_save_profile(default_profile);
126
127 return 0; 245 return 0;
128 } 246 }
129 247
130 const char *__connman_profile_active_ident(void) 248 /*
131 { 249 * Save the active profile (if any).
132 » _DBG_PROFILE(""); 250 */
133 251 int __connman_profile_save_active(void)
134 » return PROFILE_DEFAULT_IDENT; 252 {
135 } 253 » struct connman_profile *profile = active_profile();
136 254 » return (profile == NULL) ? -EINVAL :
255 » __connman_storage_save_profile(profile);
256 }
257
258 /*
259 * Return the identifier for the active profile or NULL
260 * if there is none.
261 */
262 const struct connman_storage_ident *__connman_profile_active_ident(void)
263 {
264 » struct connman_profile *profile = active_profile();
265 » return profile != NULL ? &profile->ident : NULL;
266 }
267
268 /*
269 * Return the object path for the active profile or NULL
270 * if there is none.
271 */
137 const char *__connman_profile_active_path(void) 272 const char *__connman_profile_active_path(void)
138 { 273 {
139 » _DBG_PROFILE(""); 274 » struct connman_profile *profile = active_profile();
140 275 » return profile != NULL ? profile->path : NULL;
141 » if (default_profile == NULL)
142 » » return NULL;
143
144 » return default_profile->path;
145 } 276 }
146 277
147 static guint changed_timeout = 0; 278 static guint changed_timeout = 0;
148 279
280 static void clear_timeout(void)
281 {
282 if (changed_timeout > 0) {
283 g_source_remove(changed_timeout);
284 changed_timeout = 0;
285 }
286 }
287
149 static void append_services(DBusMessageIter *iter, void *arg) 288 static void append_services(DBusMessageIter *iter, void *arg)
150 { 289 {
151 » const struct connman_profile *profile = arg; 290 » __connman_service_list(iter, arg);
152 » if (g_strcmp0(profile->ident, PROFILE_DEFAULT_IDENT) == 0)
153 » » __connman_service_list(iter, arg);
154 } 291 }
155 static gboolean services_changed(gpointer user_data) 292 static gboolean services_changed(gpointer user_data)
156 { 293 {
157 » struct connman_profile *profile = default_profile; 294 » struct connman_profile *profile = active_profile();
158 295
159 changed_timeout = 0; 296 changed_timeout = 0;
160 297
161 if (profile != NULL) { 298 if (profile != NULL) {
162 connman_dbus_send_property_changed_array(profile->path, 299 connman_dbus_send_property_changed_array(profile->path,
163 CONNMAN_PROFILE_INTERFACE, "Services", 300 CONNMAN_PROFILE_INTERFACE, "Services",
164 » » DBUS_TYPE_OBJECT_PATH, append_services, profile); 301 » » DBUS_TYPE_OBJECT_PATH, append_services, NULL);
165 302 » }
166 » » if (g_strcmp0(profile->ident, PROFILE_DEFAULT_IDENT) == 0) 303
167 » » » connman_dbus_send_property_changed_array( 304 » connman_dbus_send_property_changed_array(CONNMAN_MANAGER_PATH,
168 » » » CONNMAN_MANAGER_PATH, CONNMAN_MANAGER_INTERFACE, 305 » CONNMAN_MANAGER_INTERFACE, "Services",
169 » » » "Services", 306 » DBUS_TYPE_OBJECT_PATH, append_services, NULL);
170 » » » DBUS_TYPE_OBJECT_PATH, append_services, profile);
171 » }
172 return FALSE; 307 return FALSE;
173 } 308 }
174 309
310 /*
311 * Handle changes to the profile. Generate PropertyChanged signals
312 * on Manager.Services and Profile.Services for the currently active
313 * profile. To minimize overhead requests may be coalesced using a
314 * 1 second delay on the signals.
315 */
175 void __connman_profile_changed(gboolean delayed) 316 void __connman_profile_changed(gboolean delayed)
176 { 317 {
177 » _DBG_PROFILE(""); 318 » _DBG_PROFILE("delayed %d changed_timeout %d", delayed, changed_timeout);
178 319
179 » if (changed_timeout > 0) { 320 » clear_timeout();
180 » » g_source_remove(changed_timeout); 321
181 » » changed_timeout = 0; 322 » if (delayed == TRUE) {
182 » } 323 » » changed_timeout = g_timeout_add_seconds(1, services_changed,
183 324 » » NULL);
184 » if (delayed == FALSE) { 325 » } else
185 services_changed(NULL); 326 services_changed(NULL);
186 return;
187 }
188
189 changed_timeout = g_timeout_add_seconds(1, services_changed, NULL);
190 } 327 }
191 328
192 int __connman_profile_add_device(struct connman_device *device) 329 int __connman_profile_add_device(struct connman_device *device)
193 { 330 {
194 struct connman_service *service; 331 struct connman_service *service;
195 332
196 _DBG_PROFILE("device %p", device); 333 _DBG_PROFILE("device %p", device);
197 334
198 service = __connman_service_create_from_device(device); 335 service = __connman_service_create_from_device(device);
199 if (service == NULL) 336 if (service == NULL)
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
267 404
268 static void __profile_entry_list(DBusMessageIter *iter, void *arg) 405 static void __profile_entry_list(DBusMessageIter *iter, void *arg)
269 { 406 {
270 struct connman_profile *profile = arg; 407 struct connman_profile *profile = arg;
271 GKeyFile *keyfile; 408 GKeyFile *keyfile;
272 gchar **groups; 409 gchar **groups;
273 int i; 410 int i;
274 411
275 _DBG_PROFILE("profile %p", profile); 412 _DBG_PROFILE("profile %p", profile);
276 413
277 » keyfile = __connman_storage_open(profile->ident); 414 » keyfile = __connman_storage_open(&profile->ident);
278 if (keyfile == NULL) 415 if (keyfile == NULL)
279 return; 416 return;
280 417
281 groups = g_key_file_get_groups(keyfile, NULL); 418 groups = g_key_file_get_groups(keyfile, NULL);
282 for (i = 0; groups[i] != NULL; i++) { 419 for (i = 0; groups[i] != NULL; i++) {
283 const char *gname = groups[i]; 420 const char *gname = groups[i];
284 switch (get_service_type(gname)) { 421 switch (get_service_type(gname)) {
285 case CONNMAN_SERVICE_TYPE_UNKNOWN: 422 case CONNMAN_SERVICE_TYPE_UNKNOWN:
286 case CONNMAN_SERVICE_TYPE_ETHERNET: 423 case CONNMAN_SERVICE_TYPE_ETHERNET:
287 break; 424 break;
288 case CONNMAN_SERVICE_TYPE_BLUETOOTH: 425 case CONNMAN_SERVICE_TYPE_BLUETOOTH:
289 case CONNMAN_SERVICE_TYPE_WIMAX: 426 case CONNMAN_SERVICE_TYPE_WIMAX:
290 /* NB: don't care about these right now */ 427 /* NB: don't care about these right now */
291 break; 428 break;
292 case CONNMAN_SERVICE_TYPE_CELLULAR: 429 case CONNMAN_SERVICE_TYPE_CELLULAR:
293 case CONNMAN_SERVICE_TYPE_WIFI: 430 case CONNMAN_SERVICE_TYPE_WIFI:
294 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, 431 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
295 &gname); 432 &gname);
296 break; 433 break;
297 } 434 }
298 } 435 }
299 g_strfreev(groups); 436 g_strfreev(groups);
300 » __connman_storage_close(profile->ident, keyfile, FALSE); 437 » __connman_storage_close(&profile->ident, keyfile, FALSE);
301 } 438 }
302 439
303 static DBusMessage *get_properties(DBusConnection *conn, 440 static DBusMessage *get_properties(DBusConnection *conn,
304 DBusMessage *msg, void *data) 441 DBusMessage *msg, void *data)
305 { 442 {
306 struct connman_profile *profile = data; 443 struct connman_profile *profile = data;
307 DBusMessage *reply; 444 DBusMessage *reply;
308 DBusMessageIter array, dict; 445 DBusMessageIter array, dict;
309 446
310 _DBG_PROFILE("conn %p", conn); 447 _DBG_PROFILE("conn %p", conn);
311 448
312 reply = dbus_message_new_method_return(msg); 449 reply = dbus_message_new_method_return(msg);
313 if (reply == NULL) 450 if (reply == NULL)
314 return NULL; 451 return NULL;
315 452
316 dbus_message_iter_init_append(reply, &array); 453 dbus_message_iter_init_append(reply, &array);
317 454
318 dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY, 455 dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
319 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING 456 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
320 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING 457 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
321 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); 458 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
322 459
323 if (profile->name != NULL) 460 if (profile->name != NULL)
324 connman_dbus_dict_append_variant(&dict, "Name", 461 connman_dbus_dict_append_variant(&dict, "Name",
325 DBUS_TYPE_STRING, &profile->name); 462 DBUS_TYPE_STRING, &profile->name);
326 463
327 » connman_dbus_dict_append_variant(&dict, "OfflineMode", 464 » if (profile == default_profile)
328 » DBUS_TYPE_BOOLEAN, &profile->offlinemode); 465 » » connman_dbus_dict_append_variant(&dict, "OfflineMode",
466 » » DBUS_TYPE_BOOLEAN, &profile->offlinemode);
329 467
330 » connman_dbus_dict_append_variant_array(&dict, "Services", 468 » if (profile == active_profile())
331 » DBUS_TYPE_OBJECT_PATH, __connman_service_list, NULL); 469 » » connman_dbus_dict_append_variant_array(&dict, "Services",
470 » » DBUS_TYPE_OBJECT_PATH, __connman_service_list, NULL);
332 471
333 connman_dbus_dict_append_variant_array(&dict, "Entries", 472 connman_dbus_dict_append_variant_array(&dict, "Entries",
334 DBUS_TYPE_STRING, __profile_entry_list, profile); 473 DBUS_TYPE_STRING, __profile_entry_list, profile);
335 474
336 dbus_message_iter_close_container(&array, &dict); 475 dbus_message_iter_close_container(&array, &dict);
337 476
338 return reply; 477 return reply;
339 } 478 }
340 479
341 static DBusMessage *set_property(DBusConnection *conn, 480 static DBusMessage *set_property(DBusConnection *conn,
(...skipping 23 matching lines...) Expand all
365 const char *name; 504 const char *name;
366 505
367 if (type != DBUS_TYPE_STRING) 506 if (type != DBUS_TYPE_STRING)
368 return __connman_error_invalid_arguments(msg); 507 return __connman_error_invalid_arguments(msg);
369 508
370 dbus_message_iter_get_basic(&value, &name); 509 dbus_message_iter_get_basic(&value, &name);
371 510
372 g_free(profile->name); 511 g_free(profile->name);
373 profile->name = g_strdup(name); 512 profile->name = g_strdup(name);
374 513
375 » » if (profile->name != NULL) 514 » » if (profile->name != NULL) {
376 » » » name_changed(profile); 515 » » » connman_dbus_send_property_changed_variant(
377 516 » » » profile->path, CONNMAN_PROFILE_INTERFACE, "Name",
378 » » __connman_storage_save_profile(profile); 517 » » » DBUS_TYPE_STRING, &profile->name);
379 » } else if (g_str_equal(name, "OfflineMode") == TRUE) { 518 » » }
380 » » connman_bool_t offlinemode;
381
382 » » if (type != DBUS_TYPE_BOOLEAN)
383 » » » return __connman_error_invalid_arguments(msg);
384
385 » » dbus_message_iter_get_basic(&value, &offlinemode);
386
387 » » if (profile->offlinemode == offlinemode)
388 » » » return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
389
390 » » profile->offlinemode = offlinemode;
391 » » offlinemode_changed(profile);
392 519
393 __connman_storage_save_profile(profile); 520 __connman_storage_save_profile(profile);
394 } else 521 } else
395 return __connman_error_invalid_property(msg); 522 return __connman_error_invalid_property(msg);
396 523
397 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); 524 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
398 } 525 }
399 526
400 static DBusMessage *get_entry(DBusConnection *conn, 527 static DBusMessage *get_entry(DBusConnection *conn,
401 DBusMessage *msg, void *data) 528 DBusMessage *msg, void *data)
402 { 529 {
403 #define ADD_STR(name, val) do { \ 530 #define ADD_STR(name, val) do { \
404 connman_dbus_dict_append_variant(&dict, name, DBUS_TYPE_STRING, val); \ 531 connman_dbus_dict_append_variant(&dict, name, DBUS_TYPE_STRING, val); \
405 } while (0) 532 } while (0)
406 #define VAL_STR(name) do { \ 533 #define VAL_STR(name) do { \
407 val = g_key_file_get_string(keyfile, ident, name, NULL); \ 534 val = g_key_file_get_string(keyfile, ident, name, NULL); \
408 if (val != NULL) \ 535 if (val != NULL) \
409 ADD_STR(name, &val); \ 536 ADD_STR(name, &val); \
410 } while (0) 537 } while (0)
411 struct connman_profile *profile = data; 538 struct connman_profile *profile = data;
412 GKeyFile *keyfile; 539 GKeyFile *keyfile;
413 const char *ident, *val; 540 const char *ident, *val;
414 gchar **tokens; 541 gchar **tokens;
415 DBusMessageIter iter, array, dict; 542 DBusMessageIter iter, array, dict;
416 DBusMessage *reply; 543 DBusMessage *reply;
417 connman_bool_t autoconnect, hidden_ssid; 544 connman_bool_t autoconnect, hidden_ssid;
545 int len;
418 546
419 _DBG_PROFILE("profile %p", profile); 547 _DBG_PROFILE("profile %p", profile);
420 548
421 if (dbus_message_iter_init(msg, &iter) == FALSE) 549 if (dbus_message_iter_init(msg, &iter) == FALSE)
422 return __connman_error_invalid_arguments(msg); 550 return __connman_error_invalid_arguments(msg);
423 551
424 dbus_message_iter_get_basic(&iter, &ident); 552 dbus_message_iter_get_basic(&iter, &ident);
425 553
426 » keyfile = __connman_storage_open(profile->ident); 554 » keyfile = __connman_storage_open(&profile->ident);
427 if (keyfile == NULL) { 555 if (keyfile == NULL) {
428 » » _DBG_PROFILE("cannot open keyfile %s", profile->ident); 556 » » _DBG_PROFILE("cannot open keyfile %s:%s",
557 » » profile->ident.user, profile->ident.ident);
429 return __connman_error_not_found(msg); /* XXX */ 558 return __connman_error_not_found(msg); /* XXX */
430 } 559 }
431 560
432 if (g_key_file_has_group(keyfile, ident) == FALSE) { 561 if (g_key_file_has_group(keyfile, ident) == FALSE) {
433 _DBG_PROFILE("ident %s not found", ident); 562 _DBG_PROFILE("ident %s not found", ident);
434 » » __connman_storage_close(profile->ident, keyfile, FALSE); 563 » » __connman_storage_close(&profile->ident, keyfile, FALSE);
435 return __connman_error_not_found(msg); 564 return __connman_error_not_found(msg);
436 } 565 }
437 566
438 /* 567 /*
439 * Split group name into components; e.g. 568 * Split group name into components; e.g.
440 * <type>_<device>_<ssid>_<mode>_<security> for wifi 569 * <type>_<device>_<ssid>_<mode>_<security> for wifi
441 */ 570 */
442 tokens = g_strsplit(ident, "_", 0); 571 tokens = g_strsplit(ident, "_", 0);
443 » /* NB: tokens[0] is NULL if ident is "" */ 572 » len = g_strv_length(tokens);
444 » if (tokens == NULL || tokens[0] == NULL) { 573 » if (len < 2) {
445 » » _DBG_PROFILE("ident %s malformed", ident); 574 » » _DBG_PROFILE("ident %s malformed, len %d", ident, len);
446 » » __connman_storage_close(profile->ident, keyfile, FALSE); 575 » » g_strfreev(tokens);
576 » » __connman_storage_close(&profile->ident, keyfile, FALSE);
447 return __connman_error_invalid_arguments(msg); 577 return __connman_error_invalid_arguments(msg);
448 } 578 }
449 579
450 reply = dbus_message_new_method_return(msg); 580 reply = dbus_message_new_method_return(msg);
451 if (reply == NULL) { 581 if (reply == NULL) {
452 _DBG_PROFILE("cannot allocate reply"); 582 _DBG_PROFILE("cannot allocate reply");
453 g_strfreev(tokens); 583 g_strfreev(tokens);
454 » » __connman_storage_close(profile->ident, keyfile, FALSE); 584 » » __connman_storage_close(&profile->ident, keyfile, FALSE);
455 return NULL; 585 return NULL;
456 } 586 }
457 587
458 dbus_message_iter_init_append(reply, &array); 588 dbus_message_iter_init_append(reply, &array);
459 589
460 dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY, 590 dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
461 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING 591 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
462 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING 592 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
463 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); 593 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
464 594
465 val = tokens[0]; 595 val = tokens[0];
466 connman_dbus_dict_append_variant(&dict, "Type", DBUS_TYPE_STRING, &val); 596 connman_dbus_dict_append_variant(&dict, "Type", DBUS_TYPE_STRING, &val);
467 597
468 switch (__connman_service_string2type(val)) { 598 switch (__connman_service_string2type(val)) {
469 case CONNMAN_SERVICE_TYPE_WIFI: 599 case CONNMAN_SERVICE_TYPE_WIFI:
470 » » if (g_strv_length(tokens) != 5) { 600 » » if (len != 5 && len != 6) {
471 » » » /* TODO(sleffler) accept > 5? */ 601 » » » _DBG_PROFILE("bad token cnt %d for ident %s",
472 » » » _DBG_PROFILE("bad token cnt %d", g_strv_length(tokens)); 602 » » » len, ident);
473 break; 603 break;
474 } 604 }
475 val = tokens[3]; 605 val = tokens[3];
476 ADD_STR("Mode", &val); 606 ADD_STR("Mode", &val);
477 val = tokens[4]; 607 val = tokens[4];
608 /* NB: g_strsplit breaks 802_1x into 802+1x; restore */
609 if (g_strcmp0(val, "802") == 0)
610 val = "802_1x";
478 ADD_STR("Security", &val); 611 ADD_STR("Security", &val);
479 break; 612 break;
480 case CONNMAN_SERVICE_TYPE_CELLULAR: 613 case CONNMAN_SERVICE_TYPE_CELLULAR:
481 /* TODO(sleffler) extract cellular attributes */ 614 /* TODO(sleffler) extract cellular attributes */
482 break; 615 break;
483 default: 616 default:
484 break; 617 break;
485 } 618 }
486 619
487 /* NB: always set AutoConnect in reply */ 620 /* NB: always set AutoConnect in reply */
488 val = g_key_file_get_string(keyfile, ident, "AutoConnect", NULL); 621 val = g_key_file_get_string(keyfile, ident, "AutoConnect", NULL);
489 autoconnect = (g_strcmp0(val, "true") == 0 ? TRUE : FALSE); 622 autoconnect = (g_strcmp0(val, "true") == 0 ? TRUE : FALSE);
490 connman_dbus_dict_append_variant(&dict, "AutoConnect", 623 connman_dbus_dict_append_variant(&dict, "AutoConnect",
491 DBUS_TYPE_BOOLEAN, &autoconnect); 624 DBUS_TYPE_BOOLEAN, &autoconnect);
492 625
493 VAL_STR("Name"); 626 VAL_STR("Name");
494 VAL_STR("Passphrase"); 627 VAL_STR("Passphrase");
495 VAL_STR("Failure"); 628 VAL_STR("Failure");
496 VAL_STR("Modified"); 629 VAL_STR("Modified");
497 630
498 val = g_key_file_get_string(keyfile, ident, "WiFi.HiddenSSID", NULL); 631 val = g_key_file_get_string(keyfile, ident, "WiFi.HiddenSSID", NULL);
499 hidden_ssid = (g_strcmp0(val, "true") == 0 ? TRUE : FALSE); 632 hidden_ssid = (g_strcmp0(val, "true") == 0 ? TRUE : FALSE);
500 connman_dbus_dict_append_variant(&dict, "WiFi.HiddenSSID", 633 connman_dbus_dict_append_variant(&dict, "WiFi.HiddenSSID",
501 DBUS_TYPE_BOOLEAN, &hidden_ssid); 634 DBUS_TYPE_BOOLEAN, &hidden_ssid);
502 635
503 dbus_message_iter_close_container(&array, &dict); 636 dbus_message_iter_close_container(&array, &dict);
504 637
505 g_strfreev(tokens); 638 g_strfreev(tokens);
506 » __connman_storage_close(profile->ident, keyfile, FALSE); 639 » __connman_storage_close(&profile->ident, keyfile, FALSE);
507 640
508 return reply; 641 return reply;
509 #undef VAL_STR 642 #undef VAL_STR
510 #undef ADD_STR 643 #undef ADD_STR
511 } 644 }
512 645
513 static DBusMessage *delete_entry(DBusConnection *conn, 646 static DBusMessage *delete_entry(DBusConnection *conn,
514 DBusMessage *msg, void *data) 647 DBusMessage *msg, void *data)
515 { 648 {
516 struct connman_profile *profile = data; 649 struct connman_profile *profile = data;
517 DBusMessageIter iter; 650 DBusMessageIter iter;
518 const char *identifier; 651 const char *identifier;
519 struct connman_service *service; 652 struct connman_service *service;
520 GKeyFile *keyfile; 653 GKeyFile *keyfile;
521 gboolean status; 654 gboolean status;
522 655
523 » _DBG_PROFILE("profile %s", profile->ident); 656 » _DBG_PROFILE("profile %s:%s", profile->ident.user,
657 » profile->ident.ident);
524 658
525 if (dbus_message_iter_init(msg, &iter) == FALSE) 659 if (dbus_message_iter_init(msg, &iter) == FALSE)
526 return __connman_error_invalid_arguments(msg); 660 return __connman_error_invalid_arguments(msg);
527 661
528 dbus_message_iter_get_basic(&iter, &identifier); 662 dbus_message_iter_get_basic(&iter, &identifier);
529 663
530 if (__connman_security_check_privilege(msg, 664 if (__connman_security_check_privilege(msg,
531 CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0) 665 CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
532 return __connman_error_permission_denied(msg); 666 return __connman_error_permission_denied(msg);
533 667
534 service = __connman_service_lookup(identifier); 668 service = __connman_service_lookup(identifier);
535 if (service != NULL) { 669 if (service != NULL) {
536 /* NB: this does not remove the service */ 670 /* NB: this does not remove the service */
537 __connman_service_reset(service); 671 __connman_service_reset(service);
538 } 672 }
539 673
540 /* Remove directly from profile */ 674 /* Remove directly from profile */
541 » keyfile = __connman_storage_open(profile->ident); 675 » keyfile = __connman_storage_open(&profile->ident);
542 if (keyfile == NULL) { 676 if (keyfile == NULL) {
543 _DBG_PROFILE("cannot open key file"); 677 _DBG_PROFILE("cannot open key file");
544 return __connman_error_invalid_arguments(msg); 678 return __connman_error_invalid_arguments(msg);
545 } 679 }
546 680
547 status = g_key_file_remove_group(keyfile, identifier, NULL); 681 status = g_key_file_remove_group(keyfile, identifier, NULL);
548 » __connman_storage_close(profile->ident, keyfile, status); 682 » __connman_storage_close(&profile->ident, keyfile, status);
549 683
550 if (status == FALSE) { 684 if (status == FALSE) {
551 _DBG_PROFILE("cannot remove %s", identifier); 685 _DBG_PROFILE("cannot remove %s", identifier);
552 return __connman_error_not_found(msg); 686 return __connman_error_not_found(msg);
553 } 687 }
554 688
555 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); 689 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
556 } 690 }
557 691
558 static GDBusMethodTable profile_methods[] = { 692 static GDBusMethodTable profile_methods[] = {
559 { "GetProperties", "", "a{sv}", get_properties }, 693 { "GetProperties", "", "a{sv}", get_properties },
560 { "SetProperty", "sv", "", set_property }, 694 { "SetProperty", "sv", "", set_property },
561 { "GetEntry", "s", "a{sv}", get_entry }, 695 { "GetEntry", "s", "a{sv}", get_entry },
562 { "DeleteEntry", "s", "", delete_entry }, 696 { "DeleteEntry", "s", "", delete_entry },
563 { }, 697 { },
564 }; 698 };
565 699
566 static GDBusSignalTable profile_signals[] = { 700 static GDBusSignalTable profile_signals[] = {
567 { "PropertyChanged", "sv" }, 701 { "PropertyChanged", "sv" },
568 { }, 702 { },
569 }; 703 };
570 704
705 static void free_ident(struct connman_storage_ident *ident)
706 {
707 /* NB: blech, don't reclaim, it's statically allocated */
708 if (!ident_equal(ident, &default_ident)) {
709 g_free(ident->user);
710 g_free(ident->ident);
711 }
712 }
713
571 static void free_profile(struct connman_profile *profile) 714 static void free_profile(struct connman_profile *profile)
572 { 715 {
716 free_ident(&profile->ident);
717 g_free(profile->path);
573 g_free(profile->name); 718 g_free(profile->name);
574 g_free(profile->path);
575 g_free(profile->ident);
576 g_free(profile); 719 g_free(profile);
577 } 720 }
578 721
579 static void unregister_profile(gpointer data) 722 static void unregister_profile(gpointer data)
580 { 723 {
581 struct connman_profile *profile = data; 724 struct connman_profile *profile = data;
582 725
583 _DBG_PROFILE("profile %p", profile); 726 _DBG_PROFILE("profile %p", profile);
584 727
585 » connman_info("Removing profile %s", profile->ident); 728 » connman_info("Remove profile %s:%s", profile->ident.user,
729 » profile->ident.ident);
586 730
587 g_dbus_unregister_interface(connection, profile->path, 731 g_dbus_unregister_interface(connection, profile->path,
588 CONNMAN_PROFILE_INTERFACE); 732 CONNMAN_PROFILE_INTERFACE);
589 733
590 » if (g_strcmp0(profile->ident, PROFILE_DEFAULT_IDENT) == 0) 734 » if (profile == default_profile)
591 default_profile = NULL; 735 default_profile = NULL;
592 736
593 free_profile(profile); 737 free_profile(profile);
594 } 738 }
595 739
596 static int create_profile(const char *ident, const char *name, 740 static char *getpath(const struct connman_storage_ident *ident)
597 » » » » » » » const char **path) 741 {
742 » if (ident->user != NULL) {
743 » » /* NB: check for two tokens done in validate_ident */
744 » » return g_strdup_printf("/profile/%s/%s",
745 » » ident->user, ident->ident);
746 » } else
747 » » return g_strdup_printf("/profile/%s", ident->ident);
748 }
749
750 /*
751 * Create an in-memory profile using the specified identifier
752 * and name. The object path and a reference to the profile
753 * data structure are returned on success.
754 */
755 static int create_profile(struct connman_storage_ident *ident,
756 const char *name, const char **path, struct connman_profile **pprofile)
598 { 757 {
599 struct connman_profile *profile; 758 struct connman_profile *profile;
600 759
601 » _DBG_PROFILE("ident %s name %s", ident, name); 760 » _DBG_PROFILE("ident %s:%s name %s", ident->user, ident->ident, name);
602 761
603 profile = g_try_new0(struct connman_profile, 1); 762 profile = g_try_new0(struct connman_profile, 1);
604 » if (profile == NULL) 763 » if (profile == NULL) {
764 » » free_ident(ident);
605 return -ENOMEM; 765 return -ENOMEM;
766 }
606 767
607 » profile->ident = g_strdup(ident); 768 » profile->ident = *ident;
608 » profile->path = g_strdup_printf("/profile/%s", ident); 769 » profile->path = getpath(ident);
609 770 » /* TODO(sleffler) check ident.user */
610 » if (profile->ident == NULL || profile->path == NULL) { 771 » if (profile->ident.ident == NULL || profile->path == NULL) {
611 free_profile(profile); 772 free_profile(profile);
612 return -ENOMEM; 773 return -ENOMEM;
613 } 774 }
614 775
615 if (g_hash_table_lookup(profile_hash, profile->path) != NULL) { 776 if (g_hash_table_lookup(profile_hash, profile->path) != NULL) {
616 free_profile(profile); 777 free_profile(profile);
617 return -EEXIST; 778 return -EEXIST;
618 } 779 }
619 780
620 profile->name = g_strdup(name); 781 profile->name = g_strdup(name);
621 782
622 __connman_storage_load_profile(profile); 783 __connman_storage_load_profile(profile);
623 784
624 g_hash_table_insert(profile_hash, g_strdup(profile->path), profile); 785 g_hash_table_insert(profile_hash, g_strdup(profile->path), profile);
625 786
626 » connman_info("Adding profile %s", ident); 787 » connman_info("Add profile %s:%s", ident->user, ident->ident);
627 788
628 » if (g_strcmp0(ident, PROFILE_DEFAULT_IDENT) == 0) 789 » if (ident_equal(ident, &default_ident))
629 default_profile = profile; 790 default_profile = profile;
630 791
631 g_dbus_register_interface(connection, profile->path, 792 g_dbus_register_interface(connection, profile->path,
632 CONNMAN_PROFILE_INTERFACE, 793 CONNMAN_PROFILE_INTERFACE,
633 profile_methods, profile_signals, 794 profile_methods, profile_signals,
634 NULL, profile, NULL); 795 NULL, profile, NULL);
635 796
636 if (path != NULL) 797 if (path != NULL)
637 *path = profile->path; 798 *path = profile->path;
638 799
639 _DBG_PROFILE("profile %p path %s", profile, profile->path); 800 _DBG_PROFILE("profile %p path %s", profile, profile->path);
640 801
802 *pprofile = profile;
641 return 0; 803 return 0;
642 } 804 }
643 805
644 static gboolean validate_ident(const char *ident) 806 /*
807 * Check a profile identifier token. This must be non-null and
808 * made up of alpha-numeric chars suitable for use in a D-bus
809 * object path.
810 */
811 static gboolean validate_token(const char *ident)
645 { 812 {
646 unsigned int i; 813 unsigned int i;
647 unsigned int len = strlen(ident); 814 unsigned int len = strlen(ident);
648 815
649 if (len < 1) 816 if (len < 1)
650 return FALSE; 817 return FALSE;
651 818
652 for (i = 0; i < len; i++) { 819 for (i = 0; i < len; i++) {
653 if (ident[i] >= '0' && ident[i] <= '9') 820 if (ident[i] >= '0' && ident[i] <= '9')
654 continue; 821 continue;
655 if (ident[i] >= 'a' && ident[i] <= 'z') 822 if (ident[i] >= 'a' && ident[i] <= 'z')
656 continue; 823 continue;
657 if (ident[i] >= 'A' && ident[i] <= 'Z') 824 if (ident[i] >= 'A' && ident[i] <= 'Z')
658 continue; 825 continue;
659 return FALSE; 826 return FALSE;
660 } 827 }
661 828
662 return TRUE; 829 return TRUE;
663 } 830 }
664 831
832 /*
833 * Validate the profile identifier. It must be suitable
834 * for use in a D-Bus object path and, optionally, be of
835 * the form ~user/ident to signify a per-user profile.
836 */
837 static gboolean parse_ident(const char *str,
838 struct connman_storage_ident *ident)
839 {
840 gboolean is_valid;
841
842 if (str[0] == '~') {
843 /* syntax is ~user/name for profile in cryptohome */
844 gchar **tokens = g_strsplit_set(str, "~/", 4);
845 if (g_strv_length(tokens) == 3) {
846 is_valid = (validate_token(tokens[1]) == TRUE &&
847 validate_token(tokens[2]) == TRUE);
848 if (is_valid) {
849 ident->user = g_strdup(tokens[1]);
850 ident->ident = g_strdup(tokens[2]);
851 }
852 } else
853 is_valid = FALSE;
854 g_strfreev(tokens);
855 } else {
856 is_valid = validate_token(str);
857 if (is_valid) {
858 ident->user = NULL;
859 ident->ident = g_strdup(str);
860 }
861 }
862 return is_valid;
863 }
864
865 /*
866 * Lookup a profile on the stack by object path.
867 */
868 static struct connman_profile *lookup_stack_by_path(const char *path)
869 {
870 int i;
871
872 for (i = cur_profile; i >= 0; i--)
873 if (g_strcmp0(profile_stack[i]->path, path) == 0)
874 return profile_stack[i];
875 return NULL;
876 }
877
878 /*
879 * Push a profile on the stack and make it the ``active profile''.
880 * The profile may be currently registered in memory or previously
881 * created by CreateProfile. The profile may not already be on
882 * the stack.
883 */
884 int __connman_profile_push(const char *ident, const char *name,
885 const char **path)
886 {
887 struct connman_profile *profile;
888 struct connman_storage_ident sid;
889 char *tmp_path;
890 int err;
891
892 _DBG_PROFILE("ident %s name %s", ident, name);
893
894 if (parse_ident(ident, &sid) == FALSE) {
895 connman_error("%s: invalid profile name %s", __func__, ident);
896 return -EINVAL;
897 }
898
899 if (cur_profile+1 >= PROFILE_MAX) {
900 connman_error("%s: too many profiles (max %d)", __func__,
901 PROFILE_MAX);
902 free_ident(&sid);
903 return -EMFILE;
904 }
905
906 /*
907 * Check for in-memory profile by way of a CreateProfile request.
908 */
909 tmp_path = getpath(&sid);
910 if (tmp_path == NULL) {
911 connman_error("%s: no memory for %s", __func__, ident);
912 free_ident(&sid);
913 return -ENOMEM;
914 }
915
916 profile = g_hash_table_lookup(profile_hash, tmp_path);
917 g_free(tmp_path);
918 if (profile == NULL) {
919 /*
920 * Not in memory; accept an existing file.
921 */
922 if (__connman_storage_exists(&sid) == FALSE) {
923 connman_error("%s: profile %s does not exist",
924 __func__, ident);
925 free_ident(&sid);
926 return -ENOENT;
927 }
928
929 err = create_profile(&sid, name, path, &profile);
930 if (err < 0) {
931 connman_error("%s: cannot open, error %d",
932 __func__, err);
933 /* NB: create_profile reclaims sid */
934 return err;
935 }
936 } else {
937 free_ident(&sid); /* NB: not needed below */
938 /*
939 * Check this profile is not already on the stack.
940 */
941 if (lookup_stack_by_path(profile->path) != NULL) {
942 connman_error("%s: already pushed", __func__);
943 return -EEXIST;
944 }
945 if (path != NULL)
946 *path = profile->path;
947 }
948
949 profile_stack[++cur_profile] = profile;
950
951 profiles_changed();
952
953 /* NB: this is a noop if we are online (or trying to get online) */
954 __connman_service_auto_connect_any();
955
956 return 0;
957 }
958
959 /*
960 * Pop the profile from the top of the stack and remove it from
961 * the in-memory table. Any associated services are invalidated
962 * (credentials revoked and connections closed). After a pop we
963 * generate a PropertyChanged signal for Manager.Profiles.
964 *
965 * An optional identifier may be specified. If specified it is
966 * checked against the active profile and if not the same then
967 * the request is rejected. This is useful to ensure the right
968 * profile is pop'd (as might happen on logout if an associated
969 * push failed for some reason).
970 */
971 int __connman_profile_pop(const char *ident)
972 {
973 struct connman_profile *profile;
974
975 _DBG_PROFILE("ident %s", ident);
976
977 if (cur_profile < 0) {
978 connman_error("%s: profile stack empty", __func__);
979 return -EINVAL;
980 }
981
982 profile = profile_stack[cur_profile];
983
984 if (ident != NULL) {
985 struct connman_storage_ident sid;
986
987 if (parse_ident(ident, &sid) == FALSE) {
988 connman_error("%s: invalid profile name %s",
989 __func__, ident);
990 return -EINVAL;
991 }
992 if (ident_equal(&profile->ident, &sid) == FALSE) {
993 connman_error("%s: %s is not the active profile",
994 __func__, ident);
995 free_ident(&sid);
996 return -ENXIO;
997 }
998 free_ident(&sid);
999 }
1000
1001 __connman_service_invalidate_profile(&profile->ident);
1002
1003 g_hash_table_remove(profile_hash, profile->path);
1004 cur_profile--;
1005
1006 profiles_changed();
1007
1008 /* NB: no need to kick auto-connect; it will happen due to invalidate */
1009
1010 return 0;
1011 }
1012
1013 /*
1014 * Create a profile file and register it in memory. The
1015 * file is created with minimal contents.
1016 * TODO(sleffler) disallow overwriting an existing file?
1017 */
665 int __connman_profile_create(const char *name, const char **path) 1018 int __connman_profile_create(const char *name, const char **path)
666 { 1019 {
667 struct connman_profile *profile; 1020 struct connman_profile *profile;
1021 struct connman_storage_ident sid;
668 int err; 1022 int err;
669 1023
670 _DBG_PROFILE("name %s", name); 1024 _DBG_PROFILE("name %s", name);
671 1025
672 » if (validate_ident(name) == FALSE) 1026 » if (parse_ident(name, &sid) == FALSE) {
673 » » return -EINVAL; 1027 » » connman_error("%s: invalid profile name %s)", __func__, name);
674 1028 » » return -EINVAL;
675 » err = create_profile(name, NULL, path); 1029 » }
676 » if (err < 0) 1030
1031 » err = create_profile(&sid, NULL, path, &profile);
1032 » if (err < 0) {
1033 » » connman_error("%s: cannot open, error %d", __func__, err);
1034 » » /* NB: create_profile reclaims sid */
677 return err; 1035 return err;
678 1036 » }
679 » profile = g_hash_table_lookup(profile_hash, *path);
680 » if (profile == NULL)
681 » » return -EIO;
682 1037
683 __connman_storage_save_profile(profile); 1038 __connman_storage_save_profile(profile);
684 1039
685 profiles_changed(); 1040 profiles_changed();
686 1041
687 return 0; 1042 return 0;
688 } 1043 }
689 1044
690 int __connman_profile_remove(const char *path) 1045 /*
691 { 1046 * Delete a profile and remove from memory. The default
692 » struct connman_profile *profile; 1047 * profile may not be removed/deleted. Likewise, one
693 1048 * cannot remove a profile pushed on the stack.
694 » _DBG_PROFILE("path %s", path); 1049 */
695 1050 int __connman_profile_remove(const char *ident)
696 » if (default_profile != NULL && 1051 {
697 » » » » g_strcmp0(path, default_profile->path) == 0) 1052 » struct connman_profile *profile;
698 » » return -EINVAL; 1053 » struct connman_storage_ident sid;
699 1054 » char *tmp_path;
700 » profile = g_hash_table_lookup(profile_hash, path); 1055 » int err = 0;
701 » if (profile == NULL) 1056
702 » » return -ENXIO; 1057 » _DBG_PROFILE("ident %s", ident);
703 1058
704 » __connman_storage_delete(profile->ident); 1059 » if (parse_ident(ident, &sid) == FALSE) {
705 1060 » » connman_error("%s: invalid profile name %s)", __func__, ident);
706 » g_hash_table_remove(profile_hash, path); 1061 » » return -EINVAL;
707 1062 » }
708 » profiles_changed(); 1063
709 1064 » if (ident_equal(&sid, &default_ident)) {
710 » return 0; 1065 » » /* TODO(sleffler) should this be permitted? */
711 } 1066 » » connman_error("%s: cannot delete default profile", __func__);
712 1067 » » err = -EINVAL;
1068 » » goto done;
1069 » }
1070
1071 » /*
1072 » * Check for in-memory profile by way of a CreateProfile request.
1073 » */
1074 » tmp_path = getpath(&sid);
1075 » if (tmp_path == NULL) {
1076 » » connman_error("%s: no memory for %s", __func__, ident);
1077 » » err = -ENOMEM;
1078 » » goto done;
1079 » }
1080 » profile = g_hash_table_lookup(profile_hash, tmp_path);
1081 » g_free(tmp_path);
1082
1083 » if (profile != NULL) {
1084 » » /*
1085 » » * Check this profile is not on the stack.
1086 » » */
1087 » » if (lookup_stack_by_path(profile->path) != NULL) {
1088 » » » connman_error("%s: cannot delete (on the stack)",
1089 » » » __func__);
1090 » » » err = -EEXIST;
1091 » » » goto done;
1092 » » }
1093 » » g_hash_table_remove(profile_hash, profile->path);
1094
1095 » » profiles_changed();
1096 » }
1097
1098 » __connman_storage_delete(&sid);
1099 done:
1100 » free_ident(&sid);
1101 » return err;
1102 }
1103
1104 /*
1105 * Initialize the profile stack by pushing the default
1106 * (global) profile. Unlike connman we do not read in
1107 * all available .profile's in the global dir.
1108 */
713 static int profile_init(void) 1109 static int profile_init(void)
714 { 1110 {
715 » GDir *dir; 1111 » struct connman_profile *profile;
716 » const gchar *file; 1112 » int err;
717 1113
718 » _DBG_PROFILE(""); 1114 » err = create_profile(&default_ident, "Default", NULL, &profile);
719 1115 » if (err == 0)
720 » dir = g_dir_open(STORAGEDIR, 0, NULL); 1116 » » profile_stack[++cur_profile] = profile;
721 » if (dir != NULL) { 1117 » return err;
722 » » while ((file = g_dir_read_name(dir)) != NULL) {
723 » » » GString *str;
724 » » » gchar *ident;
725
726 » » » if (g_str_has_suffix(file, ".profile") == FALSE)
727 » » » » continue;
728
729 » » » ident = g_strrstr(file, ".profile");
730 » » » if (ident == NULL)
731 » » » » continue;
732
733 » » » str = g_string_new_len(file, ident - file);
734 » » » if (str == NULL)
735 » » » » continue;
736
737 » » » ident = g_string_free(str, FALSE);
738
739 » » » if (validate_ident(ident) == TRUE)
740 » » » » create_profile(ident, NULL, NULL);
741
742 » » » g_free(ident);
743 » » }
744
745 » » g_dir_close(dir);
746 » }
747
748 » if (g_hash_table_size(profile_hash) == 0)
749 » » create_profile(PROFILE_DEFAULT_IDENT, "Default", NULL);
750
751 » profiles_changed();
752
753 » return 0;
754 } 1118 }
755 1119
756 static int profile_load(struct connman_profile *profile) 1120 static int profile_load(struct connman_profile *profile)
757 { 1121 {
758 GKeyFile *keyfile; 1122 GKeyFile *keyfile;
759 GError *error = NULL; 1123 GError *error = NULL;
760 connman_bool_t offlinemode; 1124 connman_bool_t offlinemode;
761 char *name; 1125 char *name;
762 1126
763 _DBG_PROFILE("profile %p", profile); 1127 _DBG_PROFILE("profile %p", profile);
764 1128
765 » keyfile = __connman_storage_open(profile->ident); 1129 » keyfile = __connman_storage_open(&profile->ident);
766 if (keyfile == NULL) 1130 if (keyfile == NULL)
767 return -EIO; 1131 return -EIO;
768 1132
769 name = g_key_file_get_string(keyfile, "global", "Name", NULL); 1133 name = g_key_file_get_string(keyfile, "global", "Name", NULL);
770 if (name != NULL) { 1134 if (name != NULL) {
771 g_free(profile->name); 1135 g_free(profile->name);
772 profile->name = name; 1136 profile->name = name;
773 } 1137 }
774 1138
775 offlinemode = g_key_file_get_boolean(keyfile, "global", 1139 offlinemode = g_key_file_get_boolean(keyfile, "global",
776 "OfflineMode", &error); 1140 "OfflineMode", &error);
777 if (error == NULL) 1141 if (error == NULL)
778 profile->offlinemode = offlinemode; 1142 profile->offlinemode = offlinemode;
779 g_clear_error(&error); 1143 g_clear_error(&error);
780 1144
781 » __connman_storage_close(profile->ident, keyfile, FALSE); 1145 » __connman_storage_close(&profile->ident, keyfile, FALSE);
782 1146
783 return 0; 1147 return 0;
784 } 1148 }
785 1149
786 static int profile_save(struct connman_profile *profile) 1150 static int profile_save(struct connman_profile *profile)
787 { 1151 {
788 GKeyFile *keyfile; 1152 GKeyFile *keyfile;
789 1153
790 _DBG_PROFILE("profile %p", profile); 1154 _DBG_PROFILE("profile %p", profile);
791 1155
792 » keyfile = __connman_storage_open(profile->ident); 1156 » keyfile = __connman_storage_open(&profile->ident);
793 if (keyfile == NULL) 1157 if (keyfile == NULL)
794 return -EIO; 1158 return -EIO;
795 1159
796 if (profile->name != NULL) 1160 if (profile->name != NULL)
797 g_key_file_set_string(keyfile, "global", 1161 g_key_file_set_string(keyfile, "global",
798 "Name", profile->name); 1162 "Name", profile->name);
799 1163
800 g_key_file_set_boolean(keyfile, "global", 1164 g_key_file_set_boolean(keyfile, "global",
801 "OfflineMode", profile->offlinemode); 1165 "OfflineMode", profile->offlinemode);
802 1166
803 » __connman_storage_close(profile->ident, keyfile, TRUE); 1167 » __connman_storage_close(&profile->ident, keyfile, TRUE);
804 1168
805 return 0; 1169 return 0;
806 } 1170 }
807 1171
808 static struct connman_storage profile_storage = { 1172 static struct connman_storage profile_storage = {
809 .name = "profile", 1173 .name = "profile",
810 .priority = CONNMAN_STORAGE_PRIORITY_LOW, 1174 .priority = CONNMAN_STORAGE_PRIORITY_LOW,
811 .profile_init = profile_init, 1175 .profile_init = profile_init,
812 .profile_load = profile_load, 1176 .profile_load = profile_load,
813 .profile_save = profile_save, 1177 .profile_save = profile_save,
814 }; 1178 };
815 1179
816 int __connman_profile_init(void) 1180 int __connman_profile_init(void)
817 { 1181 {
818 _DBG_PROFILE(""); 1182 _DBG_PROFILE("");
819 1183
820 connection = connman_dbus_get_connection(); 1184 connection = connman_dbus_get_connection();
821 if (connection == NULL) 1185 if (connection == NULL)
822 return -1; 1186 return -1;
823 1187
824 if (connman_storage_register(&profile_storage) < 0) 1188 if (connman_storage_register(&profile_storage) < 0)
825 connman_error("Failed to register profile storage"); 1189 connman_error("Failed to register profile storage");
826 1190
827 profile_hash = g_hash_table_new_full(g_str_hash, g_str_equal, 1191 profile_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
828 g_free, unregister_profile); 1192 g_free, unregister_profile);
829 1193
830 return 0; 1194 return 0;
831 } 1195 }
832 1196
1197 int __connman_profile_push_batch(char **profiles)
1198 {
1199 int i;
1200
1201 if (profiles == NULL)
1202 return 0;
1203
1204 for (i = 0; profiles[i] != NULL; i++) {
1205 int err = __connman_profile_push(profiles[i], NULL, NULL);
1206 if (err != 0)
1207 return err;
1208 }
1209 return 0;
1210 }
1211
833 void __connman_profile_cleanup(void) 1212 void __connman_profile_cleanup(void)
834 { 1213 {
835 _DBG_PROFILE(""); 1214 _DBG_PROFILE("");
836 1215
837 if (connection == NULL) 1216 if (connection == NULL)
838 return; 1217 return;
839 1218
1219 while (cur_profile >= 0)
1220 __connman_profile_pop(NULL);
1221
840 g_hash_table_destroy(profile_hash); 1222 g_hash_table_destroy(profile_hash);
841 profile_hash = NULL; 1223 profile_hash = NULL;
842 1224
1225 clear_timeout(); /* cancel any pending timer */
1226
843 connman_storage_unregister(&profile_storage); 1227 connman_storage_unregister(&profile_storage);
844 1228
845 dbus_connection_unref(connection); 1229 dbus_connection_unref(connection);
846 } 1230 }
OLDNEW
« no previous file with comments | « src/manager.c ('k') | src/service.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698