blob: c1eb35f0b4c375785d33615466ad8d6b754d7487 [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>
Jason Glasgowdf7c5532012-05-14 14:41:45 -040011#include <set>
Paul Stewart75897df2011-04-27 09:05:53 -070012#include <string>
Chris Masone52cd19b2011-06-29 17:23:04 -070013#include <vector>
Paul Stewart75897df2011-04-27 09:05:53 -070014
Eric Shienbrood3e20a232012-02-16 11:35:56 -050015#include <base/bind.h>
Paul Stewarte6132022011-08-16 09:11:02 -070016#include <base/file_util.h>
Chris Masoneee929b72011-05-10 10:02:18 -070017#include <base/logging.h>
Chris Masone9be4a9d2011-05-16 15:44:09 -070018#include <base/memory/ref_counted.h>
Eric Shienbrood3e20a232012-02-16 11:35:56 -050019#include <base/stringprintf.h>
Paul Stewart22aa71b2011-09-16 12:15:11 -070020#include <base/string_util.h>
Chris Masone3bd3c8c2011-06-13 08:20:26 -070021#include <chromeos/dbus/service_constants.h>
Chris Masoneee929b72011-05-10 10:02:18 -070022
Chris Masoned0ceb8c2011-06-02 10:05:39 -070023#include "shill/adaptor_interfaces.h"
Paul Stewartc1dec4d2011-12-08 15:25:28 -080024#include "shill/connection.h"
Paul Stewart75897df2011-04-27 09:05:53 -070025#include "shill/control_interface.h"
Chris Masoned0ceb8c2011-06-02 10:05:39 -070026#include "shill/dbus_adaptor.h"
Chris Masone7aa5f902011-07-11 11:13:35 -070027#include "shill/default_profile.h"
Chris Masone9be4a9d2011-05-16 15:44:09 -070028#include "shill/device.h"
29#include "shill/device_info.h"
Chris Masone6791a432011-07-12 13:23:19 -070030#include "shill/ephemeral_profile.h"
Chris Masone8fe2c7e2011-06-09 15:51:19 -070031#include "shill/error.h"
Paul Stewart26b327e2011-10-19 11:38:09 -070032#include "shill/event_dispatcher.h"
Gary Moraina9fb3252012-05-31 12:05:31 -070033#include "shill/hook_table.h"
Chris Masone9d779932011-08-25 16:33:41 -070034#include "shill/key_file_store.h"
Thieu Lea20cbc22012-01-09 22:01:43 +000035#include "shill/metrics.h"
Chris Masone7aa5f902011-07-11 11:13:35 -070036#include "shill/profile.h"
Chris Masoneb925cc82011-06-22 15:39:57 -070037#include "shill/property_accessor.h"
Gary Morainac1bdb42012-02-16 17:42:29 -080038#include "shill/proxy_factory.h"
Paul Stewarte6132022011-08-16 09:11:02 -070039#include "shill/resolver.h"
Ben Chanfad4a0b2012-04-18 15:49:59 -070040#include "shill/scope_logger.h"
Chris Masone9be4a9d2011-05-16 15:44:09 -070041#include "shill/service.h"
Thieu Lea20cbc22012-01-09 22:01:43 +000042#include "shill/service_sorter.h"
Darin Petkov33af05c2012-02-28 10:10:30 +010043#include "shill/vpn_service.h"
mukesh agrawal7a4e4002011-09-06 11:26:05 -070044#include "shill/wifi.h"
45#include "shill/wifi_service.h"
Darin Petkovd1cd7972012-05-22 15:26:15 +020046#include "shill/wimax_service.h"
Paul Stewart75897df2011-04-27 09:05:53 -070047
Eric Shienbrood3e20a232012-02-16 11:35:56 -050048using base::Bind;
49using base::StringPrintf;
50using base::Unretained;
Gaurav Shah435de2c2011-11-17 19:01:07 -080051using std::set;
Paul Stewart75897df2011-04-27 09:05:53 -070052using std::string;
Chris Masone9be4a9d2011-05-16 15:44:09 -070053using std::vector;
Paul Stewart75897df2011-04-27 09:05:53 -070054
55namespace shill {
Paul Stewarte6132022011-08-16 09:11:02 -070056
Darin Petkovb65c2452012-02-23 15:17:06 +010057// statics
58const char Manager::kErrorNoDevice[] = "no wifi devices available";
59const char Manager::kErrorTypeRequired[] = "must specify service type";
60const char Manager::kErrorUnsupportedServiceType[] =
61 "service type is unsupported";
mukesh agrawal7a4e4002011-09-06 11:26:05 -070062
Paul Stewart75897df2011-04-27 09:05:53 -070063Manager::Manager(ControlInterface *control_interface,
Darin Petkov887f2982011-07-14 16:10:17 -070064 EventDispatcher *dispatcher,
Thieu Le3426c8f2012-01-11 17:35:11 -080065 Metrics *metrics,
Chris Masone2ae797d2011-08-23 20:41:00 -070066 GLib *glib,
67 const string &run_directory,
68 const string &storage_directory,
69 const string &user_storage_format)
mukesh agrawal8a3188d2011-12-01 20:56:44 +000070 : dispatcher_(dispatcher),
mukesh agrawal8a3188d2011-12-01 20:56:44 +000071 run_path_(FilePath(run_directory)),
72 storage_path_(FilePath(storage_directory)),
73 user_storage_format_(user_storage_format),
74 adaptor_(control_interface->CreateManagerAdaptor(this)),
Thieu Le3426c8f2012-01-11 17:35:11 -080075 device_info_(control_interface, dispatcher, metrics, this),
76 modem_info_(control_interface, dispatcher, metrics, this, glib),
Darin Petkov33af05c2012-02-28 10:10:30 +010077 vpn_provider_(control_interface, dispatcher, metrics, this),
Darin Petkovb72b62e2012-05-15 16:55:36 +020078 wimax_provider_(control_interface, dispatcher, metrics, this),
mukesh agrawal8a3188d2011-12-01 20:56:44 +000079 running_(false),
80 connect_profiles_to_rpc_(true),
81 ephemeral_profile_(new EphemeralProfile(control_interface, this)),
82 control_interface_(control_interface),
Thieu Le3426c8f2012-01-11 17:35:11 -080083 metrics_(metrics),
Paul Stewart10e9e4e2012-04-26 19:46:28 -070084 glib_(glib),
Gary Moraina9fb3252012-05-31 12:05:31 -070085 use_startup_portal_list_(false),
86 termination_actions_(dispatcher) {
Chris Masone7aa5f902011-07-11 11:13:35 -070087 HelpRegisterDerivedString(flimflam::kActiveProfileProperty,
Paul Stewart1b253142012-01-26 14:05:52 -080088 &Manager::GetActiveProfileRpcIdentifier,
Chris Masone7aa5f902011-07-11 11:13:35 -070089 NULL);
Paul Stewartd408fdf2012-05-07 17:15:57 -070090 store_.RegisterBool(flimflam::kArpGatewayProperty, &props_.arp_gateway);
Chris Masone27c4aa52011-07-02 13:10:14 -070091 HelpRegisterDerivedStrings(flimflam::kAvailableTechnologiesProperty,
92 &Manager::AvailableTechnologies,
93 NULL);
Paul Stewart10e9e4e2012-04-26 19:46:28 -070094 HelpRegisterDerivedString(flimflam::kCheckPortalListProperty,
95 &Manager::GetCheckPortalList,
96 &Manager::SetCheckPortalList);
Chris Masone27c4aa52011-07-02 13:10:14 -070097 HelpRegisterDerivedStrings(flimflam::kConnectedTechnologiesProperty,
98 &Manager::ConnectedTechnologies,
99 NULL);
Chris Masone88cbd5f2011-07-03 14:30:04 -0700100 store_.RegisterString(flimflam::kCountryProperty, &props_.country);
Chris Masone27c4aa52011-07-02 13:10:14 -0700101 HelpRegisterDerivedString(flimflam::kDefaultTechnologyProperty,
102 &Manager::DefaultTechnology,
103 NULL);
Chris Masone27c4aa52011-07-02 13:10:14 -0700104 HelpRegisterDerivedStrings(flimflam::kDevicesProperty,
105 &Manager::EnumerateDevices,
106 NULL);
Chris Masone88cbd5f2011-07-03 14:30:04 -0700107 HelpRegisterDerivedStrings(flimflam::kEnabledTechnologiesProperty,
108 &Manager::EnabledTechnologies,
109 NULL);
110 store_.RegisterBool(flimflam::kOfflineModeProperty, &props_.offline_mode);
111 store_.RegisterString(flimflam::kPortalURLProperty, &props_.portal_url);
Paul Stewartc681fa02012-03-02 19:40:04 -0800112 store_.RegisterInt32(kPortalCheckIntervalProperty,
113 &props_.portal_check_interval_seconds);
Paul Stewart1b253142012-01-26 14:05:52 -0800114 HelpRegisterDerivedStrings(flimflam::kProfilesProperty,
115 &Manager::EnumerateProfiles,
116 NULL);
Paul Stewartc681fa02012-03-02 19:40:04 -0800117 store_.RegisterString(kHostNameProperty, &props_.host_name);
Chris Masone88cbd5f2011-07-03 14:30:04 -0700118 HelpRegisterDerivedString(flimflam::kStateProperty,
119 &Manager::CalculateState,
120 NULL);
mukesh agrawal2366eed2012-03-20 18:21:50 -0700121 HelpRegisterConstDerivedRpcIdentifiers(flimflam::kServicesProperty,
122 &Manager::EnumerateAvailableServices);
Chris Masone27c4aa52011-07-02 13:10:14 -0700123 HelpRegisterDerivedStrings(flimflam::kServiceWatchListProperty,
124 &Manager::EnumerateWatchedServices,
125 NULL);
Chris Masone3c3f6a12011-07-01 10:01:41 -0700126
mukesh agrawal84de5d22012-02-17 19:29:15 -0800127 // Set default technology order "by hand", to avoid invoking side
128 // effects of SetTechnologyOrder.
129 technology_order_.push_back(
Darin Petkov2f903b32012-04-18 12:56:43 +0200130 Technology::IdentifierFromName(flimflam::kTypeVPN));
131 technology_order_.push_back(
mukesh agrawal84de5d22012-02-17 19:29:15 -0800132 Technology::IdentifierFromName(flimflam::kTypeEthernet));
133 technology_order_.push_back(
Darin Petkove08d9192012-05-21 12:21:15 +0200134 Technology::IdentifierFromName(flimflam::kTypeWimax));
135 technology_order_.push_back(
mukesh agrawal84de5d22012-02-17 19:29:15 -0800136 Technology::IdentifierFromName(flimflam::kTypeWifi));
137 technology_order_.push_back(
138 Technology::IdentifierFromName(flimflam::kTypeCellular));
139
Ben Chanfad4a0b2012-04-18 15:49:59 -0700140 SLOG(Manager, 2) << "Manager initialized.";
Paul Stewart75897df2011-04-27 09:05:53 -0700141}
142
Chris Masone6791a432011-07-12 13:23:19 -0700143Manager::~Manager() {
Chris Masone9d779932011-08-25 16:33:41 -0700144 profiles_.clear();
Chris Masone6791a432011-07-12 13:23:19 -0700145}
Paul Stewart75897df2011-04-27 09:05:53 -0700146
mukesh agrawal8f317b62011-07-15 11:53:23 -0700147void Manager::AddDeviceToBlackList(const string &device_name) {
148 device_info_.AddDeviceToBlackList(device_name);
149}
150
Paul Stewart75897df2011-04-27 09:05:53 -0700151void Manager::Start() {
Paul Stewart0af98bf2011-05-10 17:38:08 -0700152 LOG(INFO) << "Manager started.";
Paul Stewarte6132022011-08-16 09:11:02 -0700153
Gary Morainac1bdb42012-02-16 17:42:29 -0800154 power_manager_.reset(new PowerManager(ProxyFactory::GetInstance()));
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500155 // TODO(ers): weak ptr for metrics_?
156 PowerManager::PowerStateCallback cb =
157 Bind(&Metrics::NotifyPowerStateChange, Unretained(metrics_));
Thieu Leb84ba342012-03-02 15:15:19 -0800158 power_manager_->AddStateChangeCallback(Metrics::kMetricPowerManagerKey, cb);
159
Chris Masone2ae797d2011-08-23 20:41:00 -0700160 CHECK(file_util::CreateDirectory(run_path_)) << run_path_.value();
Paul Stewarte6132022011-08-16 09:11:02 -0700161 Resolver::GetInstance()->set_path(run_path_.Append("resolv.conf"));
Chris Masone2ae797d2011-08-23 20:41:00 -0700162
Gaurav Shah71354762011-11-28 19:22:49 -0800163 InitializeProfiles();
Paul Stewart75897df2011-04-27 09:05:53 -0700164 running_ = true;
Chris Masone413a3192011-05-09 17:10:05 -0700165 adaptor_->UpdateRunning();
Paul Stewart0af98bf2011-05-10 17:38:08 -0700166 device_info_.Start();
Darin Petkov887f2982011-07-14 16:10:17 -0700167 modem_info_.Start();
Darin Petkov33af05c2012-02-28 10:10:30 +0100168 vpn_provider_.Start();
Darin Petkov9893d9c2012-05-17 15:27:31 -0700169 wimax_provider_.Start();
Paul Stewart75897df2011-04-27 09:05:53 -0700170}
171
172void Manager::Stop() {
173 running_ = false;
Chris Masone9d779932011-08-25 16:33:41 -0700174 // Persist profile, device, service information to disk.
175 vector<ProfileRefPtr>::iterator it;
176 for (it = profiles_.begin(); it != profiles_.end(); ++it) {
Paul Stewartd0a3b812012-03-28 22:48:22 -0700177 // Since this happens in a loop, the current manager state is stored to
178 // all default profiles in the stack. This is acceptable because the
179 // only time multiple default profiles are loaded are during autotests.
Chris Masone6515aab2011-10-12 16:19:09 -0700180 (*it)->Save();
Chris Masone9d779932011-08-25 16:33:41 -0700181 }
Chris Masone9d779932011-08-25 16:33:41 -0700182
Thieu Le1271d682011-11-02 22:48:19 +0000183 vector<ServiceRefPtr>::iterator services_it;
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000184 Error e;
Thieu Le1271d682011-11-02 22:48:19 +0000185 for (services_it = services_.begin(); services_it != services_.end();
186 ++services_it) {
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000187 (*services_it)->Disconnect(&e);
Thieu Le1271d682011-11-02 22:48:19 +0000188 }
189
Chris Masone413a3192011-05-09 17:10:05 -0700190 adaptor_->UpdateRunning();
Darin Petkovb72b62e2012-05-15 16:55:36 +0200191 wimax_provider_.Stop();
Darin Petkov33af05c2012-02-28 10:10:30 +0100192 vpn_provider_.Stop();
Darin Petkov887f2982011-07-14 16:10:17 -0700193 modem_info_.Stop();
194 device_info_.Stop();
Thieu Leb84ba342012-03-02 15:15:19 -0800195
196 // Some unit tests do not call Manager::Start().
197 if (power_manager_.get())
198 power_manager_->RemoveStateChangeCallback(Metrics::kMetricPowerManagerKey);
Paul Stewart75897df2011-04-27 09:05:53 -0700199}
200
Gaurav Shah71354762011-11-28 19:22:49 -0800201void Manager::InitializeProfiles() {
202 DCHECK(profiles_.empty());
203 // The default profile must go first on the stack.
204 CHECK(file_util::CreateDirectory(storage_path_)) << storage_path_.value();
Paul Stewart870523b2012-01-11 17:00:42 -0800205 scoped_refptr<DefaultProfile>
206 default_profile(new DefaultProfile(control_interface_,
Gaurav Shah71354762011-11-28 19:22:49 -0800207 this,
208 storage_path_,
Paul Stewartd0a3b812012-03-28 22:48:22 -0700209 DefaultProfile::kDefaultId,
Gaurav Shah71354762011-11-28 19:22:49 -0800210 props_));
Paul Stewart870523b2012-01-11 17:00:42 -0800211 CHECK(default_profile->InitStorage(glib_, Profile::kCreateOrOpenExisting,
212 NULL));
213 CHECK(default_profile->LoadManagerProperties(&props_));
214 profiles_.push_back(default_profile.release());
Gaurav Shah71354762011-11-28 19:22:49 -0800215 Error error;
Paul Stewart19c871d2011-12-15 16:10:13 -0800216 string path;
Gaurav Shah71354762011-11-28 19:22:49 -0800217 for (vector<string>::iterator it = startup_profiles_.begin();
218 it != startup_profiles_.end(); ++it)
Paul Stewart19c871d2011-12-15 16:10:13 -0800219 PushProfile(*it, &path, &error);
Gaurav Shah71354762011-11-28 19:22:49 -0800220}
221
Paul Stewart19c871d2011-12-15 16:10:13 -0800222void Manager::CreateProfile(const string &name, string *path, Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700223 SLOG(Manager, 2) << __func__ << " " << name;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700224 Profile::Identifier ident;
225 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700226 Error::PopulateAndLog(error, Error::kInvalidArguments,
227 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700228 return;
229 }
Paul Stewartd0a3b812012-03-28 22:48:22 -0700230
231 ProfileRefPtr profile;
232 if (ident.user.empty()) {
233 profile = new DefaultProfile(control_interface_,
234 this,
235 storage_path_,
236 ident.identifier,
237 props_);
238 } else {
239 profile = new Profile(control_interface_,
240 this,
241 ident,
242 user_storage_format_,
Gary Morainb672d352012-04-25 09:19:06 -0700243 true);
Paul Stewartd0a3b812012-03-28 22:48:22 -0700244 }
245
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700246 if (!profile->InitStorage(glib_, Profile::kCreateNew, error)) {
Paul Stewart19c871d2011-12-15 16:10:13 -0800247 // |error| will have been populated by InitStorage().
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700248 return;
249 }
250
251 // Save profile data out, and then let the scoped pointer fall out of scope.
252 if (!profile->Save()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700253 Error::PopulateAndLog(error, Error::kInternalError,
254 "Profile name " + name + " could not be saved");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700255 return;
256 }
Paul Stewart19c871d2011-12-15 16:10:13 -0800257
258 *path = profile->GetRpcIdentifier();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700259}
260
Paul Stewart19c871d2011-12-15 16:10:13 -0800261void Manager::PushProfile(const string &name, string *path, Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700262 SLOG(Manager, 2) << __func__ << " " << name;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700263 Profile::Identifier ident;
264 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700265 Error::PopulateAndLog(error, Error::kInvalidArguments,
266 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700267 return;
268 }
269
270 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
271 it != profiles_.end();
272 ++it) {
273 if ((*it)->MatchesIdentifier(ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700274 Error::PopulateAndLog(error, Error::kAlreadyExists,
275 "Profile name " + name + " is already on stack");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700276 return;
277 }
278 }
279
Paul Stewartd0a3b812012-03-28 22:48:22 -0700280 ProfileRefPtr profile;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700281 if (ident.user.empty()) {
Paul Stewartd0a3b812012-03-28 22:48:22 -0700282 // Allow a machine-wide-profile to be pushed on the stack only if the
283 // profile stack is empty, or if the topmost profile on the stack is
284 // also a machine-wide (non-user) profile.
285 if (!profiles_.empty() && !profiles_.back()->GetUser().empty()) {
286 Error::PopulateAndLog(error, Error::kInvalidArguments,
287 "Cannot load non-default global profile " + name +
288 " on top of a user profile");
289 return;
290 }
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700291
Paul Stewartd0a3b812012-03-28 22:48:22 -0700292 scoped_refptr<DefaultProfile>
293 default_profile(new DefaultProfile(control_interface_,
294 this,
295 storage_path_,
296 ident.identifier,
297 props_));
298 if (!default_profile->InitStorage(glib_, Profile::kOpenExisting, error)) {
299 // |error| will have been populated by InitStorage().
300 return;
301 }
302
303 if (!default_profile->LoadManagerProperties(&props_)) {
304 Error::PopulateAndLog(error, Error::kInvalidArguments,
305 "Could not load Manager properties from profile " +
306 name);
307 return;
308 }
309 profile = default_profile;
310 } else {
311 profile = new Profile(control_interface_,
312 this,
313 ident,
314 user_storage_format_,
315 connect_profiles_to_rpc_);
316 if (!profile->InitStorage(glib_, Profile::kOpenExisting, error)) {
317 // |error| will have been populated by InitStorage().
318 return;
319 }
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700320 }
321
Paul Stewarta849a3d2011-11-03 05:54:09 -0700322 profiles_.push_back(profile);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700323
324 // Offer each registered Service the opportunity to join this new Profile.
Paul Stewarta41e38d2011-11-11 07:47:29 -0800325 for (vector<ServiceRefPtr>::iterator it = services_.begin();
326 it != services_.end(); ++it) {
Paul Stewartbba6a5b2011-11-02 18:45:59 -0700327 profile->ConfigureService(*it);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700328 }
329
Paul Stewarta41e38d2011-11-11 07:47:29 -0800330 // Shop the Profile contents around to Devices which can create
331 // non-visible services.
332 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
333 it != devices_.end(); ++it) {
334 profile->ConfigureDevice(*it);
335 }
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800336
Darin Petkovc63dcf02012-05-24 11:51:43 +0200337 // Offer the Profile contents to the service/device providers which will
338 // create new services if necessary.
Paul Stewart66815332012-04-09 18:09:36 -0700339 vpn_provider_.CreateServicesFromProfile(profile);
Darin Petkovc63dcf02012-05-24 11:51:43 +0200340 wimax_provider_.CreateServicesFromProfile(profile);
Paul Stewart66815332012-04-09 18:09:36 -0700341
Paul Stewart19c871d2011-12-15 16:10:13 -0800342 *path = profile->GetRpcIdentifier();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800343 SortServices();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700344}
345
346void Manager::PopProfileInternal() {
347 CHECK(!profiles_.empty());
348 ProfileRefPtr active_profile = profiles_.back();
349 profiles_.pop_back();
Paul Stewart75225512012-01-26 22:51:33 -0800350 vector<ServiceRefPtr>::iterator it;
Paul Stewart65512e12012-03-26 18:01:08 -0700351 for (it = services_.begin(); it != services_.end();) {
352 if ((*it)->profile().get() != active_profile.get() ||
353 MatchProfileWithService(*it) ||
354 !UnloadService(&it)) {
355 LOG(ERROR) << "Skipping unload of service";
356 ++it;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700357 }
358 }
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800359 SortServices();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700360}
361
Paul Stewarta41e38d2011-11-11 07:47:29 -0800362void Manager::PopProfile(const string &name, Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700363 SLOG(Manager, 2) << __func__ << " " << name;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700364 Profile::Identifier ident;
365 if (profiles_.empty()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700366 Error::PopulateAndLog(error, Error::kNotFound, "Profile stack is empty");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700367 return;
368 }
369 ProfileRefPtr active_profile = profiles_.back();
370 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700371 Error::PopulateAndLog(error, Error::kInvalidArguments,
372 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700373 return;
374 }
375 if (!active_profile->MatchesIdentifier(ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700376 Error::PopulateAndLog(error, Error::kNotSupported,
377 name + " is not the active profile");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700378 return;
379 }
380 PopProfileInternal();
381}
382
383void Manager::PopAnyProfile(Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700384 SLOG(Manager, 2) << __func__;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700385 Profile::Identifier ident;
386 if (profiles_.empty()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700387 Error::PopulateAndLog(error, Error::kNotFound, "Profile stack is empty");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700388 return;
389 }
390 PopProfileInternal();
391}
392
Paul Stewarte73d05c2012-03-29 16:26:05 -0700393void Manager::RemoveProfile(const string &name, Error *error) {
394 Profile::Identifier ident;
395 if (!Profile::ParseIdentifier(name, &ident)) {
396 Error::PopulateAndLog(error, Error::kInvalidArguments,
397 "Invalid profile name " + name);
398 return;
399 }
400
401 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
402 it != profiles_.end();
403 ++it) {
404 if ((*it)->MatchesIdentifier(ident)) {
405 Error::PopulateAndLog(error, Error::kInvalidArguments,
406 "Cannot remove profile name " + name +
407 " since it is on stack");
408 return;
409 }
410 }
411
412 ProfileRefPtr profile;
413 if (ident.user.empty()) {
414 profile = new DefaultProfile(control_interface_,
415 this,
416 storage_path_,
417 ident.identifier,
418 props_);
419 } else {
420 profile = new Profile(control_interface_,
421 this,
422 ident,
423 user_storage_format_,
424 false);
425 }
426
427
428 // |error| will have been populated if RemoveStorage fails.
429 profile->RemoveStorage(glib_, error);
430
431 return;
432}
433
Paul Stewart75225512012-01-26 22:51:33 -0800434bool Manager::HandleProfileEntryDeletion(const ProfileRefPtr &profile,
435 const std::string &entry_name) {
436 bool moved_services = false;
437 for (vector<ServiceRefPtr>::iterator it = services_.begin();
Paul Stewart65512e12012-03-26 18:01:08 -0700438 it != services_.end();) {
Paul Stewart75225512012-01-26 22:51:33 -0800439 if ((*it)->profile().get() == profile.get() &&
440 (*it)->GetStorageIdentifier() == entry_name) {
441 profile->AbandonService(*it);
Paul Stewart65512e12012-03-26 18:01:08 -0700442 if (MatchProfileWithService(*it) ||
443 !UnloadService(&it)) {
444 ++it;
Paul Stewart75225512012-01-26 22:51:33 -0800445 }
446 moved_services = true;
Paul Stewart65512e12012-03-26 18:01:08 -0700447 } else {
448 ++it;
Paul Stewart75225512012-01-26 22:51:33 -0800449 }
450 }
451 return moved_services;
452}
453
Paul Stewart0756db92012-01-27 08:34:47 -0800454ServiceRefPtr Manager::GetServiceWithStorageIdentifier(
455 const ProfileRefPtr &profile, const std::string &entry_name, Error *error) {
456 for (vector<ServiceRefPtr>::iterator it = services_.begin();
457 it != services_.end(); ++it) {
458 if ((*it)->profile().get() == profile.get() &&
459 (*it)->GetStorageIdentifier() == entry_name) {
460 return *it;
461 }
462 }
463
464 Error::PopulateAndLog(error, Error::kNotFound,
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500465 StringPrintf("Entry %s is not registered in the manager",
466 entry_name.c_str()));
Paul Stewart0756db92012-01-27 08:34:47 -0800467 return NULL;
468}
469
Paul Stewart13ed2252012-03-21 12:52:46 -0700470ServiceRefPtr Manager::GetServiceWithGUID(
471 const std::string &guid, Error *error) {
472 for (vector<ServiceRefPtr>::iterator it = services_.begin();
473 it != services_.end(); ++it) {
474 if ((*it)->guid() == guid) {
475 return *it;
476 }
477 }
478
479 Error::PopulateAndLog(error, Error::kNotFound,
480 StringPrintf("Service wth GUID %s is not registered in the manager",
481 guid.c_str()));
482 return NULL;
483}
484
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700485ServiceRefPtr Manager::GetDefaultService() const {
486 if (services_.empty() || !services_[0]->connection().get()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700487 SLOG(Manager, 2) << "In " << __func__ << ": No default connection exists.";
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700488 return NULL;
489 }
490 return services_[0];
491}
492
Paul Stewart20088d82012-02-16 06:58:55 -0800493bool Manager::IsPortalDetectionEnabled(Technology::Identifier tech) {
494 Error error;
495 vector<Technology::Identifier> portal_technologies;
Paul Stewart10e9e4e2012-04-26 19:46:28 -0700496 return Technology::GetTechnologyVectorFromString(GetCheckPortalList(NULL),
Paul Stewart20088d82012-02-16 06:58:55 -0800497 &portal_technologies,
498 &error) &&
499 std::find(portal_technologies.begin(), portal_technologies.end(),
500 tech) != portal_technologies.end();
501}
502
Paul Stewart10e9e4e2012-04-26 19:46:28 -0700503void Manager::SetStartupPortalList(const string &portal_list) {
504 startup_portal_list_ = portal_list;
505 use_startup_portal_list_ = true;
506}
507
Paul Stewart10ccbb32012-04-26 15:59:30 -0700508bool Manager::IsServiceEphemeral(const ServiceConstRefPtr &service) const {
509 return service->profile() == ephemeral_profile_;
510}
511
Paul Stewart1b253142012-01-26 14:05:52 -0800512const ProfileRefPtr &Manager::ActiveProfile() const {
Eric Shienbroodc74cf9c2012-03-02 15:00:35 -0500513 DCHECK_NE(profiles_.size(), 0U);
Chris Masone7aa5f902011-07-11 11:13:35 -0700514 return profiles_.back();
515}
516
Paul Stewart1b253142012-01-26 14:05:52 -0800517bool Manager::IsActiveProfile(const ProfileRefPtr &profile) const {
518 return (profiles_.size() > 0 &&
519 ActiveProfile().get() == profile.get());
520}
521
Eric Shienbrood9a245532012-03-07 14:20:39 -0500522void Manager::SaveActiveProfile() {
523 if (!profiles_.empty()) {
524 ActiveProfile()->Save();
525 }
526}
527
Chris Masone6515aab2011-10-12 16:19:09 -0700528bool Manager::MoveServiceToProfile(const ServiceRefPtr &to_move,
529 const ProfileRefPtr &destination) {
530 const ProfileRefPtr from = to_move->profile();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700531 SLOG(Manager, 2) << "Moving service "
532 << to_move->UniqueName()
533 << " to profile "
534 << destination->GetFriendlyName()
535 << " from "
536 << from->GetFriendlyName();
Chris Masone6515aab2011-10-12 16:19:09 -0700537 return destination->AdoptService(to_move) &&
538 from->AbandonService(to_move);
Chris Masone6791a432011-07-12 13:23:19 -0700539}
540
Paul Stewart7f61e522012-03-22 11:13:45 -0700541ProfileRefPtr Manager::LookupProfileByRpcIdentifier(
542 const string &profile_rpcid) {
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800543 for (vector<ProfileRefPtr>::iterator it = profiles_.begin();
544 it != profiles_.end();
545 ++it) {
546 if (profile_rpcid == (*it)->GetRpcIdentifier()) {
Paul Stewart7f61e522012-03-22 11:13:45 -0700547 return *it;
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800548 }
549 }
Paul Stewart7f61e522012-03-22 11:13:45 -0700550 return NULL;
551}
552
553void Manager::SetProfileForService(const ServiceRefPtr &to_set,
554 const string &profile_rpcid,
555 Error *error) {
556 ProfileRefPtr profile = LookupProfileByRpcIdentifier(profile_rpcid);
557 if (!profile) {
558 Error::PopulateAndLog(error, Error::kInvalidArguments,
559 StringPrintf("Unknown Profile %s requested for "
560 "Service", profile_rpcid.c_str()));
561 return;
562 }
563
564 if (to_set->profile().get() == profile.get()) {
565 Error::PopulateAndLog(error, Error::kInvalidArguments,
566 "Service is already connected to this profile");
567 } else if (!MoveServiceToProfile(to_set, profile)) {
568 Error::PopulateAndLog(error, Error::kInternalError,
569 "Unable to move service to profile");
570 }
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800571}
572
Eric Shienbrood9a245532012-03-07 14:20:39 -0500573void Manager::EnableTechnology(const std::string &technology_name,
574 Error *error,
575 const ResultCallback &callback) {
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400576 CHECK(error != NULL);
577 DCHECK(error->IsOngoing());
Eric Shienbrood9a245532012-03-07 14:20:39 -0500578 Technology::Identifier id = Technology::IdentifierFromName(technology_name);
579 if (id == Technology::kUnknown) {
580 error->Populate(Error::kInvalidArguments, "Unknown technology");
581 return;
582 }
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400583 bool deferred = false;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500584 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
585 it != devices_.end(); ++it) {
586 DeviceRefPtr device = *it;
Joshua Krollda798622012-06-05 12:30:48 -0700587 if (device->technology() == id && !device->enabled()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500588 device->SetEnabledPersistent(true, error, callback);
589 // Continue with other devices even if one fails
590 // TODO(ers): Decide whether an error should be returned
591 // for the overall EnableTechnology operation if some
592 // devices succeed and some fail.
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400593 if (error->IsOngoing())
594 deferred = true;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500595 }
596 }
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400597 // If no device has deferred work, then clear the error to
598 // communicate to the caller that all work is done.
599 if (!deferred)
600 error->Reset();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500601}
602
603void Manager::DisableTechnology(const std::string &technology_name,
604 Error *error,
605 const ResultCallback &callback) {
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400606 CHECK(error != NULL);
607 DCHECK(error->IsOngoing());
Eric Shienbrood9a245532012-03-07 14:20:39 -0500608 Technology::Identifier id = Technology::IdentifierFromName(technology_name);
609 if (id == Technology::kUnknown) {
610 error->Populate(Error::kInvalidArguments, "Unknown technology");
611 return;
612 }
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400613 bool deferred = false;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500614 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
615 it != devices_.end(); ++it) {
616 DeviceRefPtr device = *it;
Joshua Krollda798622012-06-05 12:30:48 -0700617 if (device->technology() == id && device->enabled()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500618 device->SetEnabledPersistent(false, error, callback);
619 // Continue with other devices even if one fails
620 // TODO(ers): Decide whether an error should be returned
621 // for the overall DisableTechnology operation if some
622 // devices succeed and some fail.
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400623 if (error->IsOngoing())
624 deferred = true;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500625 }
626 }
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400627 // If no device has deferred work, then clear the error to
628 // communicate to the caller that all work is done.
629 if (!deferred)
630 error->Reset();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500631}
632
633void Manager::UpdateEnabledTechnologies() {
634 Error error;
635 adaptor_->EmitStringsChanged(flimflam::kEnabledTechnologiesProperty,
636 EnabledTechnologies(&error));
637}
638
Chris Masone2b105542011-06-22 10:58:09 -0700639void Manager::RegisterDevice(const DeviceRefPtr &to_manage) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700640 SLOG(Manager, 2) << __func__ << "(" << to_manage->FriendlyName() << ")";
Chris Masonec1e50412011-06-07 13:04:53 -0700641 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700642 for (it = devices_.begin(); it != devices_.end(); ++it) {
Chris Masonec1e50412011-06-07 13:04:53 -0700643 if (to_manage.get() == it->get())
Chris Masone9be4a9d2011-05-16 15:44:09 -0700644 return;
645 }
Chris Masonec1e50412011-06-07 13:04:53 -0700646 devices_.push_back(to_manage);
Paul Stewartf1ce5d22011-05-19 13:10:20 -0700647
Paul Stewarta41e38d2011-11-11 07:47:29 -0800648 // We are applying device properties from the DefaultProfile, and adding
649 // the union of hidden services in all loaded profiles to the device.
Chris Masone6515aab2011-10-12 16:19:09 -0700650 for (vector<ProfileRefPtr>::iterator it = profiles_.begin();
651 it != profiles_.end();
652 ++it) {
Paul Stewarta41e38d2011-11-11 07:47:29 -0800653 // Load device configuration, if any exists, as well as hidden services.
654 (*it)->ConfigureDevice(to_manage);
655
656 // Currently the only profile for which "Save" is implemented is the
657 // DefaultProfile. It iterates over all Devices and stores their state.
658 // We perform the Save now in case the device we have just registered
659 // is new and needs to be added to the stored DefaultProfile.
Chris Masone6515aab2011-10-12 16:19:09 -0700660 (*it)->Save();
661 }
Paul Stewarta41e38d2011-11-11 07:47:29 -0800662
663 // In normal usage, running_ will always be true when we are here, however
664 // unit tests sometimes do things in otherwise invalid states.
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400665 if (running_ && (to_manage->enabled_persistent() ||
666 to_manage->IsUnderlyingDeviceEnabled()))
Eric Shienbrood9a245532012-03-07 14:20:39 -0500667 to_manage->SetEnabled(true);
Gaurav Shah435de2c2011-11-17 19:01:07 -0800668
Eric Shienbrood8839a892012-03-29 10:33:48 -0400669 EmitDeviceProperties();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700670}
671
mukesh agrawal5029c6c2011-08-25 11:12:40 -0700672void Manager::DeregisterDevice(const DeviceRefPtr &to_forget) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700673 SLOG(Manager, 2) << __func__ << "(" << to_forget->FriendlyName() << ")";
Chris Masonec1e50412011-06-07 13:04:53 -0700674 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700675 for (it = devices_.begin(); it != devices_.end(); ++it) {
Chris Masonec1e50412011-06-07 13:04:53 -0700676 if (to_forget.get() == it->get()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700677 SLOG(Manager, 2) << "Deregistered device: " << to_forget->UniqueName();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500678 to_forget->SetEnabled(false);
Chris Masone9be4a9d2011-05-16 15:44:09 -0700679 devices_.erase(it);
Eric Shienbrood8839a892012-03-29 10:33:48 -0400680 EmitDeviceProperties();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700681 return;
682 }
683 }
Ben Chanfad4a0b2012-04-18 15:49:59 -0700684 SLOG(Manager, 2) << __func__ << " unknown device: "
685 << to_forget->UniqueName();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700686}
687
Eric Shienbrood8839a892012-03-29 10:33:48 -0400688void Manager::EmitDeviceProperties() {
689 vector<DeviceRefPtr>::iterator it;
690 vector<string> device_paths;
691 for (it = devices_.begin(); it != devices_.end(); ++it) {
692 device_paths.push_back((*it)->GetRpcIdentifier());
693 }
694 adaptor_->EmitRpcIdentifierArrayChanged(flimflam::kDevicesProperty,
695 device_paths);
696 Error error;
697 adaptor_->EmitStringsChanged(flimflam::kAvailableTechnologiesProperty,
698 AvailableTechnologies(&error));
699 adaptor_->EmitStringsChanged(flimflam::kEnabledTechnologiesProperty,
700 EnabledTechnologies(&error));
701}
702
mukesh agrawal4eb4d782011-12-05 17:34:37 +0000703bool Manager::HasService(const ServiceRefPtr &service) {
704 vector<ServiceRefPtr>::iterator it;
705 for (it = services_.begin(); it != services_.end(); ++it) {
706 if ((*it)->UniqueName() == service->UniqueName())
707 return true;
708 }
709 return false;
710}
711
Chris Masone2b105542011-06-22 10:58:09 -0700712void Manager::RegisterService(const ServiceRefPtr &to_manage) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700713 SLOG(Manager, 2) << "In " << __func__ << "(): Registering service "
714 << to_manage->UniqueName();
mukesh agrawald835b202011-10-07 15:26:47 -0700715
Paul Stewart75225512012-01-26 22:51:33 -0800716 MatchProfileWithService(to_manage);
Chris Masone6791a432011-07-12 13:23:19 -0700717
718 // Now add to OUR list.
Chris Masonec1e50412011-06-07 13:04:53 -0700719 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700720 for (it = services_.begin(); it != services_.end(); ++it) {
mukesh agrawald835b202011-10-07 15:26:47 -0700721 CHECK(to_manage->UniqueName() != (*it)->UniqueName());
Chris Masone9be4a9d2011-05-16 15:44:09 -0700722 }
Chris Masonec1e50412011-06-07 13:04:53 -0700723 services_.push_back(to_manage);
Paul Stewart22aa71b2011-09-16 12:15:11 -0700724 SortServices();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700725}
726
Chris Masone6515aab2011-10-12 16:19:09 -0700727void Manager::DeregisterService(const ServiceRefPtr &to_forget) {
Chris Masonec1e50412011-06-07 13:04:53 -0700728 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700729 for (it = services_.begin(); it != services_.end(); ++it) {
Chris Masone6791a432011-07-12 13:23:19 -0700730 if (to_forget->UniqueName() == (*it)->UniqueName()) {
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800731 DCHECK(!(*it)->connection());
Chris Masone9be4a9d2011-05-16 15:44:09 -0700732 services_.erase(it);
Paul Stewart22aa71b2011-09-16 12:15:11 -0700733 SortServices();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700734 return;
735 }
736 }
737}
738
Paul Stewart65512e12012-03-26 18:01:08 -0700739bool Manager::UnloadService(vector<ServiceRefPtr>::iterator *service_iterator) {
740 if (!(**service_iterator)->Unload()) {
741 return false;
742 }
743
744 DCHECK(!(**service_iterator)->connection());
745 *service_iterator = services_.erase(*service_iterator);
746
747 return true;
748}
749
mukesh agrawal00917ce2011-11-22 23:56:55 +0000750void Manager::UpdateService(const ServiceRefPtr &to_update) {
751 CHECK(to_update);
Paul Stewart03dba0b2011-08-22 16:32:45 -0700752 LOG(INFO) << "Service " << to_update->UniqueName() << " updated;"
Gaurav Shahc6d6c722011-11-17 18:59:39 -0800753 << " state: " << Service::ConnectStateToString(to_update->state())
754 << " failure: "
755 << Service::ConnectFailureToString(to_update->failure());
Ben Chanfad4a0b2012-04-18 15:49:59 -0700756 SLOG(Manager, 2) << "IsConnected(): " << to_update->IsConnected();
757 SLOG(Manager, 2) << "IsConnecting(): " << to_update->IsConnecting();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800758 if (to_update->IsConnected()) {
mukesh agrawal00917ce2011-11-22 23:56:55 +0000759 to_update->MakeFavorite();
Gary Moraind93615e2012-04-27 11:50:03 -0700760 // Persists the updated favorite setting in the profile.
761 SaveServiceToProfile(to_update);
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800762 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700763 SortServices();
Paul Stewart03dba0b2011-08-22 16:32:45 -0700764}
765
Gary Moraind93615e2012-04-27 11:50:03 -0700766void Manager::SaveServiceToProfile(const ServiceRefPtr &to_update) {
767 if (IsServiceEphemeral(to_update)) {
768 if (profiles_.empty()) {
769 LOG(ERROR) << "Cannot assign profile to service: no profiles exist!";
770 } else {
771 MoveServiceToProfile(to_update, profiles_.back());
772 }
773 } else {
774 to_update->profile()->UpdateService(to_update);
775 }
776}
777
Gary Moraina9fb3252012-05-31 12:05:31 -0700778void Manager::AddTerminationAction(const std::string &name,
779 const base::Closure &start) {
780 termination_actions_.Add(name, start);
781}
782
783void Manager::TerminationActionComplete(const std::string &name) {
784 termination_actions_.ActionComplete(name);
785}
786
787void Manager::RemoveTerminationAction(const std::string &name) {
788 termination_actions_.Remove(name);
789}
790
791void Manager::RunTerminationActions(
792 int timeout_ms, const base::Callback<void(const Error &)> &done) {
793 termination_actions_.Run(timeout_ms, done);
794}
795
Paul Stewartfdd16072011-09-16 12:41:35 -0700796void Manager::FilterByTechnology(Technology::Identifier tech,
Chris Masonec1e50412011-06-07 13:04:53 -0700797 vector<DeviceRefPtr> *found) {
Chris Masone9be4a9d2011-05-16 15:44:09 -0700798 CHECK(found);
Chris Masonec1e50412011-06-07 13:04:53 -0700799 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700800 for (it = devices_.begin(); it != devices_.end(); ++it) {
Joshua Krollda798622012-06-05 12:30:48 -0700801 if ((*it)->technology() == tech)
Chris Masone9be4a9d2011-05-16 15:44:09 -0700802 found->push_back(*it);
803 }
804}
805
Paul Stewart22aa71b2011-09-16 12:15:11 -0700806ServiceRefPtr Manager::FindService(const string& name) {
Chris Masonec1e50412011-06-07 13:04:53 -0700807 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700808 for (it = services_.begin(); it != services_.end(); ++it) {
Chris Masone6791a432011-07-12 13:23:19 -0700809 if (name == (*it)->UniqueName())
Chris Masonee0dea762011-06-09 09:06:03 -0700810 return *it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700811 }
Chris Masonee0dea762011-06-09 09:06:03 -0700812 return NULL;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700813}
814
mukesh agrawal2366eed2012-03-20 18:21:50 -0700815void Manager::HelpRegisterConstDerivedRpcIdentifiers(
816 const string &name,
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400817 RpcIdentifiers(Manager::*get)(Error *error)) {
mukesh agrawal2366eed2012-03-20 18:21:50 -0700818 store_.RegisterDerivedRpcIdentifiers(
819 name,
820 RpcIdentifiersAccessor(
821 new CustomAccessor<Manager, RpcIdentifiers>(this, get, NULL)));
822}
823
mukesh agrawalffa3d042011-10-06 15:26:10 -0700824void Manager::HelpRegisterDerivedString(
825 const string &name,
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800826 string(Manager::*get)(Error *),
mukesh agrawalffa3d042011-10-06 15:26:10 -0700827 void(Manager::*set)(const string&, Error *)) {
Chris Masone27c4aa52011-07-02 13:10:14 -0700828 store_.RegisterDerivedString(
829 name,
830 StringAccessor(new CustomAccessor<Manager, string>(this, get, set)));
Chris Masoneb925cc82011-06-22 15:39:57 -0700831}
832
mukesh agrawalffa3d042011-10-06 15:26:10 -0700833void Manager::HelpRegisterDerivedStrings(
834 const string &name,
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800835 Strings(Manager::*get)(Error *),
mukesh agrawalffa3d042011-10-06 15:26:10 -0700836 void(Manager::*set)(const Strings &, Error *)) {
Chris Masone27c4aa52011-07-02 13:10:14 -0700837 store_.RegisterDerivedStrings(
838 name,
839 StringsAccessor(new CustomAccessor<Manager, Strings>(this, get, set)));
Chris Masoneb925cc82011-06-22 15:39:57 -0700840}
841
Paul Stewart22aa71b2011-09-16 12:15:11 -0700842void Manager::SortServices() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700843 SLOG(Manager, 4) << "In " << __func__;
Thieu Lea20cbc22012-01-09 22:01:43 +0000844 ServiceRefPtr default_service;
845
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800846 if (!services_.empty()) {
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700847 // Keep track of the service that is the candidate for the default
848 // service. We have not yet tested to see if this service has a
849 // connection.
Thieu Lea20cbc22012-01-09 22:01:43 +0000850 default_service = services_[0];
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800851 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700852 sort(services_.begin(), services_.end(), ServiceSorter(technology_order_));
Paul Stewarta41e38d2011-11-11 07:47:29 -0800853
854 vector<string> service_paths;
855 vector<ServiceRefPtr>::iterator it;
856 for (it = services_.begin(); it != services_.end(); ++it) {
857 if ((*it)->IsVisible()) {
858 service_paths.push_back((*it)->GetRpcIdentifier());
859 }
860 }
861 adaptor_->EmitRpcIdentifierArrayChanged(flimflam::kServicesProperty,
862 service_paths);
Gaurav Shah435de2c2011-11-17 19:01:07 -0800863
864 Error error;
865 adaptor_->EmitStringsChanged(flimflam::kConnectedTechnologiesProperty,
866 ConnectedTechnologies(&error));
867 adaptor_->EmitStringChanged(flimflam::kDefaultTechnologyProperty,
868 DefaultTechnology(&error));
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800869
870 if (!services_.empty()) {
Thieu Lea20cbc22012-01-09 22:01:43 +0000871 ConnectionRefPtr default_connection = default_service->connection();
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800872 if (default_connection.get() &&
873 (services_[0]->connection().get() != default_connection.get())) {
874 default_connection->SetIsDefault(false);
875 }
876 if (services_[0]->connection().get()) {
877 services_[0]->connection()->SetIsDefault(true);
Thieu Lea20cbc22012-01-09 22:01:43 +0000878 default_service = services_[0];
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700879 } else {
880 default_service = NULL;
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800881 }
882 }
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700883 metrics_->NotifyDefaultServiceChanged(default_service);
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800884
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000885 AutoConnect();
886}
887
Paul Stewart75225512012-01-26 22:51:33 -0800888bool Manager::MatchProfileWithService(const ServiceRefPtr &service) {
889 vector<ProfileRefPtr>::reverse_iterator it;
890 for (it = profiles_.rbegin(); it != profiles_.rend(); ++it) {
891 if ((*it)->ConfigureService(service)) {
892 break;
893 }
894 }
895 if (it == profiles_.rend()) {
896 ephemeral_profile_->AdoptService(service);
897 return false;
898 }
899 return true;
900}
901
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000902void Manager::AutoConnect() {
903 // We might be called in the middle of another request (e.g., as a
904 // consequence of Service::SetState calling UpdateService). To avoid
905 // re-entrancy issues in dbus-c++, defer to the event loop.
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500906 dispatcher_->PostTask(Bind(&Manager::AutoConnectTask, AsWeakPtr()));
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000907}
908
909void Manager::AutoConnectTask() {
910 if (services_.empty()) {
911 LOG(INFO) << "No services.";
912 return;
913 }
914
Ben Chanfad4a0b2012-04-18 15:49:59 -0700915 if (SLOG_IS_ON(Manager, 4)) {
916 SLOG(Manager, 4) << "Sorted service list: ";
mukesh agrawalddc378f2012-02-17 18:26:20 -0800917 for (size_t i = 0; i < services_.size(); ++i) {
918 ServiceRefPtr service = services_[i];
919 const char *compare_reason = NULL;
920 if (i + 1 < services_.size()) {
921 Service::Compare(
922 service, services_[i+1], technology_order_, &compare_reason);
923 } else {
mukesh agrawalbf14e942012-03-02 14:36:34 -0800924 compare_reason = "last";
mukesh agrawalddc378f2012-02-17 18:26:20 -0800925 }
Ben Chanfad4a0b2012-04-18 15:49:59 -0700926 SLOG(Manager, 4) << "Service " << service->friendly_name()
927 << " IsConnected: " << service->IsConnected()
928 << " IsConnecting: " << service->IsConnecting()
929 << " IsFailed: " << service->IsFailed()
930 << " connectable: " << service->connectable()
931 << " auto_connect: " << service->auto_connect()
932 << " favorite: " << service->favorite()
933 << " priority: " << service->priority()
934 << " security_level: " << service->security_level()
935 << " strength: " << service->strength()
936 << " UniqueName: " << service->UniqueName()
937 << " sorted: " << compare_reason;
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000938 }
939 }
940
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800941 // Perform auto-connect.
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000942 for (vector<ServiceRefPtr>::iterator it = services_.begin();
943 it != services_.end(); ++it) {
944 if ((*it)->auto_connect()) {
mukesh agrawal592516d2012-01-12 14:01:00 -0800945 LOG(INFO) << "Requesting autoconnect to service "
946 << (*it)->friendly_name() << ".";
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000947 (*it)->AutoConnect();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800948 }
949 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700950}
951
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800952string Manager::CalculateState(Error */*error*/) {
Gary Morain028545d2012-04-07 14:55:52 -0700953 // |services_| is sorted such that connected services are first.
954 if (!services_.empty() &&
955 services_.front()->IsConnected()) {
956 return flimflam::kStateOnline;
957 }
Chris Masoneb925cc82011-06-22 15:39:57 -0700958 return flimflam::kStateOffline;
959}
960
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800961vector<string> Manager::AvailableTechnologies(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -0800962 set<string> unique_technologies;
963 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
964 it != devices_.end(); ++it) {
965 unique_technologies.insert(
966 Technology::NameFromIdentifier((*it)->technology()));
967 }
968 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -0700969}
970
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800971vector<string> Manager::ConnectedTechnologies(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -0800972 set<string> unique_technologies;
973 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
974 it != devices_.end(); ++it) {
975 if ((*it)->IsConnected())
976 unique_technologies.insert(
977 Technology::NameFromIdentifier((*it)->technology()));
978 }
979 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -0700980}
981
Gaurav Shah435de2c2011-11-17 19:01:07 -0800982string Manager::DefaultTechnology(Error *error) {
983 return (!services_.empty() && services_[0]->IsConnected()) ?
984 services_[0]->GetTechnologyString(error) : "";
Chris Masoneb925cc82011-06-22 15:39:57 -0700985}
986
Eric Shienbrood9a245532012-03-07 14:20:39 -0500987vector<string> Manager::EnabledTechnologies(Error */*error*/) {
988 set<string> unique_technologies;
989 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
990 it != devices_.end(); ++it) {
991 if ((*it)->enabled())
992 unique_technologies.insert(
993 Technology::NameFromIdentifier((*it)->technology()));
994 }
995 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -0700996}
997
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800998vector<string> Manager::EnumerateDevices(Error */*error*/) {
Chris Masone3c3f6a12011-07-01 10:01:41 -0700999 vector<string> device_rpc_ids;
1000 for (vector<DeviceRefPtr>::const_iterator it = devices_.begin();
1001 it != devices_.end();
1002 ++it) {
1003 device_rpc_ids.push_back((*it)->GetRpcIdentifier());
1004 }
1005 return device_rpc_ids;
1006}
1007
Paul Stewart1b253142012-01-26 14:05:52 -08001008vector<string> Manager::EnumerateProfiles(Error */*error*/) {
1009 vector<string> profile_rpc_ids;
1010 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
1011 it != profiles_.end();
1012 ++it) {
1013 profile_rpc_ids.push_back((*it)->GetRpcIdentifier());
1014 }
1015 return profile_rpc_ids;
1016}
1017
Gaurav Shah1b7a6162011-11-09 11:41:01 -08001018vector<string> Manager::EnumerateAvailableServices(Error */*error*/) {
Chris Masone3c3f6a12011-07-01 10:01:41 -07001019 vector<string> service_rpc_ids;
1020 for (vector<ServiceRefPtr>::const_iterator it = services_.begin();
1021 it != services_.end();
1022 ++it) {
1023 service_rpc_ids.push_back((*it)->GetRpcIdentifier());
1024 }
1025 return service_rpc_ids;
1026}
1027
Gaurav Shah1b7a6162011-11-09 11:41:01 -08001028vector<string> Manager::EnumerateWatchedServices(Error *error) {
Chris Masone6791a432011-07-12 13:23:19 -07001029 // TODO(cmasone): Filter this list for services in appropriate states.
Gaurav Shah1b7a6162011-11-09 11:41:01 -08001030 return EnumerateAvailableServices(error);
Chris Masone3c3f6a12011-07-01 10:01:41 -07001031}
1032
Paul Stewart1b253142012-01-26 14:05:52 -08001033string Manager::GetActiveProfileRpcIdentifier(Error */*error*/) {
1034 return ActiveProfile()->GetRpcIdentifier();
Chris Masone7aa5f902011-07-11 11:13:35 -07001035}
1036
Paul Stewart10e9e4e2012-04-26 19:46:28 -07001037string Manager::GetCheckPortalList(Error */*error*/) {
Jason Glasgowdf7c5532012-05-14 14:41:45 -04001038 return use_startup_portal_list_ ? startup_portal_list_ :
1039 props_.check_portal_list;
Paul Stewart10e9e4e2012-04-26 19:46:28 -07001040}
1041
1042void Manager::SetCheckPortalList(const string &portal_list, Error *error) {
1043 props_.check_portal_list = portal_list;
1044 use_startup_portal_list_ = false;
1045}
1046
mukesh agrawal32399322011-09-01 10:53:43 -07001047// called via RPC (e.g., from ManagerDBusAdaptor)
Darin Petkovb65c2452012-02-23 15:17:06 +01001048ServiceRefPtr Manager::GetService(const KeyValueStore &args, Error *error) {
Paul Stewart7f5ad572012-06-04 15:18:54 -07001049 if (args.ContainsString(flimflam::kTypeProperty) &&
1050 args.GetString(flimflam::kTypeProperty) == flimflam::kTypeVPN) {
1051 // GetService on a VPN service should actually perform ConfigureService.
1052 // TODO(pstew): Remove this hack and change Chrome to use ConfigureService
1053 // instead, when we no longer need to support flimflam. crosbug.com/31523
1054 return ConfigureService(args, error);
1055 }
1056 return GetServiceInner(args, error);
1057}
1058
1059ServiceRefPtr Manager::GetServiceInner(const KeyValueStore &args,
1060 Error *error) {
Paul Stewart13ed2252012-03-21 12:52:46 -07001061 if (args.ContainsString(flimflam::kGuidProperty)) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001062 SLOG(Manager, 2) << __func__ << ": searching by GUID";
Paul Stewart13ed2252012-03-21 12:52:46 -07001063 ServiceRefPtr service =
1064 GetServiceWithGUID(args.GetString(flimflam::kGuidProperty), NULL);
1065 if (service) {
Paul Stewartcb59fed2012-03-21 21:14:46 -07001066 service->Configure(args, error);
Paul Stewart13ed2252012-03-21 12:52:46 -07001067 return service;
1068 }
1069 }
1070
Darin Petkovb65c2452012-02-23 15:17:06 +01001071 if (!args.ContainsString(flimflam::kTypeProperty)) {
Paul Stewart7f61e522012-03-22 11:13:45 -07001072 Error::PopulateAndLog(error, Error::kInvalidArguments, kErrorTypeRequired);
Darin Petkovb65c2452012-02-23 15:17:06 +01001073 return NULL;
1074 }
1075
1076 string type = args.GetString(flimflam::kTypeProperty);
Darin Petkovd1cd7972012-05-22 15:26:15 +02001077 if (type == flimflam::kTypeVPN) {
1078 SLOG(Manager, 2) << __func__ << ": getting VPN Service";
1079 return vpn_provider_.GetService(args, error);
1080 }
Darin Petkovb65c2452012-02-23 15:17:06 +01001081 if (type == flimflam::kTypeWifi) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001082 SLOG(Manager, 2) << __func__ << ": getting WiFi Service";
Darin Petkovb65c2452012-02-23 15:17:06 +01001083 return GetWifiService(args, error);
1084 }
Darin Petkovd1cd7972012-05-22 15:26:15 +02001085 if (type == flimflam::kTypeWimax) {
1086 SLOG(Manager, 2) << __func__ << ": getting WiMAX Service";
1087 return wimax_provider_.GetService(args, error);
Darin Petkovb65c2452012-02-23 15:17:06 +01001088 }
mukesh agrawal06175d72012-04-23 16:46:01 -07001089 Error::PopulateAndLog(error, Error::kNotSupported,
1090 kErrorUnsupportedServiceType);
Darin Petkovb65c2452012-02-23 15:17:06 +01001091 return NULL;
1092}
1093
mukesh agrawal7a4e4002011-09-06 11:26:05 -07001094WiFiServiceRefPtr Manager::GetWifiService(const KeyValueStore &args,
1095 Error *error) {
Paul Stewarta41e38d2011-11-11 07:47:29 -08001096 vector<DeviceRefPtr> wifi_devices;
Paul Stewart22aa71b2011-09-16 12:15:11 -07001097 FilterByTechnology(Technology::kWifi, &wifi_devices);
mukesh agrawal7a4e4002011-09-06 11:26:05 -07001098 if (wifi_devices.empty()) {
mukesh agrawal06175d72012-04-23 16:46:01 -07001099 Error::PopulateAndLog(error, Error::kInvalidArguments, kErrorNoDevice);
mukesh agrawal7a4e4002011-09-06 11:26:05 -07001100 return NULL;
1101 } else {
1102 WiFi *wifi = dynamic_cast<WiFi *>(wifi_devices.front().get());
1103 CHECK(wifi);
1104 return wifi->GetService(args, error);
1105 }
1106}
1107
Paul Stewart7f61e522012-03-22 11:13:45 -07001108// called via RPC (e.g., from ManagerDBusAdaptor)
Paul Stewart7f5ad572012-06-04 15:18:54 -07001109ServiceRefPtr Manager::ConfigureService(const KeyValueStore &args,
1110 Error *error) {
Paul Stewart7f61e522012-03-22 11:13:45 -07001111 ProfileRefPtr profile = ActiveProfile();
1112 bool profile_specified = args.ContainsString(flimflam::kProfileProperty);
1113 if (profile_specified) {
1114 string profile_rpcid = args.GetString(flimflam::kProfileProperty);
1115 profile = LookupProfileByRpcIdentifier(profile_rpcid);
1116 if (!profile) {
1117 Error::PopulateAndLog(error, Error::kInvalidArguments,
1118 "Invalid profile name " + profile_rpcid);
Paul Stewart7f5ad572012-06-04 15:18:54 -07001119 return NULL;
Paul Stewart7f61e522012-03-22 11:13:45 -07001120 }
1121 }
1122
Paul Stewart7f5ad572012-06-04 15:18:54 -07001123 ServiceRefPtr service = GetServiceInner(args, error);
Paul Stewart7f61e522012-03-22 11:13:45 -07001124 if (error->IsFailure() || !service) {
1125 LOG(ERROR) << "GetService failed; returning upstream error.";
Paul Stewart7f5ad572012-06-04 15:18:54 -07001126 return NULL;
Paul Stewart7f61e522012-03-22 11:13:45 -07001127 }
1128
mukesh agrawal06175d72012-04-23 16:46:01 -07001129 // Overwrite the profile data with the resulting configured service.
Paul Stewart7f61e522012-03-22 11:13:45 -07001130 if (!profile->UpdateService(service)) {
1131 Error::PopulateAndLog(error, Error::kInternalError,
1132 "Unable to save service to profile");
Paul Stewart7f5ad572012-06-04 15:18:54 -07001133 return NULL;
Paul Stewart7f61e522012-03-22 11:13:45 -07001134 }
1135
1136 if (HasService(service)) {
1137 // If the service has been registered (it may not be -- as is the case
1138 // with invisible WiFi networks), we can now transfer the service between
1139 // profiles.
Paul Stewart10ccbb32012-04-26 15:59:30 -07001140 if (IsServiceEphemeral(service) ||
Paul Stewart7f61e522012-03-22 11:13:45 -07001141 (profile_specified && service->profile() != profile)) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001142 SLOG(Manager, 2) << "Moving service to profile "
1143 << profile->GetFriendlyName();
Paul Stewart7f61e522012-03-22 11:13:45 -07001144 if (!MoveServiceToProfile(service, profile)) {
1145 Error::PopulateAndLog(error, Error::kInternalError,
1146 "Unable to move service to profile");
1147 }
1148 }
1149 }
Paul Stewart4357f4e2012-04-26 17:39:26 -07001150
1151 // Notify the service that a profile has been configured for it.
1152 service->OnProfileConfigured();
Paul Stewart7f5ad572012-06-04 15:18:54 -07001153
1154 return service;
Paul Stewart7f61e522012-03-22 11:13:45 -07001155}
1156
Paul Stewartc681fa02012-03-02 19:40:04 -08001157void Manager::RecheckPortal(Error */*error*/) {
1158 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1159 it != devices_.end(); ++it) {
1160 if ((*it)->RequestPortalDetection()) {
1161 // Only start Portal Detection on the device with the default connection.
1162 // We will get a "true" return value when we've found that device, and
1163 // can end our loop early as a result.
1164 break;
1165 }
1166 }
1167}
1168
Paul Stewartd215af62012-04-24 23:25:50 -07001169void Manager::RecheckPortalOnService(const ServiceRefPtr &service) {
1170 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1171 it != devices_.end(); ++it) {
1172 if ((*it)->IsConnectedToService(service)) {
1173 // As opposed to RecheckPortal() above, we explicitly stop and then
1174 // restart portal detection, since the service to recheck was explicitly
1175 // specified.
1176 (*it)->RestartPortalDetection();
1177 break;
1178 }
1179 }
1180}
1181
mukesh agrawal7a4e4002011-09-06 11:26:05 -07001182// called via RPC (e.g., from ManagerDBusAdaptor)
Paul Stewart22aa71b2011-09-16 12:15:11 -07001183void Manager::RequestScan(const string &technology, Error *error) {
mukesh agrawal32399322011-09-01 10:53:43 -07001184 if (technology == flimflam::kTypeWifi || technology == "") {
1185 vector<DeviceRefPtr> wifi_devices;
Paul Stewartfdd16072011-09-16 12:41:35 -07001186 FilterByTechnology(Technology::kWifi, &wifi_devices);
mukesh agrawal32399322011-09-01 10:53:43 -07001187
1188 for (vector<DeviceRefPtr>::iterator it = wifi_devices.begin();
1189 it != wifi_devices.end();
1190 ++it) {
Darin Petkovc0865312011-09-16 15:31:20 -07001191 (*it)->Scan(error);
mukesh agrawal32399322011-09-01 10:53:43 -07001192 }
1193 } else {
1194 // TODO(quiche): support scanning for other technologies?
Paul Stewartbe005172011-11-02 18:10:29 -07001195 Error::PopulateAndLog(error, Error::kInvalidArguments,
1196 "Unrecognized technology " + technology);
mukesh agrawal32399322011-09-01 10:53:43 -07001197 }
1198}
1199
Paul Stewart22aa71b2011-09-16 12:15:11 -07001200string Manager::GetTechnologyOrder() {
1201 vector<string> technology_names;
1202 for (vector<Technology::Identifier>::iterator it = technology_order_.begin();
1203 it != technology_order_.end();
1204 ++it) {
1205 technology_names.push_back(Technology::NameFromIdentifier(*it));
1206 }
1207
1208 return JoinString(technology_names, ',');
1209}
1210
1211void Manager::SetTechnologyOrder(const string &order, Error *error) {
1212 vector<Technology::Identifier> new_order;
Ben Chanfad4a0b2012-04-18 15:49:59 -07001213 SLOG(Manager, 2) << "Setting technology order to " << order;
Paul Stewart20088d82012-02-16 06:58:55 -08001214 if (!Technology::GetTechnologyVectorFromString(order, &new_order, error)) {
1215 return;
Paul Stewart22aa71b2011-09-16 12:15:11 -07001216 }
1217
1218 technology_order_ = new_order;
1219 SortServices();
1220}
1221
Paul Stewart75897df2011-04-27 09:05:53 -07001222} // namespace shill