blob: dea61a52f33d61849e94c784f9e18bc09953d3a7 [file] [log] [blame]
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Paul Stewart75897df2011-04-27 09:05:53 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Chris Masone8fe2c7e2011-06-09 15:51:19 -07005#include "shill/manager.h"
6
Paul Stewart75897df2011-04-27 09:05:53 -07007#include <time.h>
Paul Stewart75897df2011-04-27 09:05:53 -07008#include <stdio.h>
Chris Masoneee929b72011-05-10 10:02:18 -07009
Paul Stewart22aa71b2011-09-16 12:15:11 -070010#include <algorithm>
Paul Stewart75897df2011-04-27 09:05:53 -070011#include <string>
Chris Masone52cd19b2011-06-29 17:23:04 -070012#include <vector>
Paul Stewart75897df2011-04-27 09:05:53 -070013
Eric Shienbrood3e20a232012-02-16 11:35:56 -050014#include <base/bind.h>
Paul Stewarte6132022011-08-16 09:11:02 -070015#include <base/file_util.h>
Chris Masoneee929b72011-05-10 10:02:18 -070016#include <base/logging.h>
Chris Masone9be4a9d2011-05-16 15:44:09 -070017#include <base/memory/ref_counted.h>
Eric Shienbrood3e20a232012-02-16 11:35:56 -050018#include <base/stringprintf.h>
Paul Stewart22aa71b2011-09-16 12:15:11 -070019#include <base/string_util.h>
Chris Masone3bd3c8c2011-06-13 08:20:26 -070020#include <chromeos/dbus/service_constants.h>
Chris Masoneee929b72011-05-10 10:02:18 -070021
Chris Masoned0ceb8c2011-06-02 10:05:39 -070022#include "shill/adaptor_interfaces.h"
Paul Stewartc1dec4d2011-12-08 15:25:28 -080023#include "shill/connection.h"
Paul Stewart75897df2011-04-27 09:05:53 -070024#include "shill/control_interface.h"
Chris Masoned0ceb8c2011-06-02 10:05:39 -070025#include "shill/dbus_adaptor.h"
Chris Masone7aa5f902011-07-11 11:13:35 -070026#include "shill/default_profile.h"
Chris Masone9be4a9d2011-05-16 15:44:09 -070027#include "shill/device.h"
28#include "shill/device_info.h"
Chris Masone6791a432011-07-12 13:23:19 -070029#include "shill/ephemeral_profile.h"
Chris Masone8fe2c7e2011-06-09 15:51:19 -070030#include "shill/error.h"
Paul Stewart26b327e2011-10-19 11:38:09 -070031#include "shill/event_dispatcher.h"
Chris Masone9d779932011-08-25 16:33:41 -070032#include "shill/key_file_store.h"
Thieu Lea20cbc22012-01-09 22:01:43 +000033#include "shill/metrics.h"
Chris Masone7aa5f902011-07-11 11:13:35 -070034#include "shill/profile.h"
Chris Masoneb925cc82011-06-22 15:39:57 -070035#include "shill/property_accessor.h"
Gary Morainac1bdb42012-02-16 17:42:29 -080036#include "shill/proxy_factory.h"
Paul Stewarte6132022011-08-16 09:11:02 -070037#include "shill/resolver.h"
Ben Chanfad4a0b2012-04-18 15:49:59 -070038#include "shill/scope_logger.h"
Chris Masone9be4a9d2011-05-16 15:44:09 -070039#include "shill/service.h"
Thieu Lea20cbc22012-01-09 22:01:43 +000040#include "shill/service_sorter.h"
Darin Petkov33af05c2012-02-28 10:10:30 +010041#include "shill/vpn_service.h"
mukesh agrawal7a4e4002011-09-06 11:26:05 -070042#include "shill/wifi.h"
43#include "shill/wifi_service.h"
Paul Stewart75897df2011-04-27 09:05:53 -070044
Eric Shienbrood3e20a232012-02-16 11:35:56 -050045using base::Bind;
46using base::StringPrintf;
47using base::Unretained;
Gaurav Shah435de2c2011-11-17 19:01:07 -080048using std::set;
Paul Stewart75897df2011-04-27 09:05:53 -070049using std::string;
Chris Masone9be4a9d2011-05-16 15:44:09 -070050using std::vector;
Paul Stewart75897df2011-04-27 09:05:53 -070051
52namespace shill {
Paul Stewarte6132022011-08-16 09:11:02 -070053
Darin Petkovb65c2452012-02-23 15:17:06 +010054// statics
55const char Manager::kErrorNoDevice[] = "no wifi devices available";
56const char Manager::kErrorTypeRequired[] = "must specify service type";
57const char Manager::kErrorUnsupportedServiceType[] =
58 "service type is unsupported";
mukesh agrawal7a4e4002011-09-06 11:26:05 -070059
Paul Stewart75897df2011-04-27 09:05:53 -070060Manager::Manager(ControlInterface *control_interface,
Darin Petkov887f2982011-07-14 16:10:17 -070061 EventDispatcher *dispatcher,
Thieu Le3426c8f2012-01-11 17:35:11 -080062 Metrics *metrics,
Chris Masone2ae797d2011-08-23 20:41:00 -070063 GLib *glib,
64 const string &run_directory,
65 const string &storage_directory,
66 const string &user_storage_format)
mukesh agrawal8a3188d2011-12-01 20:56:44 +000067 : dispatcher_(dispatcher),
mukesh agrawal8a3188d2011-12-01 20:56:44 +000068 run_path_(FilePath(run_directory)),
69 storage_path_(FilePath(storage_directory)),
70 user_storage_format_(user_storage_format),
71 adaptor_(control_interface->CreateManagerAdaptor(this)),
Thieu Le3426c8f2012-01-11 17:35:11 -080072 device_info_(control_interface, dispatcher, metrics, this),
73 modem_info_(control_interface, dispatcher, metrics, this, glib),
Darin Petkov33af05c2012-02-28 10:10:30 +010074 vpn_provider_(control_interface, dispatcher, metrics, this),
mukesh agrawal8a3188d2011-12-01 20:56:44 +000075 running_(false),
76 connect_profiles_to_rpc_(true),
77 ephemeral_profile_(new EphemeralProfile(control_interface, this)),
78 control_interface_(control_interface),
Thieu Le3426c8f2012-01-11 17:35:11 -080079 metrics_(metrics),
mukesh agrawal8a3188d2011-12-01 20:56:44 +000080 glib_(glib) {
Chris Masone7aa5f902011-07-11 11:13:35 -070081 HelpRegisterDerivedString(flimflam::kActiveProfileProperty,
Paul Stewart1b253142012-01-26 14:05:52 -080082 &Manager::GetActiveProfileRpcIdentifier,
Chris Masone7aa5f902011-07-11 11:13:35 -070083 NULL);
Chris Masone27c4aa52011-07-02 13:10:14 -070084 HelpRegisterDerivedStrings(flimflam::kAvailableTechnologiesProperty,
85 &Manager::AvailableTechnologies,
86 NULL);
Chris Masone88cbd5f2011-07-03 14:30:04 -070087 store_.RegisterString(flimflam::kCheckPortalListProperty,
88 &props_.check_portal_list);
Chris Masone27c4aa52011-07-02 13:10:14 -070089 HelpRegisterDerivedStrings(flimflam::kConnectedTechnologiesProperty,
90 &Manager::ConnectedTechnologies,
91 NULL);
Chris Masone88cbd5f2011-07-03 14:30:04 -070092 store_.RegisterString(flimflam::kCountryProperty, &props_.country);
Chris Masone27c4aa52011-07-02 13:10:14 -070093 HelpRegisterDerivedString(flimflam::kDefaultTechnologyProperty,
94 &Manager::DefaultTechnology,
95 NULL);
Chris Masone27c4aa52011-07-02 13:10:14 -070096 HelpRegisterDerivedStrings(flimflam::kDevicesProperty,
97 &Manager::EnumerateDevices,
98 NULL);
Chris Masone88cbd5f2011-07-03 14:30:04 -070099 HelpRegisterDerivedStrings(flimflam::kEnabledTechnologiesProperty,
100 &Manager::EnabledTechnologies,
101 NULL);
102 store_.RegisterBool(flimflam::kOfflineModeProperty, &props_.offline_mode);
103 store_.RegisterString(flimflam::kPortalURLProperty, &props_.portal_url);
Paul Stewartc681fa02012-03-02 19:40:04 -0800104 store_.RegisterInt32(kPortalCheckIntervalProperty,
105 &props_.portal_check_interval_seconds);
Paul Stewart1b253142012-01-26 14:05:52 -0800106 HelpRegisterDerivedStrings(flimflam::kProfilesProperty,
107 &Manager::EnumerateProfiles,
108 NULL);
Paul Stewartc681fa02012-03-02 19:40:04 -0800109 store_.RegisterString(kHostNameProperty, &props_.host_name);
Chris Masone88cbd5f2011-07-03 14:30:04 -0700110 HelpRegisterDerivedString(flimflam::kStateProperty,
111 &Manager::CalculateState,
112 NULL);
mukesh agrawal2366eed2012-03-20 18:21:50 -0700113 HelpRegisterConstDerivedRpcIdentifiers(flimflam::kServicesProperty,
114 &Manager::EnumerateAvailableServices);
Chris Masone27c4aa52011-07-02 13:10:14 -0700115 HelpRegisterDerivedStrings(flimflam::kServiceWatchListProperty,
116 &Manager::EnumerateWatchedServices,
117 NULL);
Chris Masone3c3f6a12011-07-01 10:01:41 -0700118
mukesh agrawal84de5d22012-02-17 19:29:15 -0800119 // Set default technology order "by hand", to avoid invoking side
120 // effects of SetTechnologyOrder.
121 technology_order_.push_back(
Darin Petkov2f903b32012-04-18 12:56:43 +0200122 Technology::IdentifierFromName(flimflam::kTypeVPN));
123 technology_order_.push_back(
mukesh agrawal84de5d22012-02-17 19:29:15 -0800124 Technology::IdentifierFromName(flimflam::kTypeEthernet));
125 technology_order_.push_back(
126 Technology::IdentifierFromName(flimflam::kTypeWifi));
127 technology_order_.push_back(
128 Technology::IdentifierFromName(flimflam::kTypeCellular));
129
Ben Chanfad4a0b2012-04-18 15:49:59 -0700130 SLOG(Manager, 2) << "Manager initialized.";
Paul Stewart75897df2011-04-27 09:05:53 -0700131}
132
Chris Masone6791a432011-07-12 13:23:19 -0700133Manager::~Manager() {
Chris Masone9d779932011-08-25 16:33:41 -0700134 profiles_.clear();
Chris Masone6791a432011-07-12 13:23:19 -0700135}
Paul Stewart75897df2011-04-27 09:05:53 -0700136
mukesh agrawal8f317b62011-07-15 11:53:23 -0700137void Manager::AddDeviceToBlackList(const string &device_name) {
138 device_info_.AddDeviceToBlackList(device_name);
139}
140
Paul Stewart75897df2011-04-27 09:05:53 -0700141void Manager::Start() {
Paul Stewart0af98bf2011-05-10 17:38:08 -0700142 LOG(INFO) << "Manager started.";
Paul Stewarte6132022011-08-16 09:11:02 -0700143
Gary Morainac1bdb42012-02-16 17:42:29 -0800144 power_manager_.reset(new PowerManager(ProxyFactory::GetInstance()));
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500145 // TODO(ers): weak ptr for metrics_?
146 PowerManager::PowerStateCallback cb =
147 Bind(&Metrics::NotifyPowerStateChange, Unretained(metrics_));
Thieu Leb84ba342012-03-02 15:15:19 -0800148 power_manager_->AddStateChangeCallback(Metrics::kMetricPowerManagerKey, cb);
149
Chris Masone2ae797d2011-08-23 20:41:00 -0700150 CHECK(file_util::CreateDirectory(run_path_)) << run_path_.value();
Paul Stewarte6132022011-08-16 09:11:02 -0700151 Resolver::GetInstance()->set_path(run_path_.Append("resolv.conf"));
Chris Masone2ae797d2011-08-23 20:41:00 -0700152
Gaurav Shah71354762011-11-28 19:22:49 -0800153 InitializeProfiles();
Paul Stewart75897df2011-04-27 09:05:53 -0700154 running_ = true;
Chris Masone413a3192011-05-09 17:10:05 -0700155 adaptor_->UpdateRunning();
Paul Stewart0af98bf2011-05-10 17:38:08 -0700156 device_info_.Start();
Darin Petkov887f2982011-07-14 16:10:17 -0700157 modem_info_.Start();
Darin Petkov33af05c2012-02-28 10:10:30 +0100158 vpn_provider_.Start();
Paul Stewart75897df2011-04-27 09:05:53 -0700159}
160
161void Manager::Stop() {
162 running_ = false;
Chris Masone9d779932011-08-25 16:33:41 -0700163 // Persist profile, device, service information to disk.
164 vector<ProfileRefPtr>::iterator it;
165 for (it = profiles_.begin(); it != profiles_.end(); ++it) {
Paul Stewartd0a3b812012-03-28 22:48:22 -0700166 // Since this happens in a loop, the current manager state is stored to
167 // all default profiles in the stack. This is acceptable because the
168 // only time multiple default profiles are loaded are during autotests.
Chris Masone6515aab2011-10-12 16:19:09 -0700169 (*it)->Save();
Chris Masone9d779932011-08-25 16:33:41 -0700170 }
Chris Masone9d779932011-08-25 16:33:41 -0700171
Thieu Le1271d682011-11-02 22:48:19 +0000172 vector<ServiceRefPtr>::iterator services_it;
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000173 Error e;
Thieu Le1271d682011-11-02 22:48:19 +0000174 for (services_it = services_.begin(); services_it != services_.end();
175 ++services_it) {
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000176 (*services_it)->Disconnect(&e);
Thieu Le1271d682011-11-02 22:48:19 +0000177 }
178
Chris Masone413a3192011-05-09 17:10:05 -0700179 adaptor_->UpdateRunning();
Darin Petkov33af05c2012-02-28 10:10:30 +0100180 vpn_provider_.Stop();
Darin Petkov887f2982011-07-14 16:10:17 -0700181 modem_info_.Stop();
182 device_info_.Stop();
Thieu Leb84ba342012-03-02 15:15:19 -0800183
184 // Some unit tests do not call Manager::Start().
185 if (power_manager_.get())
186 power_manager_->RemoveStateChangeCallback(Metrics::kMetricPowerManagerKey);
Paul Stewart75897df2011-04-27 09:05:53 -0700187}
188
Gaurav Shah71354762011-11-28 19:22:49 -0800189void Manager::InitializeProfiles() {
190 DCHECK(profiles_.empty());
191 // The default profile must go first on the stack.
192 CHECK(file_util::CreateDirectory(storage_path_)) << storage_path_.value();
Paul Stewart870523b2012-01-11 17:00:42 -0800193 scoped_refptr<DefaultProfile>
194 default_profile(new DefaultProfile(control_interface_,
Gaurav Shah71354762011-11-28 19:22:49 -0800195 this,
196 storage_path_,
Paul Stewartd0a3b812012-03-28 22:48:22 -0700197 DefaultProfile::kDefaultId,
Gaurav Shah71354762011-11-28 19:22:49 -0800198 props_));
Paul Stewart870523b2012-01-11 17:00:42 -0800199 CHECK(default_profile->InitStorage(glib_, Profile::kCreateOrOpenExisting,
200 NULL));
201 CHECK(default_profile->LoadManagerProperties(&props_));
202 profiles_.push_back(default_profile.release());
Gaurav Shah71354762011-11-28 19:22:49 -0800203 Error error;
Paul Stewart19c871d2011-12-15 16:10:13 -0800204 string path;
Gaurav Shah71354762011-11-28 19:22:49 -0800205 for (vector<string>::iterator it = startup_profiles_.begin();
206 it != startup_profiles_.end(); ++it)
Paul Stewart19c871d2011-12-15 16:10:13 -0800207 PushProfile(*it, &path, &error);
Gaurav Shah71354762011-11-28 19:22:49 -0800208}
209
Paul Stewart19c871d2011-12-15 16:10:13 -0800210void Manager::CreateProfile(const string &name, string *path, Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700211 SLOG(Manager, 2) << __func__ << " " << name;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700212 Profile::Identifier ident;
213 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700214 Error::PopulateAndLog(error, Error::kInvalidArguments,
215 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700216 return;
217 }
Paul Stewartd0a3b812012-03-28 22:48:22 -0700218
219 ProfileRefPtr profile;
220 if (ident.user.empty()) {
221 profile = new DefaultProfile(control_interface_,
222 this,
223 storage_path_,
224 ident.identifier,
225 props_);
226 } else {
227 profile = new Profile(control_interface_,
228 this,
229 ident,
230 user_storage_format_,
Paul Stewarte73d05c2012-03-29 16:26:05 -0700231 false);
Paul Stewartd0a3b812012-03-28 22:48:22 -0700232 }
233
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700234 if (!profile->InitStorage(glib_, Profile::kCreateNew, error)) {
Paul Stewart19c871d2011-12-15 16:10:13 -0800235 // |error| will have been populated by InitStorage().
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700236 return;
237 }
238
239 // Save profile data out, and then let the scoped pointer fall out of scope.
240 if (!profile->Save()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700241 Error::PopulateAndLog(error, Error::kInternalError,
242 "Profile name " + name + " could not be saved");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700243 return;
244 }
Paul Stewart19c871d2011-12-15 16:10:13 -0800245
246 *path = profile->GetRpcIdentifier();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700247}
248
Paul Stewart19c871d2011-12-15 16:10:13 -0800249void Manager::PushProfile(const string &name, string *path, Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700250 SLOG(Manager, 2) << __func__ << " " << name;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700251 Profile::Identifier ident;
252 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700253 Error::PopulateAndLog(error, Error::kInvalidArguments,
254 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700255 return;
256 }
257
258 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
259 it != profiles_.end();
260 ++it) {
261 if ((*it)->MatchesIdentifier(ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700262 Error::PopulateAndLog(error, Error::kAlreadyExists,
263 "Profile name " + name + " is already on stack");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700264 return;
265 }
266 }
267
Paul Stewartd0a3b812012-03-28 22:48:22 -0700268 ProfileRefPtr profile;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700269 if (ident.user.empty()) {
Paul Stewartd0a3b812012-03-28 22:48:22 -0700270 // Allow a machine-wide-profile to be pushed on the stack only if the
271 // profile stack is empty, or if the topmost profile on the stack is
272 // also a machine-wide (non-user) profile.
273 if (!profiles_.empty() && !profiles_.back()->GetUser().empty()) {
274 Error::PopulateAndLog(error, Error::kInvalidArguments,
275 "Cannot load non-default global profile " + name +
276 " on top of a user profile");
277 return;
278 }
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700279
Paul Stewartd0a3b812012-03-28 22:48:22 -0700280 scoped_refptr<DefaultProfile>
281 default_profile(new DefaultProfile(control_interface_,
282 this,
283 storage_path_,
284 ident.identifier,
285 props_));
286 if (!default_profile->InitStorage(glib_, Profile::kOpenExisting, error)) {
287 // |error| will have been populated by InitStorage().
288 return;
289 }
290
291 if (!default_profile->LoadManagerProperties(&props_)) {
292 Error::PopulateAndLog(error, Error::kInvalidArguments,
293 "Could not load Manager properties from profile " +
294 name);
295 return;
296 }
297 profile = default_profile;
298 } else {
299 profile = new Profile(control_interface_,
300 this,
301 ident,
302 user_storage_format_,
303 connect_profiles_to_rpc_);
304 if (!profile->InitStorage(glib_, Profile::kOpenExisting, error)) {
305 // |error| will have been populated by InitStorage().
306 return;
307 }
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700308 }
309
Paul Stewarta849a3d2011-11-03 05:54:09 -0700310 profiles_.push_back(profile);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700311
312 // Offer each registered Service the opportunity to join this new Profile.
Paul Stewarta41e38d2011-11-11 07:47:29 -0800313 for (vector<ServiceRefPtr>::iterator it = services_.begin();
314 it != services_.end(); ++it) {
Paul Stewartbba6a5b2011-11-02 18:45:59 -0700315 profile->ConfigureService(*it);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700316 }
317
Paul Stewarta41e38d2011-11-11 07:47:29 -0800318 // Shop the Profile contents around to Devices which can create
319 // non-visible services.
320 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
321 it != devices_.end(); ++it) {
322 profile->ConfigureDevice(*it);
323 }
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800324
Paul Stewart66815332012-04-09 18:09:36 -0700325 // Offer the Profile contents to the VPNProvider which will create
326 // new VPN services if necessary.
327 vpn_provider_.CreateServicesFromProfile(profile);
328
Paul Stewart19c871d2011-12-15 16:10:13 -0800329 *path = profile->GetRpcIdentifier();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800330 SortServices();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700331}
332
333void Manager::PopProfileInternal() {
334 CHECK(!profiles_.empty());
335 ProfileRefPtr active_profile = profiles_.back();
336 profiles_.pop_back();
Paul Stewart75225512012-01-26 22:51:33 -0800337 vector<ServiceRefPtr>::iterator it;
Paul Stewart65512e12012-03-26 18:01:08 -0700338 for (it = services_.begin(); it != services_.end();) {
339 if ((*it)->profile().get() != active_profile.get() ||
340 MatchProfileWithService(*it) ||
341 !UnloadService(&it)) {
342 LOG(ERROR) << "Skipping unload of service";
343 ++it;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700344 }
345 }
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800346 SortServices();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700347}
348
Paul Stewarta41e38d2011-11-11 07:47:29 -0800349void Manager::PopProfile(const string &name, Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700350 SLOG(Manager, 2) << __func__ << " " << name;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700351 Profile::Identifier ident;
352 if (profiles_.empty()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700353 Error::PopulateAndLog(error, Error::kNotFound, "Profile stack is empty");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700354 return;
355 }
356 ProfileRefPtr active_profile = profiles_.back();
357 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700358 Error::PopulateAndLog(error, Error::kInvalidArguments,
359 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700360 return;
361 }
362 if (!active_profile->MatchesIdentifier(ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700363 Error::PopulateAndLog(error, Error::kNotSupported,
364 name + " is not the active profile");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700365 return;
366 }
367 PopProfileInternal();
368}
369
370void Manager::PopAnyProfile(Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700371 SLOG(Manager, 2) << __func__;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700372 Profile::Identifier ident;
373 if (profiles_.empty()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700374 Error::PopulateAndLog(error, Error::kNotFound, "Profile stack is empty");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700375 return;
376 }
377 PopProfileInternal();
378}
379
Paul Stewarte73d05c2012-03-29 16:26:05 -0700380void Manager::RemoveProfile(const string &name, Error *error) {
381 Profile::Identifier ident;
382 if (!Profile::ParseIdentifier(name, &ident)) {
383 Error::PopulateAndLog(error, Error::kInvalidArguments,
384 "Invalid profile name " + name);
385 return;
386 }
387
388 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
389 it != profiles_.end();
390 ++it) {
391 if ((*it)->MatchesIdentifier(ident)) {
392 Error::PopulateAndLog(error, Error::kInvalidArguments,
393 "Cannot remove profile name " + name +
394 " since it is on stack");
395 return;
396 }
397 }
398
399 ProfileRefPtr profile;
400 if (ident.user.empty()) {
401 profile = new DefaultProfile(control_interface_,
402 this,
403 storage_path_,
404 ident.identifier,
405 props_);
406 } else {
407 profile = new Profile(control_interface_,
408 this,
409 ident,
410 user_storage_format_,
411 false);
412 }
413
414
415 // |error| will have been populated if RemoveStorage fails.
416 profile->RemoveStorage(glib_, error);
417
418 return;
419}
420
Paul Stewart75225512012-01-26 22:51:33 -0800421bool Manager::HandleProfileEntryDeletion(const ProfileRefPtr &profile,
422 const std::string &entry_name) {
423 bool moved_services = false;
424 for (vector<ServiceRefPtr>::iterator it = services_.begin();
Paul Stewart65512e12012-03-26 18:01:08 -0700425 it != services_.end();) {
Paul Stewart75225512012-01-26 22:51:33 -0800426 if ((*it)->profile().get() == profile.get() &&
427 (*it)->GetStorageIdentifier() == entry_name) {
428 profile->AbandonService(*it);
Paul Stewart65512e12012-03-26 18:01:08 -0700429 if (MatchProfileWithService(*it) ||
430 !UnloadService(&it)) {
431 ++it;
Paul Stewart75225512012-01-26 22:51:33 -0800432 }
433 moved_services = true;
Paul Stewart65512e12012-03-26 18:01:08 -0700434 } else {
435 ++it;
Paul Stewart75225512012-01-26 22:51:33 -0800436 }
437 }
438 return moved_services;
439}
440
Paul Stewart0756db92012-01-27 08:34:47 -0800441ServiceRefPtr Manager::GetServiceWithStorageIdentifier(
442 const ProfileRefPtr &profile, const std::string &entry_name, Error *error) {
443 for (vector<ServiceRefPtr>::iterator it = services_.begin();
444 it != services_.end(); ++it) {
445 if ((*it)->profile().get() == profile.get() &&
446 (*it)->GetStorageIdentifier() == entry_name) {
447 return *it;
448 }
449 }
450
451 Error::PopulateAndLog(error, Error::kNotFound,
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500452 StringPrintf("Entry %s is not registered in the manager",
453 entry_name.c_str()));
Paul Stewart0756db92012-01-27 08:34:47 -0800454 return NULL;
455}
456
Paul Stewart13ed2252012-03-21 12:52:46 -0700457ServiceRefPtr Manager::GetServiceWithGUID(
458 const std::string &guid, Error *error) {
459 for (vector<ServiceRefPtr>::iterator it = services_.begin();
460 it != services_.end(); ++it) {
461 if ((*it)->guid() == guid) {
462 return *it;
463 }
464 }
465
466 Error::PopulateAndLog(error, Error::kNotFound,
467 StringPrintf("Service wth GUID %s is not registered in the manager",
468 guid.c_str()));
469 return NULL;
470}
471
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700472ServiceRefPtr Manager::GetDefaultService() const {
473 if (services_.empty() || !services_[0]->connection().get()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700474 SLOG(Manager, 2) << "In " << __func__ << ": No default connection exists.";
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700475 return NULL;
476 }
477 return services_[0];
478}
479
Paul Stewart20088d82012-02-16 06:58:55 -0800480bool Manager::IsPortalDetectionEnabled(Technology::Identifier tech) {
481 Error error;
482 vector<Technology::Identifier> portal_technologies;
483 return Technology::GetTechnologyVectorFromString(props_.check_portal_list,
484 &portal_technologies,
485 &error) &&
486 std::find(portal_technologies.begin(), portal_technologies.end(),
487 tech) != portal_technologies.end();
488}
489
Paul Stewart1b253142012-01-26 14:05:52 -0800490const ProfileRefPtr &Manager::ActiveProfile() const {
Eric Shienbroodc74cf9c2012-03-02 15:00:35 -0500491 DCHECK_NE(profiles_.size(), 0U);
Chris Masone7aa5f902011-07-11 11:13:35 -0700492 return profiles_.back();
493}
494
Paul Stewart1b253142012-01-26 14:05:52 -0800495bool Manager::IsActiveProfile(const ProfileRefPtr &profile) const {
496 return (profiles_.size() > 0 &&
497 ActiveProfile().get() == profile.get());
498}
499
Eric Shienbrood9a245532012-03-07 14:20:39 -0500500void Manager::SaveActiveProfile() {
501 if (!profiles_.empty()) {
502 ActiveProfile()->Save();
503 }
504}
505
Chris Masone6515aab2011-10-12 16:19:09 -0700506bool Manager::MoveServiceToProfile(const ServiceRefPtr &to_move,
507 const ProfileRefPtr &destination) {
508 const ProfileRefPtr from = to_move->profile();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700509 SLOG(Manager, 2) << "Moving service "
510 << to_move->UniqueName()
511 << " to profile "
512 << destination->GetFriendlyName()
513 << " from "
514 << from->GetFriendlyName();
Chris Masone6515aab2011-10-12 16:19:09 -0700515 return destination->AdoptService(to_move) &&
516 from->AbandonService(to_move);
Chris Masone6791a432011-07-12 13:23:19 -0700517}
518
Paul Stewart7f61e522012-03-22 11:13:45 -0700519ProfileRefPtr Manager::LookupProfileByRpcIdentifier(
520 const string &profile_rpcid) {
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800521 for (vector<ProfileRefPtr>::iterator it = profiles_.begin();
522 it != profiles_.end();
523 ++it) {
524 if (profile_rpcid == (*it)->GetRpcIdentifier()) {
Paul Stewart7f61e522012-03-22 11:13:45 -0700525 return *it;
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800526 }
527 }
Paul Stewart7f61e522012-03-22 11:13:45 -0700528 return NULL;
529}
530
531void Manager::SetProfileForService(const ServiceRefPtr &to_set,
532 const string &profile_rpcid,
533 Error *error) {
534 ProfileRefPtr profile = LookupProfileByRpcIdentifier(profile_rpcid);
535 if (!profile) {
536 Error::PopulateAndLog(error, Error::kInvalidArguments,
537 StringPrintf("Unknown Profile %s requested for "
538 "Service", profile_rpcid.c_str()));
539 return;
540 }
541
542 if (to_set->profile().get() == profile.get()) {
543 Error::PopulateAndLog(error, Error::kInvalidArguments,
544 "Service is already connected to this profile");
545 } else if (!MoveServiceToProfile(to_set, profile)) {
546 Error::PopulateAndLog(error, Error::kInternalError,
547 "Unable to move service to profile");
548 }
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800549}
550
Eric Shienbrood9a245532012-03-07 14:20:39 -0500551void Manager::EnableTechnology(const std::string &technology_name,
552 Error *error,
553 const ResultCallback &callback) {
554 Technology::Identifier id = Technology::IdentifierFromName(technology_name);
555 if (id == Technology::kUnknown) {
556 error->Populate(Error::kInvalidArguments, "Unknown technology");
557 return;
558 }
559 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
560 it != devices_.end(); ++it) {
561 DeviceRefPtr device = *it;
562 if (device->technology() == id && !device->enabled()) {
563 device->SetEnabledPersistent(true, error, callback);
564 // Continue with other devices even if one fails
565 // TODO(ers): Decide whether an error should be returned
566 // for the overall EnableTechnology operation if some
567 // devices succeed and some fail.
568 }
569 }
570}
571
572void Manager::DisableTechnology(const std::string &technology_name,
573 Error *error,
574 const ResultCallback &callback) {
575 Technology::Identifier id = Technology::IdentifierFromName(technology_name);
576 if (id == Technology::kUnknown) {
577 error->Populate(Error::kInvalidArguments, "Unknown technology");
578 return;
579 }
580 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
581 it != devices_.end(); ++it) {
582 DeviceRefPtr device = *it;
583 if (device->technology() == id && device->enabled()) {
584 device->SetEnabledPersistent(false, error, callback);
585 // Continue with other devices even if one fails
586 // TODO(ers): Decide whether an error should be returned
587 // for the overall DisableTechnology operation if some
588 // devices succeed and some fail.
589 }
590 }
591}
592
593void Manager::UpdateEnabledTechnologies() {
594 Error error;
595 adaptor_->EmitStringsChanged(flimflam::kEnabledTechnologiesProperty,
596 EnabledTechnologies(&error));
597}
598
Chris Masone2b105542011-06-22 10:58:09 -0700599void Manager::RegisterDevice(const DeviceRefPtr &to_manage) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700600 SLOG(Manager, 2) << __func__ << "(" << to_manage->FriendlyName() << ")";
Chris Masonec1e50412011-06-07 13:04:53 -0700601 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700602 for (it = devices_.begin(); it != devices_.end(); ++it) {
Chris Masonec1e50412011-06-07 13:04:53 -0700603 if (to_manage.get() == it->get())
Chris Masone9be4a9d2011-05-16 15:44:09 -0700604 return;
605 }
Chris Masonec1e50412011-06-07 13:04:53 -0700606 devices_.push_back(to_manage);
Paul Stewartf1ce5d22011-05-19 13:10:20 -0700607
Paul Stewarta41e38d2011-11-11 07:47:29 -0800608 // We are applying device properties from the DefaultProfile, and adding
609 // the union of hidden services in all loaded profiles to the device.
Chris Masone6515aab2011-10-12 16:19:09 -0700610 for (vector<ProfileRefPtr>::iterator it = profiles_.begin();
611 it != profiles_.end();
612 ++it) {
Paul Stewarta41e38d2011-11-11 07:47:29 -0800613 // Load device configuration, if any exists, as well as hidden services.
614 (*it)->ConfigureDevice(to_manage);
615
616 // Currently the only profile for which "Save" is implemented is the
617 // DefaultProfile. It iterates over all Devices and stores their state.
618 // We perform the Save now in case the device we have just registered
619 // is new and needs to be added to the stored DefaultProfile.
Chris Masone6515aab2011-10-12 16:19:09 -0700620 (*it)->Save();
621 }
Paul Stewarta41e38d2011-11-11 07:47:29 -0800622
623 // In normal usage, running_ will always be true when we are here, however
624 // unit tests sometimes do things in otherwise invalid states.
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400625 if (running_ && (to_manage->enabled_persistent() ||
626 to_manage->IsUnderlyingDeviceEnabled()))
Eric Shienbrood9a245532012-03-07 14:20:39 -0500627 to_manage->SetEnabled(true);
Gaurav Shah435de2c2011-11-17 19:01:07 -0800628
Eric Shienbrood8839a892012-03-29 10:33:48 -0400629 EmitDeviceProperties();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700630}
631
mukesh agrawal5029c6c2011-08-25 11:12:40 -0700632void Manager::DeregisterDevice(const DeviceRefPtr &to_forget) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700633 SLOG(Manager, 2) << __func__ << "(" << to_forget->FriendlyName() << ")";
Chris Masonec1e50412011-06-07 13:04:53 -0700634 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700635 for (it = devices_.begin(); it != devices_.end(); ++it) {
Chris Masonec1e50412011-06-07 13:04:53 -0700636 if (to_forget.get() == it->get()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700637 SLOG(Manager, 2) << "Deregistered device: " << to_forget->UniqueName();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500638 to_forget->SetEnabled(false);
Chris Masone9be4a9d2011-05-16 15:44:09 -0700639 devices_.erase(it);
Eric Shienbrood8839a892012-03-29 10:33:48 -0400640 EmitDeviceProperties();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700641 return;
642 }
643 }
Ben Chanfad4a0b2012-04-18 15:49:59 -0700644 SLOG(Manager, 2) << __func__ << " unknown device: "
645 << to_forget->UniqueName();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700646}
647
Eric Shienbrood8839a892012-03-29 10:33:48 -0400648void Manager::EmitDeviceProperties() {
649 vector<DeviceRefPtr>::iterator it;
650 vector<string> device_paths;
651 for (it = devices_.begin(); it != devices_.end(); ++it) {
652 device_paths.push_back((*it)->GetRpcIdentifier());
653 }
654 adaptor_->EmitRpcIdentifierArrayChanged(flimflam::kDevicesProperty,
655 device_paths);
656 Error error;
657 adaptor_->EmitStringsChanged(flimflam::kAvailableTechnologiesProperty,
658 AvailableTechnologies(&error));
659 adaptor_->EmitStringsChanged(flimflam::kEnabledTechnologiesProperty,
660 EnabledTechnologies(&error));
661}
662
mukesh agrawal4eb4d782011-12-05 17:34:37 +0000663bool Manager::HasService(const ServiceRefPtr &service) {
664 vector<ServiceRefPtr>::iterator it;
665 for (it = services_.begin(); it != services_.end(); ++it) {
666 if ((*it)->UniqueName() == service->UniqueName())
667 return true;
668 }
669 return false;
670}
671
Chris Masone2b105542011-06-22 10:58:09 -0700672void Manager::RegisterService(const ServiceRefPtr &to_manage) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700673 SLOG(Manager, 2) << "In " << __func__ << "(): Registering service "
674 << to_manage->UniqueName();
mukesh agrawald835b202011-10-07 15:26:47 -0700675
Paul Stewart75225512012-01-26 22:51:33 -0800676 MatchProfileWithService(to_manage);
Chris Masone6791a432011-07-12 13:23:19 -0700677
678 // Now add to OUR list.
Chris Masonec1e50412011-06-07 13:04:53 -0700679 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700680 for (it = services_.begin(); it != services_.end(); ++it) {
mukesh agrawald835b202011-10-07 15:26:47 -0700681 CHECK(to_manage->UniqueName() != (*it)->UniqueName());
Chris Masone9be4a9d2011-05-16 15:44:09 -0700682 }
Chris Masonec1e50412011-06-07 13:04:53 -0700683 services_.push_back(to_manage);
Paul Stewart22aa71b2011-09-16 12:15:11 -0700684 SortServices();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700685}
686
Chris Masone6515aab2011-10-12 16:19:09 -0700687void Manager::DeregisterService(const ServiceRefPtr &to_forget) {
Chris Masonec1e50412011-06-07 13:04:53 -0700688 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700689 for (it = services_.begin(); it != services_.end(); ++it) {
Chris Masone6791a432011-07-12 13:23:19 -0700690 if (to_forget->UniqueName() == (*it)->UniqueName()) {
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800691 DCHECK(!(*it)->connection());
Chris Masone9be4a9d2011-05-16 15:44:09 -0700692 services_.erase(it);
Paul Stewart22aa71b2011-09-16 12:15:11 -0700693 SortServices();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700694 return;
695 }
696 }
697}
698
Paul Stewart65512e12012-03-26 18:01:08 -0700699bool Manager::UnloadService(vector<ServiceRefPtr>::iterator *service_iterator) {
700 if (!(**service_iterator)->Unload()) {
701 return false;
702 }
703
704 DCHECK(!(**service_iterator)->connection());
705 *service_iterator = services_.erase(*service_iterator);
706
707 return true;
708}
709
mukesh agrawal00917ce2011-11-22 23:56:55 +0000710void Manager::UpdateService(const ServiceRefPtr &to_update) {
711 CHECK(to_update);
Paul Stewart03dba0b2011-08-22 16:32:45 -0700712 LOG(INFO) << "Service " << to_update->UniqueName() << " updated;"
Gaurav Shahc6d6c722011-11-17 18:59:39 -0800713 << " state: " << Service::ConnectStateToString(to_update->state())
714 << " failure: "
715 << Service::ConnectFailureToString(to_update->failure());
Ben Chanfad4a0b2012-04-18 15:49:59 -0700716 SLOG(Manager, 2) << "IsConnected(): " << to_update->IsConnected();
717 SLOG(Manager, 2) << "IsConnecting(): " << to_update->IsConnecting();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800718 if (to_update->IsConnected()) {
Thieu Led4e9e552012-02-16 16:26:07 -0800719 bool originally_favorite = to_update->favorite();
mukesh agrawal00917ce2011-11-22 23:56:55 +0000720 to_update->MakeFavorite();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800721 if (to_update->profile().get() == ephemeral_profile_.get()) {
722 if (profiles_.empty()) {
723 LOG(ERROR) << "Cannot assign profile to service: no profiles exist!";
724 } else {
725 MoveServiceToProfile(to_update, profiles_.back());
726 }
Thieu Led4e9e552012-02-16 16:26:07 -0800727 } else if (!originally_favorite) {
728 // Persists the updated favorite setting in the profile.
729 to_update->SaveToCurrentProfile();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800730 }
731 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700732 SortServices();
Paul Stewart03dba0b2011-08-22 16:32:45 -0700733}
734
Paul Stewartfdd16072011-09-16 12:41:35 -0700735void Manager::FilterByTechnology(Technology::Identifier tech,
Chris Masonec1e50412011-06-07 13:04:53 -0700736 vector<DeviceRefPtr> *found) {
Chris Masone9be4a9d2011-05-16 15:44:09 -0700737 CHECK(found);
Chris Masonec1e50412011-06-07 13:04:53 -0700738 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700739 for (it = devices_.begin(); it != devices_.end(); ++it) {
740 if ((*it)->TechnologyIs(tech))
741 found->push_back(*it);
742 }
743}
744
Paul Stewart22aa71b2011-09-16 12:15:11 -0700745ServiceRefPtr Manager::FindService(const string& name) {
Chris Masonec1e50412011-06-07 13:04:53 -0700746 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700747 for (it = services_.begin(); it != services_.end(); ++it) {
Chris Masone6791a432011-07-12 13:23:19 -0700748 if (name == (*it)->UniqueName())
Chris Masonee0dea762011-06-09 09:06:03 -0700749 return *it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700750 }
Chris Masonee0dea762011-06-09 09:06:03 -0700751 return NULL;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700752}
753
mukesh agrawal2366eed2012-03-20 18:21:50 -0700754void Manager::HelpRegisterConstDerivedRpcIdentifiers(
755 const string &name,
756 RpcIdentifiers(Manager::*get)(Error *)) {
757 store_.RegisterDerivedRpcIdentifiers(
758 name,
759 RpcIdentifiersAccessor(
760 new CustomAccessor<Manager, RpcIdentifiers>(this, get, NULL)));
761}
762
mukesh agrawalffa3d042011-10-06 15:26:10 -0700763void Manager::HelpRegisterDerivedString(
764 const string &name,
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800765 string(Manager::*get)(Error *),
mukesh agrawalffa3d042011-10-06 15:26:10 -0700766 void(Manager::*set)(const string&, Error *)) {
Chris Masone27c4aa52011-07-02 13:10:14 -0700767 store_.RegisterDerivedString(
768 name,
769 StringAccessor(new CustomAccessor<Manager, string>(this, get, set)));
Chris Masoneb925cc82011-06-22 15:39:57 -0700770}
771
mukesh agrawalffa3d042011-10-06 15:26:10 -0700772void Manager::HelpRegisterDerivedStrings(
773 const string &name,
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800774 Strings(Manager::*get)(Error *),
mukesh agrawalffa3d042011-10-06 15:26:10 -0700775 void(Manager::*set)(const Strings &, Error *)) {
Chris Masone27c4aa52011-07-02 13:10:14 -0700776 store_.RegisterDerivedStrings(
777 name,
778 StringsAccessor(new CustomAccessor<Manager, Strings>(this, get, set)));
Chris Masoneb925cc82011-06-22 15:39:57 -0700779}
780
Paul Stewart22aa71b2011-09-16 12:15:11 -0700781void Manager::SortServices() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700782 SLOG(Manager, 4) << "In " << __func__;
Thieu Lea20cbc22012-01-09 22:01:43 +0000783 ServiceRefPtr default_service;
784
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800785 if (!services_.empty()) {
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700786 // Keep track of the service that is the candidate for the default
787 // service. We have not yet tested to see if this service has a
788 // connection.
Thieu Lea20cbc22012-01-09 22:01:43 +0000789 default_service = services_[0];
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800790 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700791 sort(services_.begin(), services_.end(), ServiceSorter(technology_order_));
Paul Stewarta41e38d2011-11-11 07:47:29 -0800792
793 vector<string> service_paths;
794 vector<ServiceRefPtr>::iterator it;
795 for (it = services_.begin(); it != services_.end(); ++it) {
796 if ((*it)->IsVisible()) {
797 service_paths.push_back((*it)->GetRpcIdentifier());
798 }
799 }
800 adaptor_->EmitRpcIdentifierArrayChanged(flimflam::kServicesProperty,
801 service_paths);
Gaurav Shah435de2c2011-11-17 19:01:07 -0800802
803 Error error;
804 adaptor_->EmitStringsChanged(flimflam::kConnectedTechnologiesProperty,
805 ConnectedTechnologies(&error));
806 adaptor_->EmitStringChanged(flimflam::kDefaultTechnologyProperty,
807 DefaultTechnology(&error));
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800808
809 if (!services_.empty()) {
Thieu Lea20cbc22012-01-09 22:01:43 +0000810 ConnectionRefPtr default_connection = default_service->connection();
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800811 if (default_connection.get() &&
812 (services_[0]->connection().get() != default_connection.get())) {
813 default_connection->SetIsDefault(false);
814 }
815 if (services_[0]->connection().get()) {
816 services_[0]->connection()->SetIsDefault(true);
Thieu Lea20cbc22012-01-09 22:01:43 +0000817 default_service = services_[0];
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700818 } else {
819 default_service = NULL;
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800820 }
821 }
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700822 metrics_->NotifyDefaultServiceChanged(default_service);
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800823
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000824 AutoConnect();
825}
826
Paul Stewart75225512012-01-26 22:51:33 -0800827bool Manager::MatchProfileWithService(const ServiceRefPtr &service) {
828 vector<ProfileRefPtr>::reverse_iterator it;
829 for (it = profiles_.rbegin(); it != profiles_.rend(); ++it) {
830 if ((*it)->ConfigureService(service)) {
831 break;
832 }
833 }
834 if (it == profiles_.rend()) {
835 ephemeral_profile_->AdoptService(service);
836 return false;
837 }
838 return true;
839}
840
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000841void Manager::AutoConnect() {
842 // We might be called in the middle of another request (e.g., as a
843 // consequence of Service::SetState calling UpdateService). To avoid
844 // re-entrancy issues in dbus-c++, defer to the event loop.
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500845 dispatcher_->PostTask(Bind(&Manager::AutoConnectTask, AsWeakPtr()));
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000846}
847
848void Manager::AutoConnectTask() {
849 if (services_.empty()) {
850 LOG(INFO) << "No services.";
851 return;
852 }
853
Ben Chanfad4a0b2012-04-18 15:49:59 -0700854 if (SLOG_IS_ON(Manager, 4)) {
855 SLOG(Manager, 4) << "Sorted service list: ";
mukesh agrawalddc378f2012-02-17 18:26:20 -0800856 for (size_t i = 0; i < services_.size(); ++i) {
857 ServiceRefPtr service = services_[i];
858 const char *compare_reason = NULL;
859 if (i + 1 < services_.size()) {
860 Service::Compare(
861 service, services_[i+1], technology_order_, &compare_reason);
862 } else {
mukesh agrawalbf14e942012-03-02 14:36:34 -0800863 compare_reason = "last";
mukesh agrawalddc378f2012-02-17 18:26:20 -0800864 }
Ben Chanfad4a0b2012-04-18 15:49:59 -0700865 SLOG(Manager, 4) << "Service " << service->friendly_name()
866 << " IsConnected: " << service->IsConnected()
867 << " IsConnecting: " << service->IsConnecting()
868 << " IsFailed: " << service->IsFailed()
869 << " connectable: " << service->connectable()
870 << " auto_connect: " << service->auto_connect()
871 << " favorite: " << service->favorite()
872 << " priority: " << service->priority()
873 << " security_level: " << service->security_level()
874 << " strength: " << service->strength()
875 << " UniqueName: " << service->UniqueName()
876 << " sorted: " << compare_reason;
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000877 }
878 }
879
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800880 // Perform auto-connect.
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000881 for (vector<ServiceRefPtr>::iterator it = services_.begin();
882 it != services_.end(); ++it) {
883 if ((*it)->auto_connect()) {
mukesh agrawal592516d2012-01-12 14:01:00 -0800884 LOG(INFO) << "Requesting autoconnect to service "
885 << (*it)->friendly_name() << ".";
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000886 (*it)->AutoConnect();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800887 }
888 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700889}
890
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800891string Manager::CalculateState(Error */*error*/) {
Gary Morain028545d2012-04-07 14:55:52 -0700892 // |services_| is sorted such that connected services are first.
893 if (!services_.empty() &&
894 services_.front()->IsConnected()) {
895 return flimflam::kStateOnline;
896 }
Chris Masoneb925cc82011-06-22 15:39:57 -0700897 return flimflam::kStateOffline;
898}
899
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800900vector<string> Manager::AvailableTechnologies(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -0800901 set<string> unique_technologies;
902 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
903 it != devices_.end(); ++it) {
904 unique_technologies.insert(
905 Technology::NameFromIdentifier((*it)->technology()));
906 }
907 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -0700908}
909
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800910vector<string> Manager::ConnectedTechnologies(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -0800911 set<string> unique_technologies;
912 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
913 it != devices_.end(); ++it) {
914 if ((*it)->IsConnected())
915 unique_technologies.insert(
916 Technology::NameFromIdentifier((*it)->technology()));
917 }
918 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -0700919}
920
Gaurav Shah435de2c2011-11-17 19:01:07 -0800921string Manager::DefaultTechnology(Error *error) {
922 return (!services_.empty() && services_[0]->IsConnected()) ?
923 services_[0]->GetTechnologyString(error) : "";
Chris Masoneb925cc82011-06-22 15:39:57 -0700924}
925
Eric Shienbrood9a245532012-03-07 14:20:39 -0500926vector<string> Manager::EnabledTechnologies(Error */*error*/) {
927 set<string> unique_technologies;
928 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
929 it != devices_.end(); ++it) {
930 if ((*it)->enabled())
931 unique_technologies.insert(
932 Technology::NameFromIdentifier((*it)->technology()));
933 }
934 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -0700935}
936
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800937vector<string> Manager::EnumerateDevices(Error */*error*/) {
Chris Masone3c3f6a12011-07-01 10:01:41 -0700938 vector<string> device_rpc_ids;
939 for (vector<DeviceRefPtr>::const_iterator it = devices_.begin();
940 it != devices_.end();
941 ++it) {
942 device_rpc_ids.push_back((*it)->GetRpcIdentifier());
943 }
944 return device_rpc_ids;
945}
946
Paul Stewart1b253142012-01-26 14:05:52 -0800947vector<string> Manager::EnumerateProfiles(Error */*error*/) {
948 vector<string> profile_rpc_ids;
949 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
950 it != profiles_.end();
951 ++it) {
952 profile_rpc_ids.push_back((*it)->GetRpcIdentifier());
953 }
954 return profile_rpc_ids;
955}
956
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800957vector<string> Manager::EnumerateAvailableServices(Error */*error*/) {
Chris Masone3c3f6a12011-07-01 10:01:41 -0700958 vector<string> service_rpc_ids;
959 for (vector<ServiceRefPtr>::const_iterator it = services_.begin();
960 it != services_.end();
961 ++it) {
962 service_rpc_ids.push_back((*it)->GetRpcIdentifier());
963 }
964 return service_rpc_ids;
965}
966
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800967vector<string> Manager::EnumerateWatchedServices(Error *error) {
Chris Masone6791a432011-07-12 13:23:19 -0700968 // TODO(cmasone): Filter this list for services in appropriate states.
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800969 return EnumerateAvailableServices(error);
Chris Masone3c3f6a12011-07-01 10:01:41 -0700970}
971
Paul Stewart1b253142012-01-26 14:05:52 -0800972string Manager::GetActiveProfileRpcIdentifier(Error */*error*/) {
973 return ActiveProfile()->GetRpcIdentifier();
Chris Masone7aa5f902011-07-11 11:13:35 -0700974}
975
mukesh agrawal32399322011-09-01 10:53:43 -0700976// called via RPC (e.g., from ManagerDBusAdaptor)
Darin Petkovb65c2452012-02-23 15:17:06 +0100977ServiceRefPtr Manager::GetService(const KeyValueStore &args, Error *error) {
Paul Stewart13ed2252012-03-21 12:52:46 -0700978 if (args.ContainsString(flimflam::kGuidProperty)) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700979 SLOG(Manager, 2) << __func__ << ": searching by GUID";
Paul Stewart13ed2252012-03-21 12:52:46 -0700980 ServiceRefPtr service =
981 GetServiceWithGUID(args.GetString(flimflam::kGuidProperty), NULL);
982 if (service) {
Paul Stewartcb59fed2012-03-21 21:14:46 -0700983 service->Configure(args, error);
Paul Stewart13ed2252012-03-21 12:52:46 -0700984 return service;
985 }
986 }
987
Darin Petkovb65c2452012-02-23 15:17:06 +0100988 if (!args.ContainsString(flimflam::kTypeProperty)) {
Paul Stewart7f61e522012-03-22 11:13:45 -0700989 Error::PopulateAndLog(error, Error::kInvalidArguments, kErrorTypeRequired);
Darin Petkovb65c2452012-02-23 15:17:06 +0100990 return NULL;
991 }
992
993 string type = args.GetString(flimflam::kTypeProperty);
994 if (type == flimflam::kTypeWifi) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700995 SLOG(Manager, 2) << __func__ << ": getting WiFi Service";
Darin Petkovb65c2452012-02-23 15:17:06 +0100996 return GetWifiService(args, error);
997 }
998 if (type == flimflam::kTypeVPN) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700999 SLOG(Manager, 2) << __func__ << ": getting VPN Service";
Darin Petkov33af05c2012-02-28 10:10:30 +01001000 return vpn_provider_.GetService(args, error);
Darin Petkovb65c2452012-02-23 15:17:06 +01001001 }
1002 error->Populate(Error::kNotSupported, kErrorUnsupportedServiceType);
1003 return NULL;
1004}
1005
mukesh agrawal7a4e4002011-09-06 11:26:05 -07001006WiFiServiceRefPtr Manager::GetWifiService(const KeyValueStore &args,
1007 Error *error) {
Paul Stewarta41e38d2011-11-11 07:47:29 -08001008 vector<DeviceRefPtr> wifi_devices;
Paul Stewart22aa71b2011-09-16 12:15:11 -07001009 FilterByTechnology(Technology::kWifi, &wifi_devices);
mukesh agrawal7a4e4002011-09-06 11:26:05 -07001010 if (wifi_devices.empty()) {
Darin Petkovb65c2452012-02-23 15:17:06 +01001011 error->Populate(Error::kInvalidArguments, kErrorNoDevice);
mukesh agrawal7a4e4002011-09-06 11:26:05 -07001012 return NULL;
1013 } else {
1014 WiFi *wifi = dynamic_cast<WiFi *>(wifi_devices.front().get());
1015 CHECK(wifi);
1016 return wifi->GetService(args, error);
1017 }
1018}
1019
Paul Stewart7f61e522012-03-22 11:13:45 -07001020// called via RPC (e.g., from ManagerDBusAdaptor)
1021void Manager::ConfigureService(const KeyValueStore &args, Error *error) {
1022 ProfileRefPtr profile = ActiveProfile();
1023 bool profile_specified = args.ContainsString(flimflam::kProfileProperty);
1024 if (profile_specified) {
1025 string profile_rpcid = args.GetString(flimflam::kProfileProperty);
1026 profile = LookupProfileByRpcIdentifier(profile_rpcid);
1027 if (!profile) {
1028 Error::PopulateAndLog(error, Error::kInvalidArguments,
1029 "Invalid profile name " + profile_rpcid);
1030 return;
1031 }
1032 }
1033
1034 ServiceRefPtr service = GetService(args, error);
1035 if (error->IsFailure() || !service) {
1036 LOG(ERROR) << "GetService failed; returning upstream error.";
1037 return;
1038 }
1039
1040 // Overwrte the profile data with the resulting configured service.
1041 if (!profile->UpdateService(service)) {
1042 Error::PopulateAndLog(error, Error::kInternalError,
1043 "Unable to save service to profile");
1044 return;
1045 }
1046
1047 if (HasService(service)) {
1048 // If the service has been registered (it may not be -- as is the case
1049 // with invisible WiFi networks), we can now transfer the service between
1050 // profiles.
1051 if (service->profile() == ephemeral_profile_ ||
1052 (profile_specified && service->profile() != profile)) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001053 SLOG(Manager, 2) << "Moving service to profile "
1054 << profile->GetFriendlyName();
Paul Stewart7f61e522012-03-22 11:13:45 -07001055 if (!MoveServiceToProfile(service, profile)) {
1056 Error::PopulateAndLog(error, Error::kInternalError,
1057 "Unable to move service to profile");
1058 }
1059 }
1060 }
1061}
1062
Paul Stewartc681fa02012-03-02 19:40:04 -08001063void Manager::RecheckPortal(Error */*error*/) {
1064 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1065 it != devices_.end(); ++it) {
1066 if ((*it)->RequestPortalDetection()) {
1067 // Only start Portal Detection on the device with the default connection.
1068 // We will get a "true" return value when we've found that device, and
1069 // can end our loop early as a result.
1070 break;
1071 }
1072 }
1073}
1074
mukesh agrawal7a4e4002011-09-06 11:26:05 -07001075// called via RPC (e.g., from ManagerDBusAdaptor)
Paul Stewart22aa71b2011-09-16 12:15:11 -07001076void Manager::RequestScan(const string &technology, Error *error) {
mukesh agrawal32399322011-09-01 10:53:43 -07001077 if (technology == flimflam::kTypeWifi || technology == "") {
1078 vector<DeviceRefPtr> wifi_devices;
Paul Stewartfdd16072011-09-16 12:41:35 -07001079 FilterByTechnology(Technology::kWifi, &wifi_devices);
mukesh agrawal32399322011-09-01 10:53:43 -07001080
1081 for (vector<DeviceRefPtr>::iterator it = wifi_devices.begin();
1082 it != wifi_devices.end();
1083 ++it) {
Darin Petkovc0865312011-09-16 15:31:20 -07001084 (*it)->Scan(error);
mukesh agrawal32399322011-09-01 10:53:43 -07001085 }
1086 } else {
1087 // TODO(quiche): support scanning for other technologies?
Paul Stewartbe005172011-11-02 18:10:29 -07001088 Error::PopulateAndLog(error, Error::kInvalidArguments,
1089 "Unrecognized technology " + technology);
mukesh agrawal32399322011-09-01 10:53:43 -07001090 }
1091}
1092
Paul Stewart22aa71b2011-09-16 12:15:11 -07001093string Manager::GetTechnologyOrder() {
1094 vector<string> technology_names;
1095 for (vector<Technology::Identifier>::iterator it = technology_order_.begin();
1096 it != technology_order_.end();
1097 ++it) {
1098 technology_names.push_back(Technology::NameFromIdentifier(*it));
1099 }
1100
1101 return JoinString(technology_names, ',');
1102}
1103
1104void Manager::SetTechnologyOrder(const string &order, Error *error) {
1105 vector<Technology::Identifier> new_order;
Ben Chanfad4a0b2012-04-18 15:49:59 -07001106 SLOG(Manager, 2) << "Setting technology order to " << order;
Paul Stewart20088d82012-02-16 06:58:55 -08001107 if (!Technology::GetTechnologyVectorFromString(order, &new_order, error)) {
1108 return;
Paul Stewart22aa71b2011-09-16 12:15:11 -07001109 }
1110
1111 technology_order_ = new_order;
1112 SortServices();
1113}
1114
Paul Stewart75897df2011-04-27 09:05:53 -07001115} // namespace shill