blob: 5d632a6c45aa78645892c77cff38833bd13c926d [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 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 Stewart4d5efb72012-09-17 12:24:34 -070019#include <base/string_split.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"
Darin Petkov002c58e2012-06-19 02:56:05 +020027#include "shill/dbus_manager.h"
Chris Masone7aa5f902011-07-11 11:13:35 -070028#include "shill/default_profile.h"
Chris Masone9be4a9d2011-05-16 15:44:09 -070029#include "shill/device.h"
30#include "shill/device_info.h"
Chris Masone6791a432011-07-12 13:23:19 -070031#include "shill/ephemeral_profile.h"
Chris Masone8fe2c7e2011-06-09 15:51:19 -070032#include "shill/error.h"
Paul Stewart35eff132013-04-12 12:08:40 -070033#include "shill/ethernet_eap_provider.h"
34#include "shill/ethernet_eap_service.h"
Paul Stewart26b327e2011-10-19 11:38:09 -070035#include "shill/event_dispatcher.h"
Gaurav Shahb790aa22012-10-23 12:51:12 -070036#include "shill/geolocation_info.h"
Gary Moraina9fb3252012-05-31 12:05:31 -070037#include "shill/hook_table.h"
Prathmesh Prabhuba99b592013-04-17 15:13:14 -070038#include "shill/ip_address_store.h"
Chris Masone9d779932011-08-25 16:33:41 -070039#include "shill/key_file_store.h"
Christopher Wileyb691efd2012-08-09 13:51:51 -070040#include "shill/logging.h"
Chris Masone7aa5f902011-07-11 11:13:35 -070041#include "shill/profile.h"
Chris Masoneb925cc82011-06-22 15:39:57 -070042#include "shill/property_accessor.h"
Gary Morainac1bdb42012-02-16 17:42:29 -080043#include "shill/proxy_factory.h"
Paul Stewarte6132022011-08-16 09:11:02 -070044#include "shill/resolver.h"
Chris Masone9be4a9d2011-05-16 15:44:09 -070045#include "shill/service.h"
Thieu Lea20cbc22012-01-09 22:01:43 +000046#include "shill/service_sorter.h"
Darin Petkovc3505a52013-03-18 15:13:29 +010047#include "shill/vpn_provider.h"
Darin Petkov33af05c2012-02-28 10:10:30 +010048#include "shill/vpn_service.h"
mukesh agrawal7a4e4002011-09-06 11:26:05 -070049#include "shill/wifi.h"
Paul Stewart3c504012013-01-17 17:49:58 -080050#include "shill/wifi_provider.h"
mukesh agrawal7a4e4002011-09-06 11:26:05 -070051#include "shill/wifi_service.h"
Darin Petkovd1cd7972012-05-22 15:26:15 +020052#include "shill/wimax_service.h"
Paul Stewart75897df2011-04-27 09:05:53 -070053
Eric Shienbrood3e20a232012-02-16 11:35:56 -050054using base::Bind;
Albert Chaulk0e1cdea2013-02-27 15:32:55 -080055using base::FilePath;
Eric Shienbrood3e20a232012-02-16 11:35:56 -050056using base::StringPrintf;
57using base::Unretained;
Darin Petkova5e07ef2012-07-09 14:27:57 +020058using std::map;
Gaurav Shah435de2c2011-11-17 19:01:07 -080059using std::set;
Paul Stewart75897df2011-04-27 09:05:53 -070060using std::string;
Chris Masone9be4a9d2011-05-16 15:44:09 -070061using std::vector;
Paul Stewart75897df2011-04-27 09:05:53 -070062
63namespace shill {
Paul Stewarte6132022011-08-16 09:11:02 -070064
Daniel Eratf9753672013-01-24 10:17:02 -080065namespace {
66
67// Human-readable string describing the suspend delay that is registered
68// with the power manager.
69const char kSuspendDelayDescription[] = "shill";
70
71} // namespace
72
Darin Petkovb65c2452012-02-23 15:17:06 +010073// statics
74const char Manager::kErrorNoDevice[] = "no wifi devices available";
75const char Manager::kErrorTypeRequired[] = "must specify service type";
76const char Manager::kErrorUnsupportedServiceType[] =
77 "service type is unsupported";
Arman Ugurayab22c162012-10-08 19:08:38 -070078// This timeout should be less than the upstart job timeout, otherwise
79// stats for termination actions might be lost.
80const int Manager::kTerminationActionsTimeoutMilliseconds = 4500;
Darin Petkov3ec55342012-09-28 14:04:44 +020081const char Manager::kPowerManagerKey[] = "manager";
mukesh agrawal7a4e4002011-09-06 11:26:05 -070082
Paul Stewart75897df2011-04-27 09:05:53 -070083Manager::Manager(ControlInterface *control_interface,
Darin Petkov887f2982011-07-14 16:10:17 -070084 EventDispatcher *dispatcher,
Thieu Le3426c8f2012-01-11 17:35:11 -080085 Metrics *metrics,
Chris Masone2ae797d2011-08-23 20:41:00 -070086 GLib *glib,
87 const string &run_directory,
88 const string &storage_directory,
89 const string &user_storage_format)
mukesh agrawal8a3188d2011-12-01 20:56:44 +000090 : dispatcher_(dispatcher),
mukesh agrawal8a3188d2011-12-01 20:56:44 +000091 run_path_(FilePath(run_directory)),
92 storage_path_(FilePath(storage_directory)),
93 user_storage_format_(user_storage_format),
mukesh agrawald142fd62013-05-01 16:50:57 -070094 user_profile_list_path_(FilePath(Profile::kUserProfileListPathname)),
mukesh agrawal8a3188d2011-12-01 20:56:44 +000095 adaptor_(control_interface->CreateManagerAdaptor(this)),
Thieu Le3426c8f2012-01-11 17:35:11 -080096 device_info_(control_interface, dispatcher, metrics, this),
97 modem_info_(control_interface, dispatcher, metrics, this, glib),
Paul Stewart35eff132013-04-12 12:08:40 -070098 ethernet_eap_provider_(
99 new EthernetEapProvider(
100 control_interface, dispatcher, metrics, this)),
Darin Petkovc3505a52013-03-18 15:13:29 +0100101 vpn_provider_(
102 new VPNProvider(control_interface, dispatcher, metrics, this)),
Paul Stewart3c504012013-01-17 17:49:58 -0800103 wifi_provider_(
104 new WiFiProvider(control_interface, dispatcher, metrics, this)),
Darin Petkovb72b62e2012-05-15 16:55:36 +0200105 wimax_provider_(control_interface, dispatcher, metrics, this),
Paul Stewart4d5efb72012-09-17 12:24:34 -0700106 resolver_(Resolver::GetInstance()),
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000107 running_(false),
108 connect_profiles_to_rpc_(true),
Thieu Le5133b712013-02-19 14:47:21 -0800109 ephemeral_profile_(
110 new EphemeralProfile(control_interface, metrics, this)),
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000111 control_interface_(control_interface),
Thieu Le3426c8f2012-01-11 17:35:11 -0800112 metrics_(metrics),
Paul Stewart10e9e4e2012-04-26 19:46:28 -0700113 glib_(glib),
Gary Moraina9fb3252012-05-31 12:05:31 -0700114 use_startup_portal_list_(false),
Darin Petkova5e07ef2012-07-09 14:27:57 +0200115 termination_actions_(dispatcher),
Daniel Erat0818cca2012-12-14 10:16:21 -0800116 suspend_delay_registered_(false),
117 suspend_delay_id_(0),
Christopher Wiley1057cd72013-02-28 15:21:29 -0800118 default_service_callback_tag_(0),
Prathmesh Prabhuba99b592013-04-17 15:13:14 -0700119 crypto_util_proxy_(new CryptoUtilProxy(dispatcher, glib)),
120 health_checker_remote_ips_(new IPAddressStore()) {
Chris Masone7aa5f902011-07-11 11:13:35 -0700121 HelpRegisterDerivedString(flimflam::kActiveProfileProperty,
Paul Stewart1b253142012-01-26 14:05:52 -0800122 &Manager::GetActiveProfileRpcIdentifier,
Chris Masone7aa5f902011-07-11 11:13:35 -0700123 NULL);
Paul Stewartd408fdf2012-05-07 17:15:57 -0700124 store_.RegisterBool(flimflam::kArpGatewayProperty, &props_.arp_gateway);
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700125 HelpRegisterConstDerivedStrings(flimflam::kAvailableTechnologiesProperty,
126 &Manager::AvailableTechnologies);
Paul Stewart10e9e4e2012-04-26 19:46:28 -0700127 HelpRegisterDerivedString(flimflam::kCheckPortalListProperty,
128 &Manager::GetCheckPortalList,
129 &Manager::SetCheckPortalList);
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700130 HelpRegisterConstDerivedStrings(flimflam::kConnectedTechnologiesProperty,
131 &Manager::ConnectedTechnologies);
Chris Masone88cbd5f2011-07-03 14:30:04 -0700132 store_.RegisterString(flimflam::kCountryProperty, &props_.country);
Chris Masone27c4aa52011-07-02 13:10:14 -0700133 HelpRegisterDerivedString(flimflam::kDefaultTechnologyProperty,
134 &Manager::DefaultTechnology,
135 NULL);
Paul Stewart49739c02012-08-08 17:24:03 -0700136 HelpRegisterConstDerivedRpcIdentifier(
137 shill::kDefaultServiceProperty,
138 &Manager::GetDefaultServiceRpcIdentifier);
Paul Stewartcb3eb892012-06-07 14:24:46 -0700139 HelpRegisterConstDerivedRpcIdentifiers(flimflam::kDevicesProperty,
140 &Manager::EnumerateDevices);
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700141 HelpRegisterConstDerivedStrings(flimflam::kEnabledTechnologiesProperty,
142 &Manager::EnabledTechnologies);
Paul Stewart4d5efb72012-09-17 12:24:34 -0700143 HelpRegisterDerivedString(shill::kIgnoredDNSSearchPathsProperty,
144 &Manager::GetIgnoredDNSSearchPaths,
145 &Manager::SetIgnoredDNSSearchPaths);
Paul Stewart036dba02012-08-07 12:34:41 -0700146 store_.RegisterString(shill::kLinkMonitorTechnologiesProperty,
147 &props_.link_monitor_technologies);
Chris Masone88cbd5f2011-07-03 14:30:04 -0700148 store_.RegisterBool(flimflam::kOfflineModeProperty, &props_.offline_mode);
149 store_.RegisterString(flimflam::kPortalURLProperty, &props_.portal_url);
Paul Stewartc681fa02012-03-02 19:40:04 -0800150 store_.RegisterInt32(kPortalCheckIntervalProperty,
151 &props_.portal_check_interval_seconds);
Paul Stewartcb3eb892012-06-07 14:24:46 -0700152 HelpRegisterConstDerivedRpcIdentifiers(flimflam::kProfilesProperty,
153 &Manager::EnumerateProfiles);
Paul Stewartc681fa02012-03-02 19:40:04 -0800154 store_.RegisterString(kHostNameProperty, &props_.host_name);
Chris Masone88cbd5f2011-07-03 14:30:04 -0700155 HelpRegisterDerivedString(flimflam::kStateProperty,
156 &Manager::CalculateState,
157 NULL);
mukesh agrawal2366eed2012-03-20 18:21:50 -0700158 HelpRegisterConstDerivedRpcIdentifiers(flimflam::kServicesProperty,
159 &Manager::EnumerateAvailableServices);
Paul Stewart3c504012013-01-17 17:49:58 -0800160 HelpRegisterConstDerivedRpcIdentifiers(shill::kServiceCompleteListProperty,
161 &Manager::EnumerateCompleteServices);
Paul Stewartcb3eb892012-06-07 14:24:46 -0700162 HelpRegisterConstDerivedRpcIdentifiers(flimflam::kServiceWatchListProperty,
163 &Manager::EnumerateWatchedServices);
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700164 HelpRegisterConstDerivedStrings(kUninitializedTechnologiesProperty,
165 &Manager::UninitializedTechnologies);
Chris Masone3c3f6a12011-07-01 10:01:41 -0700166
mukesh agrawal84de5d22012-02-17 19:29:15 -0800167 // Set default technology order "by hand", to avoid invoking side
168 // effects of SetTechnologyOrder.
169 technology_order_.push_back(
Darin Petkov2f903b32012-04-18 12:56:43 +0200170 Technology::IdentifierFromName(flimflam::kTypeVPN));
171 technology_order_.push_back(
mukesh agrawal84de5d22012-02-17 19:29:15 -0800172 Technology::IdentifierFromName(flimflam::kTypeEthernet));
173 technology_order_.push_back(
174 Technology::IdentifierFromName(flimflam::kTypeWifi));
175 technology_order_.push_back(
Ben Chan3cafe382012-11-13 07:51:10 -0800176 Technology::IdentifierFromName(flimflam::kTypeWimax));
177 technology_order_.push_back(
mukesh agrawal84de5d22012-02-17 19:29:15 -0800178 Technology::IdentifierFromName(flimflam::kTypeCellular));
179
Ben Chanfad4a0b2012-04-18 15:49:59 -0700180 SLOG(Manager, 2) << "Manager initialized.";
Paul Stewart75897df2011-04-27 09:05:53 -0700181}
182
Darin Petkove7c6ad32012-06-29 10:22:09 +0200183Manager::~Manager() {}
Paul Stewart75897df2011-04-27 09:05:53 -0700184
mukesh agrawal8f317b62011-07-15 11:53:23 -0700185void Manager::AddDeviceToBlackList(const string &device_name) {
186 device_info_.AddDeviceToBlackList(device_name);
187}
188
Paul Stewart75897df2011-04-27 09:05:53 -0700189void Manager::Start() {
Paul Stewart0af98bf2011-05-10 17:38:08 -0700190 LOG(INFO) << "Manager started.";
Paul Stewarte6132022011-08-16 09:11:02 -0700191
Darin Petkov002c58e2012-06-19 02:56:05 +0200192 dbus_manager_.reset(new DBusManager());
193 dbus_manager_->Start();
194
Darin Petkov3ec55342012-09-28 14:04:44 +0200195 power_manager_.reset(
196 new PowerManager(dispatcher_, ProxyFactory::GetInstance()));
Darin Petkovca621542012-07-25 14:25:56 +0200197 power_manager_->AddStateChangeCallback(
Darin Petkov3ec55342012-09-28 14:04:44 +0200198 kPowerManagerKey,
Darin Petkovca621542012-07-25 14:25:56 +0200199 Bind(&Manager::OnPowerStateChanged, AsWeakPtr()));
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500200 // TODO(ers): weak ptr for metrics_?
201 PowerManager::PowerStateCallback cb =
202 Bind(&Metrics::NotifyPowerStateChange, Unretained(metrics_));
Thieu Leb84ba342012-03-02 15:15:19 -0800203 power_manager_->AddStateChangeCallback(Metrics::kMetricPowerManagerKey, cb);
204
Chris Masone2ae797d2011-08-23 20:41:00 -0700205 CHECK(file_util::CreateDirectory(run_path_)) << run_path_.value();
Paul Stewart4d5efb72012-09-17 12:24:34 -0700206 resolver_->set_path(run_path_.Append("resolv.conf"));
Chris Masone2ae797d2011-08-23 20:41:00 -0700207
Gaurav Shah71354762011-11-28 19:22:49 -0800208 InitializeProfiles();
Paul Stewart75897df2011-04-27 09:05:53 -0700209 running_ = true;
Chris Masone413a3192011-05-09 17:10:05 -0700210 adaptor_->UpdateRunning();
Paul Stewart0af98bf2011-05-10 17:38:08 -0700211 device_info_.Start();
Darin Petkov887f2982011-07-14 16:10:17 -0700212 modem_info_.Start();
Paul Stewart35eff132013-04-12 12:08:40 -0700213 ethernet_eap_provider_->Start();
Darin Petkovc3505a52013-03-18 15:13:29 +0100214 vpn_provider_->Start();
Paul Stewart3c504012013-01-17 17:49:58 -0800215 wifi_provider_->Start();
Darin Petkov9893d9c2012-05-17 15:27:31 -0700216 wimax_provider_.Start();
Paul Stewart75897df2011-04-27 09:05:53 -0700217}
218
219void Manager::Stop() {
220 running_ = false;
Paul Stewart212d60f2012-07-12 10:59:13 -0700221 // Persist device information to disk;
222 vector<DeviceRefPtr>::iterator devices_it;
223 for (devices_it = devices_.begin(); devices_it != devices_.end();
224 ++devices_it) {
225 UpdateDevice(*devices_it);
226 }
227
Wade Guthrie60a37062013-04-02 11:39:09 -0700228 UpdateWiFiProvider();
229
Paul Stewart212d60f2012-07-12 10:59:13 -0700230 // Persist profile, service information to disk.
231 vector<ProfileRefPtr>::iterator profiles_it;
232 for (profiles_it = profiles_.begin(); profiles_it != profiles_.end();
233 ++profiles_it) {
Paul Stewartd0a3b812012-03-28 22:48:22 -0700234 // Since this happens in a loop, the current manager state is stored to
235 // all default profiles in the stack. This is acceptable because the
236 // only time multiple default profiles are loaded are during autotests.
Paul Stewart212d60f2012-07-12 10:59:13 -0700237 (*profiles_it)->Save();
Chris Masone9d779932011-08-25 16:33:41 -0700238 }
Chris Masone9d779932011-08-25 16:33:41 -0700239
Thieu Le1271d682011-11-02 22:48:19 +0000240 vector<ServiceRefPtr>::iterator services_it;
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000241 Error e;
Thieu Le1271d682011-11-02 22:48:19 +0000242 for (services_it = services_.begin(); services_it != services_.end();
243 ++services_it) {
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000244 (*services_it)->Disconnect(&e);
Thieu Le1271d682011-11-02 22:48:19 +0000245 }
246
Chris Masone413a3192011-05-09 17:10:05 -0700247 adaptor_->UpdateRunning();
Darin Petkovb72b62e2012-05-15 16:55:36 +0200248 wimax_provider_.Stop();
Paul Stewart3c504012013-01-17 17:49:58 -0800249 wifi_provider_->Stop();
Darin Petkovc3505a52013-03-18 15:13:29 +0100250 vpn_provider_->Stop();
Paul Stewart35eff132013-04-12 12:08:40 -0700251 ethernet_eap_provider_->Stop();
Darin Petkov887f2982011-07-14 16:10:17 -0700252 modem_info_.Stop();
253 device_info_.Stop();
Paul Stewartdfa46052012-06-26 09:44:14 -0700254 sort_services_task_.Cancel();
Darin Petkovca621542012-07-25 14:25:56 +0200255 power_manager_.reset();
Darin Petkov002c58e2012-06-19 02:56:05 +0200256 dbus_manager_.reset();
Paul Stewart75897df2011-04-27 09:05:53 -0700257}
258
Gaurav Shah71354762011-11-28 19:22:49 -0800259void Manager::InitializeProfiles() {
mukesh agrawald142fd62013-05-01 16:50:57 -0700260 DCHECK(profiles_.empty()); // The default profile must go first on stack.
Gaurav Shah71354762011-11-28 19:22:49 -0800261 CHECK(file_util::CreateDirectory(storage_path_)) << storage_path_.value();
mukesh agrawald142fd62013-05-01 16:50:57 -0700262
263 // Ensure that we have storage for the default profile, and that
264 // the persistent copy of the default profile is not corrupt.
Paul Stewart870523b2012-01-11 17:00:42 -0800265 scoped_refptr<DefaultProfile>
266 default_profile(new DefaultProfile(control_interface_,
Thieu Le5133b712013-02-19 14:47:21 -0800267 metrics_,
Gaurav Shah71354762011-11-28 19:22:49 -0800268 this,
269 storage_path_,
Paul Stewartd0a3b812012-03-28 22:48:22 -0700270 DefaultProfile::kDefaultId,
Gaurav Shah71354762011-11-28 19:22:49 -0800271 props_));
Thieu Le5133b712013-02-19 14:47:21 -0800272 // The default profile may fail to initialize if it's corrupted.
273 // If so, recreate the default profile.
274 if (!default_profile->InitStorage(
275 glib_, Profile::kCreateOrOpenExisting, NULL))
276 CHECK(default_profile->InitStorage(glib_, Profile::kCreateNew,
277 NULL));
mukesh agrawal00752532013-05-03 15:46:55 -0700278 // In case we created a new profile, initialize its default values,
279 // and then save. This is required for properties such as
280 // PortalDetector::kDefaultCheckPortalList to be initialized correctly.
281 LoadProperties(default_profile);
mukesh agrawald142fd62013-05-01 16:50:57 -0700282 default_profile->Save();
283 default_profile = NULL; // PushProfileInternal will re-create.
284
285 // Read list of user profiles. This must be done before pushing the
286 // default profile, because modifying the profile stack updates the
287 // user profile list.
288 vector<Profile::Identifier> identifiers =
289 Profile::LoadUserProfileList(user_profile_list_path_);
290
291 // Push the default profile onto the stack.
Gaurav Shah71354762011-11-28 19:22:49 -0800292 Error error;
Paul Stewart19c871d2011-12-15 16:10:13 -0800293 string path;
mukesh agrawald142fd62013-05-01 16:50:57 -0700294 Profile::Identifier default_profile_id;
295 CHECK(Profile::ParseIdentifier(
296 DefaultProfile::kDefaultId, &default_profile_id));
297 PushProfileInternal(default_profile_id, &path, &error);
298 CHECK(error.IsSuccess()); // Must have a default profile.
299
300 // Push user profiles onto the stack.
301 for (const auto &profile_id : identifiers) {
302 PushProfileInternal(profile_id, &path, &error);
Paul Stewart78af94c2013-04-17 16:02:06 -0700303 }
Gaurav Shah71354762011-11-28 19:22:49 -0800304}
305
Paul Stewart19c871d2011-12-15 16:10:13 -0800306void Manager::CreateProfile(const string &name, string *path, Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700307 SLOG(Manager, 2) << __func__ << " " << name;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700308 Profile::Identifier ident;
309 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700310 Error::PopulateAndLog(error, Error::kInvalidArguments,
311 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700312 return;
313 }
Paul Stewartd0a3b812012-03-28 22:48:22 -0700314
Paul Stewartf3eced92013-04-17 12:18:22 -0700315 if (HasProfile(ident)) {
316 Error::PopulateAndLog(error, Error::kAlreadyExists,
317 "Profile name " + name + " is already on stack");
318 return;
Paul Stewartfc9a1da2012-06-27 15:54:52 -0700319 }
320
Paul Stewartd0a3b812012-03-28 22:48:22 -0700321 ProfileRefPtr profile;
322 if (ident.user.empty()) {
323 profile = new DefaultProfile(control_interface_,
Thieu Le5133b712013-02-19 14:47:21 -0800324 metrics_,
Paul Stewartd0a3b812012-03-28 22:48:22 -0700325 this,
326 storage_path_,
327 ident.identifier,
328 props_);
329 } else {
330 profile = new Profile(control_interface_,
Thieu Le5133b712013-02-19 14:47:21 -0800331 metrics_,
Paul Stewartd0a3b812012-03-28 22:48:22 -0700332 this,
333 ident,
334 user_storage_format_,
Gary Morainb672d352012-04-25 09:19:06 -0700335 true);
Paul Stewartd0a3b812012-03-28 22:48:22 -0700336 }
337
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700338 if (!profile->InitStorage(glib_, Profile::kCreateNew, error)) {
Paul Stewart19c871d2011-12-15 16:10:13 -0800339 // |error| will have been populated by InitStorage().
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700340 return;
341 }
342
343 // Save profile data out, and then let the scoped pointer fall out of scope.
344 if (!profile->Save()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700345 Error::PopulateAndLog(error, Error::kInternalError,
346 "Profile name " + name + " could not be saved");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700347 return;
348 }
Paul Stewart19c871d2011-12-15 16:10:13 -0800349
350 *path = profile->GetRpcIdentifier();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700351}
352
Paul Stewartf3eced92013-04-17 12:18:22 -0700353bool Manager::HasProfile(const Profile::Identifier &ident) {
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700354 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
355 it != profiles_.end();
356 ++it) {
357 if ((*it)->MatchesIdentifier(ident)) {
Paul Stewartf3eced92013-04-17 12:18:22 -0700358 return true;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700359 }
360 }
Paul Stewartf3eced92013-04-17 12:18:22 -0700361 return false;
362}
363
364void Manager::PushProfileInternal(
365 const Profile::Identifier &ident, string *path, Error *error) {
366 if (HasProfile(ident)) {
367 Error::PopulateAndLog(error, Error::kAlreadyExists,
368 "Profile name " + Profile::IdentifierToString(ident) +
369 " is already on stack");
370 return;
371 }
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700372
Paul Stewartd0a3b812012-03-28 22:48:22 -0700373 ProfileRefPtr profile;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700374 if (ident.user.empty()) {
Paul Stewartd0a3b812012-03-28 22:48:22 -0700375 // Allow a machine-wide-profile to be pushed on the stack only if the
376 // profile stack is empty, or if the topmost profile on the stack is
377 // also a machine-wide (non-user) profile.
378 if (!profiles_.empty() && !profiles_.back()->GetUser().empty()) {
379 Error::PopulateAndLog(error, Error::kInvalidArguments,
Paul Stewartf3eced92013-04-17 12:18:22 -0700380 "Cannot load non-default global profile " +
381 Profile::IdentifierToString(ident) +
Paul Stewartd0a3b812012-03-28 22:48:22 -0700382 " on top of a user profile");
383 return;
384 }
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700385
Paul Stewartd0a3b812012-03-28 22:48:22 -0700386 scoped_refptr<DefaultProfile>
387 default_profile(new DefaultProfile(control_interface_,
Thieu Le5133b712013-02-19 14:47:21 -0800388 metrics_,
Paul Stewartd0a3b812012-03-28 22:48:22 -0700389 this,
390 storage_path_,
391 ident.identifier,
392 props_));
393 if (!default_profile->InitStorage(glib_, Profile::kOpenExisting, error)) {
394 // |error| will have been populated by InitStorage().
395 return;
396 }
397
Paul Stewart4d5efb72012-09-17 12:24:34 -0700398 if (!LoadProperties(default_profile)) {
Paul Stewartd0a3b812012-03-28 22:48:22 -0700399 Error::PopulateAndLog(error, Error::kInvalidArguments,
400 "Could not load Manager properties from profile " +
Paul Stewartf3eced92013-04-17 12:18:22 -0700401 Profile::IdentifierToString(ident));
Paul Stewartd0a3b812012-03-28 22:48:22 -0700402 return;
403 }
404 profile = default_profile;
405 } else {
406 profile = new Profile(control_interface_,
Thieu Le5133b712013-02-19 14:47:21 -0800407 metrics_,
Paul Stewartd0a3b812012-03-28 22:48:22 -0700408 this,
409 ident,
410 user_storage_format_,
411 connect_profiles_to_rpc_);
412 if (!profile->InitStorage(glib_, Profile::kOpenExisting, error)) {
413 // |error| will have been populated by InitStorage().
414 return;
415 }
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700416 }
417
Paul Stewarta849a3d2011-11-03 05:54:09 -0700418 profiles_.push_back(profile);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700419
420 // Offer each registered Service the opportunity to join this new Profile.
Paul Stewarta41e38d2011-11-11 07:47:29 -0800421 for (vector<ServiceRefPtr>::iterator it = services_.begin();
422 it != services_.end(); ++it) {
Paul Stewartbba6a5b2011-11-02 18:45:59 -0700423 profile->ConfigureService(*it);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700424 }
425
Paul Stewart3c504012013-01-17 17:49:58 -0800426 // Shop the Profile contents around to Devices which may have configuration
427 // stored in these profiles.
Paul Stewarta41e38d2011-11-11 07:47:29 -0800428 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
429 it != devices_.end(); ++it) {
430 profile->ConfigureDevice(*it);
431 }
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800432
Darin Petkovc63dcf02012-05-24 11:51:43 +0200433 // Offer the Profile contents to the service/device providers which will
434 // create new services if necessary.
Darin Petkovc3505a52013-03-18 15:13:29 +0100435 vpn_provider_->CreateServicesFromProfile(profile);
Paul Stewart3c504012013-01-17 17:49:58 -0800436 wifi_provider_->CreateServicesFromProfile(profile);
Darin Petkovc63dcf02012-05-24 11:51:43 +0200437 wimax_provider_.CreateServicesFromProfile(profile);
Paul Stewart66815332012-04-09 18:09:36 -0700438
Paul Stewart19c871d2011-12-15 16:10:13 -0800439 *path = profile->GetRpcIdentifier();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800440 SortServices();
Paul Stewart78af94c2013-04-17 16:02:06 -0700441 OnProfilesChanged();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700442}
443
Paul Stewartf3eced92013-04-17 12:18:22 -0700444void Manager::PushProfile(const string &name, string *path, Error *error) {
445 SLOG(Manager, 2) << __func__ << " " << name;
446 Profile::Identifier ident;
447 if (!Profile::ParseIdentifier(name, &ident)) {
448 Error::PopulateAndLog(error, Error::kInvalidArguments,
449 "Invalid profile name " + name);
450 return;
451 }
452 PushProfileInternal(ident, path, error);
453}
454
455void Manager::InsertUserProfile(const string &name,
456 const string &user_hash,
457 string *path,
458 Error *error) {
459 SLOG(Manager, 2) << __func__ << " " << name;
460 Profile::Identifier ident;
461 if (!Profile::ParseIdentifier(name, &ident) ||
462 ident.user.empty()) {
463 Error::PopulateAndLog(error, Error::kInvalidArguments,
464 "Invalid user profile name " + name);
465 return;
466 }
467 ident.user_hash = user_hash;
468 PushProfileInternal(ident, path, error);
469}
470
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700471void Manager::PopProfileInternal() {
472 CHECK(!profiles_.empty());
473 ProfileRefPtr active_profile = profiles_.back();
474 profiles_.pop_back();
Paul Stewart75225512012-01-26 22:51:33 -0800475 vector<ServiceRefPtr>::iterator it;
Paul Stewart65512e12012-03-26 18:01:08 -0700476 for (it = services_.begin(); it != services_.end();) {
477 if ((*it)->profile().get() != active_profile.get() ||
478 MatchProfileWithService(*it) ||
479 !UnloadService(&it)) {
480 LOG(ERROR) << "Skipping unload of service";
481 ++it;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700482 }
483 }
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800484 SortServices();
Paul Stewart78af94c2013-04-17 16:02:06 -0700485 OnProfilesChanged();
486}
Philipp Neubeck79173602012-11-13 21:10:09 +0100487
Paul Stewart78af94c2013-04-17 16:02:06 -0700488void Manager::OnProfilesChanged() {
Philipp Neubeck79173602012-11-13 21:10:09 +0100489 Error unused_error;
Paul Stewart78af94c2013-04-17 16:02:06 -0700490
Philipp Neubeck79173602012-11-13 21:10:09 +0100491 adaptor_->EmitStringsChanged(flimflam::kProfilesProperty,
492 EnumerateProfiles(&unused_error));
mukesh agrawald142fd62013-05-01 16:50:57 -0700493 Profile::SaveUserProfileList(user_profile_list_path_, profiles_);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700494}
495
Paul Stewarta41e38d2011-11-11 07:47:29 -0800496void Manager::PopProfile(const string &name, Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700497 SLOG(Manager, 2) << __func__ << " " << name;
Christopher Wiley3e7635e2012-08-15 09:46:17 -0700498 // This signal is sent when a user logs out of a session. Regardless of
499 // whether we find their profile to remove, lets clear the network related
500 // logs.
501 MemoryLog::GetInstance()->Clear();
502 LOG(INFO) << "Cleared the memory log on logout event.";
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700503 Profile::Identifier ident;
504 if (profiles_.empty()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700505 Error::PopulateAndLog(error, Error::kNotFound, "Profile stack is empty");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700506 return;
507 }
508 ProfileRefPtr active_profile = profiles_.back();
509 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700510 Error::PopulateAndLog(error, Error::kInvalidArguments,
511 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700512 return;
513 }
514 if (!active_profile->MatchesIdentifier(ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700515 Error::PopulateAndLog(error, Error::kNotSupported,
516 name + " is not the active profile");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700517 return;
518 }
519 PopProfileInternal();
520}
521
522void Manager::PopAnyProfile(Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700523 SLOG(Manager, 2) << __func__;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700524 Profile::Identifier ident;
525 if (profiles_.empty()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700526 Error::PopulateAndLog(error, Error::kNotFound, "Profile stack is empty");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700527 return;
528 }
529 PopProfileInternal();
530}
531
Paul Stewart307c2502013-03-23 12:32:10 -0700532void Manager::PopAllUserProfiles(Error */*error*/) {
533 SLOG(Manager, 2) << __func__;
534 // This signal is sent when a user logs out of a session. Regardless of
535 // whether we find their profile to remove, lets clear the network related
536 // logs.
537 MemoryLog::GetInstance()->Clear();
538 LOG(INFO) << "Cleared the memory log on logout event.";
539 while (!profiles_.empty() && !profiles_.back()->GetUser().empty()) {
540 PopProfileInternal();
541 }
542}
543
Paul Stewarte73d05c2012-03-29 16:26:05 -0700544void Manager::RemoveProfile(const string &name, Error *error) {
545 Profile::Identifier ident;
546 if (!Profile::ParseIdentifier(name, &ident)) {
547 Error::PopulateAndLog(error, Error::kInvalidArguments,
548 "Invalid profile name " + name);
549 return;
550 }
551
Paul Stewartf3eced92013-04-17 12:18:22 -0700552 if (HasProfile(ident)) {
553 Error::PopulateAndLog(error, Error::kInvalidArguments,
554 "Cannot remove profile name " + name +
555 " since it is on stack");
556 return;
Paul Stewarte73d05c2012-03-29 16:26:05 -0700557 }
558
559 ProfileRefPtr profile;
560 if (ident.user.empty()) {
561 profile = new DefaultProfile(control_interface_,
Thieu Le5133b712013-02-19 14:47:21 -0800562 metrics_,
Paul Stewarte73d05c2012-03-29 16:26:05 -0700563 this,
564 storage_path_,
565 ident.identifier,
566 props_);
567 } else {
568 profile = new Profile(control_interface_,
Thieu Le5133b712013-02-19 14:47:21 -0800569 metrics_,
Paul Stewarte73d05c2012-03-29 16:26:05 -0700570 this,
571 ident,
572 user_storage_format_,
573 false);
574 }
575
576
577 // |error| will have been populated if RemoveStorage fails.
578 profile->RemoveStorage(glib_, error);
579
580 return;
581}
582
Paul Stewart75225512012-01-26 22:51:33 -0800583bool Manager::HandleProfileEntryDeletion(const ProfileRefPtr &profile,
584 const std::string &entry_name) {
585 bool moved_services = false;
586 for (vector<ServiceRefPtr>::iterator it = services_.begin();
Paul Stewart65512e12012-03-26 18:01:08 -0700587 it != services_.end();) {
Paul Stewart75225512012-01-26 22:51:33 -0800588 if ((*it)->profile().get() == profile.get() &&
589 (*it)->GetStorageIdentifier() == entry_name) {
590 profile->AbandonService(*it);
Paul Stewart65512e12012-03-26 18:01:08 -0700591 if (MatchProfileWithService(*it) ||
592 !UnloadService(&it)) {
593 ++it;
Paul Stewart75225512012-01-26 22:51:33 -0800594 }
595 moved_services = true;
Paul Stewart65512e12012-03-26 18:01:08 -0700596 } else {
597 ++it;
Paul Stewart75225512012-01-26 22:51:33 -0800598 }
599 }
600 return moved_services;
601}
602
Paul Stewart967eaeb2013-04-25 19:53:07 -0700603map<string, string> Manager::GetLoadableProfileEntriesForService(
604 const ServiceConstRefPtr &service) {
605 map<string, string> profile_entries;
606 for (const auto &profile : profiles_) {
607 string entry_name = service->GetLoadableStorageIdentifier(
608 *profile->GetConstStorage());
609 if (!entry_name.empty()) {
610 profile_entries[profile->GetRpcIdentifier()] = entry_name;
611 }
612 }
613 return profile_entries;
614}
615
Paul Stewart0756db92012-01-27 08:34:47 -0800616ServiceRefPtr Manager::GetServiceWithStorageIdentifier(
617 const ProfileRefPtr &profile, const std::string &entry_name, Error *error) {
618 for (vector<ServiceRefPtr>::iterator it = services_.begin();
619 it != services_.end(); ++it) {
620 if ((*it)->profile().get() == profile.get() &&
621 (*it)->GetStorageIdentifier() == entry_name) {
622 return *it;
623 }
624 }
625
Paul Stewart76a89cb2012-09-14 06:06:48 -0700626 string error_string(
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500627 StringPrintf("Entry %s is not registered in the manager",
628 entry_name.c_str()));
Paul Stewart76a89cb2012-09-14 06:06:48 -0700629 if (error) {
630 error->Populate(Error::kNotFound, error_string);
631 }
632 SLOG(Manager, 2) << error_string;
Paul Stewart0756db92012-01-27 08:34:47 -0800633 return NULL;
634}
635
Paul Stewart13ed2252012-03-21 12:52:46 -0700636ServiceRefPtr Manager::GetServiceWithGUID(
637 const std::string &guid, Error *error) {
638 for (vector<ServiceRefPtr>::iterator it = services_.begin();
639 it != services_.end(); ++it) {
640 if ((*it)->guid() == guid) {
641 return *it;
642 }
643 }
644
Paul Stewart76a89cb2012-09-14 06:06:48 -0700645 string error_string(
Paul Stewart13ed2252012-03-21 12:52:46 -0700646 StringPrintf("Service wth GUID %s is not registered in the manager",
647 guid.c_str()));
Paul Stewart76a89cb2012-09-14 06:06:48 -0700648 if (error) {
649 error->Populate(Error::kNotFound, error_string);
650 }
651 SLOG(Manager, 2) << error_string;
Paul Stewart13ed2252012-03-21 12:52:46 -0700652 return NULL;
653}
654
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700655ServiceRefPtr Manager::GetDefaultService() const {
Arman Uguray32c76402012-11-27 14:01:13 -0800656 SLOG(Manager, 2) << __func__;
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700657 if (services_.empty() || !services_[0]->connection().get()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700658 SLOG(Manager, 2) << "In " << __func__ << ": No default connection exists.";
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700659 return NULL;
660 }
661 return services_[0];
662}
663
Paul Stewart49739c02012-08-08 17:24:03 -0700664RpcIdentifier Manager::GetDefaultServiceRpcIdentifier(Error */*error*/) {
665 ServiceRefPtr default_service = GetDefaultService();
666 return default_service ? default_service->GetRpcIdentifier() : "/";
667}
668
Paul Stewart036dba02012-08-07 12:34:41 -0700669bool Manager::IsTechnologyInList(const string &technology_list,
670 Technology::Identifier tech) const {
Paul Stewart20088d82012-02-16 06:58:55 -0800671 Error error;
Paul Stewart036dba02012-08-07 12:34:41 -0700672 vector<Technology::Identifier> technologies;
673 return Technology::GetTechnologyVectorFromString(technology_list,
674 &technologies,
Paul Stewart20088d82012-02-16 06:58:55 -0800675 &error) &&
Paul Stewart036dba02012-08-07 12:34:41 -0700676 std::find(technologies.begin(), technologies.end(), tech) !=
677 technologies.end();
678}
679
680bool Manager::IsPortalDetectionEnabled(Technology::Identifier tech) {
681 return IsTechnologyInList(GetCheckPortalList(NULL), tech);
Paul Stewart20088d82012-02-16 06:58:55 -0800682}
683
Paul Stewart10e9e4e2012-04-26 19:46:28 -0700684void Manager::SetStartupPortalList(const string &portal_list) {
685 startup_portal_list_ = portal_list;
686 use_startup_portal_list_ = true;
687}
688
Paul Stewartd2e1c362013-03-03 19:06:07 -0800689bool Manager::IsProfileBefore(const ProfileRefPtr &a,
690 const ProfileRefPtr &b) const {
691 DCHECK(a != b);
692 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
693 it != profiles_.end();
694 ++it) {
695 if (*it == a) {
696 return true;
697 }
698 if (*it == b) {
699 return false;
700 }
701 }
702 NOTREACHED() << "We should have found both profiles in the profiles_ list!";
703 return false;
704}
705
Paul Stewart10ccbb32012-04-26 15:59:30 -0700706bool Manager::IsServiceEphemeral(const ServiceConstRefPtr &service) const {
707 return service->profile() == ephemeral_profile_;
708}
709
Paul Stewart036dba02012-08-07 12:34:41 -0700710bool Manager::IsTechnologyLinkMonitorEnabled(
711 Technology::Identifier technology) const {
712 return IsTechnologyInList(props_.link_monitor_technologies, technology);
Paul Stewartbf667612012-06-29 14:49:54 -0700713}
714
Paul Stewart3c504012013-01-17 17:49:58 -0800715bool Manager::IsDefaultProfile(StoreInterface *storage) {
716 return profiles_.empty() || storage == profiles_.front()->GetConstStorage();
717}
718
719void Manager::OnProfileStorageInitialized(StoreInterface *storage) {
Wade Guthrie60a37062013-04-02 11:39:09 -0700720 wifi_provider_->LoadAndFixupServiceEntries(storage,
721 IsDefaultProfile(storage));
Paul Stewart3c504012013-01-17 17:49:58 -0800722}
723
724DeviceRefPtr Manager::GetEnabledDeviceWithTechnology(
725 Technology::Identifier technology) const {
726 vector<DeviceRefPtr> devices;
727 FilterByTechnology(technology, &devices);
728 for (vector<DeviceRefPtr>::const_iterator it = devices.begin();
729 it != devices.end(); ++it) {
730 if ((*it)->enabled()) {
731 return *it;
732 }
Paul Stewart85aea152013-01-22 09:31:56 -0800733 }
Paul Stewart3c504012013-01-17 17:49:58 -0800734 return NULL;
Paul Stewart85aea152013-01-22 09:31:56 -0800735}
736
Paul Stewart1b253142012-01-26 14:05:52 -0800737const ProfileRefPtr &Manager::ActiveProfile() const {
Eric Shienbroodc74cf9c2012-03-02 15:00:35 -0500738 DCHECK_NE(profiles_.size(), 0U);
Chris Masone7aa5f902011-07-11 11:13:35 -0700739 return profiles_.back();
740}
741
Paul Stewart1b253142012-01-26 14:05:52 -0800742bool Manager::IsActiveProfile(const ProfileRefPtr &profile) const {
743 return (profiles_.size() > 0 &&
744 ActiveProfile().get() == profile.get());
745}
746
Chris Masone6515aab2011-10-12 16:19:09 -0700747bool Manager::MoveServiceToProfile(const ServiceRefPtr &to_move,
748 const ProfileRefPtr &destination) {
749 const ProfileRefPtr from = to_move->profile();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700750 SLOG(Manager, 2) << "Moving service "
Darin Petkov457728b2013-01-09 09:49:08 +0100751 << to_move->unique_name()
Ben Chanfad4a0b2012-04-18 15:49:59 -0700752 << " to profile "
753 << destination->GetFriendlyName()
754 << " from "
755 << from->GetFriendlyName();
Darin Petkov457728b2013-01-09 09:49:08 +0100756 return destination->AdoptService(to_move) && from->AbandonService(to_move);
Chris Masone6791a432011-07-12 13:23:19 -0700757}
758
Paul Stewart7f61e522012-03-22 11:13:45 -0700759ProfileRefPtr Manager::LookupProfileByRpcIdentifier(
760 const string &profile_rpcid) {
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800761 for (vector<ProfileRefPtr>::iterator it = profiles_.begin();
762 it != profiles_.end();
763 ++it) {
764 if (profile_rpcid == (*it)->GetRpcIdentifier()) {
Paul Stewart7f61e522012-03-22 11:13:45 -0700765 return *it;
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800766 }
767 }
Paul Stewart7f61e522012-03-22 11:13:45 -0700768 return NULL;
769}
770
771void Manager::SetProfileForService(const ServiceRefPtr &to_set,
772 const string &profile_rpcid,
773 Error *error) {
774 ProfileRefPtr profile = LookupProfileByRpcIdentifier(profile_rpcid);
775 if (!profile) {
776 Error::PopulateAndLog(error, Error::kInvalidArguments,
777 StringPrintf("Unknown Profile %s requested for "
778 "Service", profile_rpcid.c_str()));
779 return;
780 }
781
Paul Stewart649f3a42012-04-24 23:22:16 -0700782 if (!to_set->profile()) {
783 // We are being asked to set the profile property of a service that
784 // has never been registered. Now is a good time to register it.
785 RegisterService(to_set);
786 }
787
Paul Stewart7f61e522012-03-22 11:13:45 -0700788 if (to_set->profile().get() == profile.get()) {
789 Error::PopulateAndLog(error, Error::kInvalidArguments,
790 "Service is already connected to this profile");
791 } else if (!MoveServiceToProfile(to_set, profile)) {
792 Error::PopulateAndLog(error, Error::kInternalError,
793 "Unable to move service to profile");
794 }
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800795}
796
Eric Shienbrood9a245532012-03-07 14:20:39 -0500797void Manager::EnableTechnology(const std::string &technology_name,
798 Error *error,
799 const ResultCallback &callback) {
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400800 CHECK(error != NULL);
801 DCHECK(error->IsOngoing());
Eric Shienbrood9a245532012-03-07 14:20:39 -0500802 Technology::Identifier id = Technology::IdentifierFromName(technology_name);
803 if (id == Technology::kUnknown) {
804 error->Populate(Error::kInvalidArguments, "Unknown technology");
805 return;
806 }
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400807 bool deferred = false;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500808 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
809 it != devices_.end(); ++it) {
810 DeviceRefPtr device = *it;
Joshua Krollda798622012-06-05 12:30:48 -0700811 if (device->technology() == id && !device->enabled()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500812 device->SetEnabledPersistent(true, error, callback);
813 // Continue with other devices even if one fails
814 // TODO(ers): Decide whether an error should be returned
815 // for the overall EnableTechnology operation if some
816 // devices succeed and some fail.
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400817 if (error->IsOngoing())
818 deferred = true;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500819 }
820 }
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400821 // If no device has deferred work, then clear the error to
822 // communicate to the caller that all work is done.
823 if (!deferred)
824 error->Reset();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500825}
826
827void Manager::DisableTechnology(const std::string &technology_name,
828 Error *error,
829 const ResultCallback &callback) {
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400830 CHECK(error != NULL);
831 DCHECK(error->IsOngoing());
Eric Shienbrood9a245532012-03-07 14:20:39 -0500832 Technology::Identifier id = Technology::IdentifierFromName(technology_name);
833 if (id == Technology::kUnknown) {
834 error->Populate(Error::kInvalidArguments, "Unknown technology");
835 return;
836 }
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400837 bool deferred = false;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500838 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
839 it != devices_.end(); ++it) {
840 DeviceRefPtr device = *it;
Joshua Krollda798622012-06-05 12:30:48 -0700841 if (device->technology() == id && device->enabled()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500842 device->SetEnabledPersistent(false, error, callback);
843 // Continue with other devices even if one fails
844 // TODO(ers): Decide whether an error should be returned
845 // for the overall DisableTechnology operation if some
846 // devices succeed and some fail.
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400847 if (error->IsOngoing())
848 deferred = true;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500849 }
850 }
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400851 // If no device has deferred work, then clear the error to
852 // communicate to the caller that all work is done.
853 if (!deferred)
854 error->Reset();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500855}
856
857void Manager::UpdateEnabledTechnologies() {
858 Error error;
859 adaptor_->EmitStringsChanged(flimflam::kEnabledTechnologiesProperty,
860 EnabledTechnologies(&error));
861}
862
Ben Chan5086b972013-01-15 21:51:38 -0800863void Manager::UpdateUninitializedTechnologies() {
864 Error error;
865 adaptor_->EmitStringsChanged(kUninitializedTechnologiesProperty,
866 UninitializedTechnologies(&error));
867}
868
Chris Masone2b105542011-06-22 10:58:09 -0700869void Manager::RegisterDevice(const DeviceRefPtr &to_manage) {
Darin Petkove7c6ad32012-06-29 10:22:09 +0200870 LOG(INFO) << "Device " << to_manage->FriendlyName() << " registered.";
871 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
872 it != devices_.end(); ++it) {
Chris Masonec1e50412011-06-07 13:04:53 -0700873 if (to_manage.get() == it->get())
Chris Masone9be4a9d2011-05-16 15:44:09 -0700874 return;
875 }
Chris Masonec1e50412011-06-07 13:04:53 -0700876 devices_.push_back(to_manage);
Paul Stewartf1ce5d22011-05-19 13:10:20 -0700877
Paul Stewart87a4ae82012-10-26 15:49:32 -0700878 LoadDeviceFromProfiles(to_manage);
Paul Stewarta41e38d2011-11-11 07:47:29 -0800879
Darin Petkove7c6ad32012-06-29 10:22:09 +0200880 // If |to_manage| is new, it needs to be persisted.
881 UpdateDevice(to_manage);
882
Paul Stewarta41e38d2011-11-11 07:47:29 -0800883 // In normal usage, running_ will always be true when we are here, however
884 // unit tests sometimes do things in otherwise invalid states.
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400885 if (running_ && (to_manage->enabled_persistent() ||
886 to_manage->IsUnderlyingDeviceEnabled()))
Eric Shienbrood9a245532012-03-07 14:20:39 -0500887 to_manage->SetEnabled(true);
Gaurav Shah435de2c2011-11-17 19:01:07 -0800888
Eric Shienbrood8839a892012-03-29 10:33:48 -0400889 EmitDeviceProperties();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700890}
891
mukesh agrawal5029c6c2011-08-25 11:12:40 -0700892void Manager::DeregisterDevice(const DeviceRefPtr &to_forget) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700893 SLOG(Manager, 2) << __func__ << "(" << to_forget->FriendlyName() << ")";
Chris Masonec1e50412011-06-07 13:04:53 -0700894 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700895 for (it = devices_.begin(); it != devices_.end(); ++it) {
Chris Masonec1e50412011-06-07 13:04:53 -0700896 if (to_forget.get() == it->get()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700897 SLOG(Manager, 2) << "Deregistered device: " << to_forget->UniqueName();
Paul Stewart212d60f2012-07-12 10:59:13 -0700898 UpdateDevice(to_forget);
Eric Shienbrood9a245532012-03-07 14:20:39 -0500899 to_forget->SetEnabled(false);
Chris Masone9be4a9d2011-05-16 15:44:09 -0700900 devices_.erase(it);
Eric Shienbrood8839a892012-03-29 10:33:48 -0400901 EmitDeviceProperties();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700902 return;
903 }
904 }
Ben Chanfad4a0b2012-04-18 15:49:59 -0700905 SLOG(Manager, 2) << __func__ << " unknown device: "
906 << to_forget->UniqueName();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700907}
908
Paul Stewart87a4ae82012-10-26 15:49:32 -0700909void Manager::LoadDeviceFromProfiles(const DeviceRefPtr &device) {
910 // We are applying device properties from the DefaultProfile, and adding the
911 // union of hidden services in all loaded profiles to the device.
912 for (vector<ProfileRefPtr>::iterator it = profiles_.begin();
913 it != profiles_.end(); ++it) {
914 // Load device configuration, if any exists, as well as hidden services.
915 (*it)->ConfigureDevice(device);
916 }
917}
918
Eric Shienbrood8839a892012-03-29 10:33:48 -0400919void Manager::EmitDeviceProperties() {
920 vector<DeviceRefPtr>::iterator it;
921 vector<string> device_paths;
922 for (it = devices_.begin(); it != devices_.end(); ++it) {
923 device_paths.push_back((*it)->GetRpcIdentifier());
924 }
925 adaptor_->EmitRpcIdentifierArrayChanged(flimflam::kDevicesProperty,
926 device_paths);
927 Error error;
928 adaptor_->EmitStringsChanged(flimflam::kAvailableTechnologiesProperty,
929 AvailableTechnologies(&error));
930 adaptor_->EmitStringsChanged(flimflam::kEnabledTechnologiesProperty,
931 EnabledTechnologies(&error));
Ben Chan5086b972013-01-15 21:51:38 -0800932 adaptor_->EmitStringsChanged(kUninitializedTechnologiesProperty,
933 UninitializedTechnologies(&error));
Eric Shienbrood8839a892012-03-29 10:33:48 -0400934}
935
mukesh agrawal4eb4d782011-12-05 17:34:37 +0000936bool Manager::HasService(const ServiceRefPtr &service) {
937 vector<ServiceRefPtr>::iterator it;
938 for (it = services_.begin(); it != services_.end(); ++it) {
Darin Petkov457728b2013-01-09 09:49:08 +0100939 if ((*it)->unique_name() == service->unique_name())
mukesh agrawal4eb4d782011-12-05 17:34:37 +0000940 return true;
941 }
942 return false;
943}
944
Chris Masone2b105542011-06-22 10:58:09 -0700945void Manager::RegisterService(const ServiceRefPtr &to_manage) {
Darin Petkov457728b2013-01-09 09:49:08 +0100946 SLOG(Manager, 2) << "Registering service " << to_manage->unique_name();
mukesh agrawald835b202011-10-07 15:26:47 -0700947
Paul Stewart75225512012-01-26 22:51:33 -0800948 MatchProfileWithService(to_manage);
Chris Masone6791a432011-07-12 13:23:19 -0700949
950 // Now add to OUR list.
Chris Masonec1e50412011-06-07 13:04:53 -0700951 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700952 for (it = services_.begin(); it != services_.end(); ++it) {
Darin Petkov457728b2013-01-09 09:49:08 +0100953 CHECK(to_manage->unique_name() != (*it)->unique_name());
Chris Masone9be4a9d2011-05-16 15:44:09 -0700954 }
Chris Masonec1e50412011-06-07 13:04:53 -0700955 services_.push_back(to_manage);
Paul Stewart22aa71b2011-09-16 12:15:11 -0700956 SortServices();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700957}
958
Chris Masone6515aab2011-10-12 16:19:09 -0700959void Manager::DeregisterService(const ServiceRefPtr &to_forget) {
Chris Masonec1e50412011-06-07 13:04:53 -0700960 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700961 for (it = services_.begin(); it != services_.end(); ++it) {
Darin Petkov457728b2013-01-09 09:49:08 +0100962 if (to_forget->unique_name() == (*it)->unique_name()) {
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800963 DCHECK(!(*it)->connection());
Paul Stewartfc9a1da2012-06-27 15:54:52 -0700964 (*it)->Unload();
Philipp Neubeck79173602012-11-13 21:10:09 +0100965 (*it)->SetProfile(NULL);
Chris Masone9be4a9d2011-05-16 15:44:09 -0700966 services_.erase(it);
Paul Stewart22aa71b2011-09-16 12:15:11 -0700967 SortServices();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700968 return;
969 }
970 }
971}
972
Paul Stewart65512e12012-03-26 18:01:08 -0700973bool Manager::UnloadService(vector<ServiceRefPtr>::iterator *service_iterator) {
974 if (!(**service_iterator)->Unload()) {
975 return false;
976 }
977
978 DCHECK(!(**service_iterator)->connection());
Philipp Neubeck79173602012-11-13 21:10:09 +0100979 (**service_iterator)->SetProfile(NULL);
Paul Stewart65512e12012-03-26 18:01:08 -0700980 *service_iterator = services_.erase(*service_iterator);
981
982 return true;
983}
984
mukesh agrawal00917ce2011-11-22 23:56:55 +0000985void Manager::UpdateService(const ServiceRefPtr &to_update) {
986 CHECK(to_update);
Darin Petkov457728b2013-01-09 09:49:08 +0100987 LOG(INFO) << "Service " << to_update->unique_name() << " updated;"
Gaurav Shahc6d6c722011-11-17 18:59:39 -0800988 << " state: " << Service::ConnectStateToString(to_update->state())
989 << " failure: "
990 << Service::ConnectFailureToString(to_update->failure());
Ben Chanfad4a0b2012-04-18 15:49:59 -0700991 SLOG(Manager, 2) << "IsConnected(): " << to_update->IsConnected();
992 SLOG(Manager, 2) << "IsConnecting(): " << to_update->IsConnecting();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800993 if (to_update->IsConnected()) {
mukesh agrawal00917ce2011-11-22 23:56:55 +0000994 to_update->MakeFavorite();
Gary Moraind93615e2012-04-27 11:50:03 -0700995 // Persists the updated favorite setting in the profile.
996 SaveServiceToProfile(to_update);
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800997 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700998 SortServices();
Paul Stewart03dba0b2011-08-22 16:32:45 -0700999}
1000
Darin Petkove7c6ad32012-06-29 10:22:09 +02001001void Manager::UpdateDevice(const DeviceRefPtr &to_update) {
1002 LOG(INFO) << "Device " << to_update->link_name() << " updated: "
1003 << (to_update->enabled_persistent() ? "enabled" : "disabled");
Wade Guthrie60a37062013-04-02 11:39:09 -07001004 // Saves the device to the topmost profile that accepts it (ordinary
1005 // profiles don't update but default profiles do). Normally, the topmost
1006 // updating profile would be the DefaultProfile at the bottom of the stack.
1007 // Autotests, differ from the normal scenario, however, in that they push a
1008 // second test-only DefaultProfile.
Darin Petkove7c6ad32012-06-29 10:22:09 +02001009 for (vector<ProfileRefPtr>::reverse_iterator rit = profiles_.rbegin();
1010 rit != profiles_.rend(); ++rit) {
1011 if ((*rit)->UpdateDevice(to_update)) {
1012 return;
1013 }
1014 }
1015}
1016
Wade Guthrie60a37062013-04-02 11:39:09 -07001017void Manager::UpdateWiFiProvider() {
1018 // Saves |wifi_provider_| to the topmost profile that accepts it (ordinary
1019 // profiles don't update but default profiles do). Normally, the topmost
1020 // updating profile would be the DefaultProfile at the bottom of the stack.
1021 // Autotests, differ from the normal scenario, however, in that they push a
1022 // second test-only DefaultProfile.
1023 for (vector<ProfileRefPtr>::reverse_iterator rit = profiles_.rbegin();
1024 rit != profiles_.rend(); ++rit) {
1025 if ((*rit)->UpdateWiFiProvider(*wifi_provider_)) {
1026 return;
1027 }
1028 }
1029}
1030
Gary Moraind93615e2012-04-27 11:50:03 -07001031void Manager::SaveServiceToProfile(const ServiceRefPtr &to_update) {
1032 if (IsServiceEphemeral(to_update)) {
1033 if (profiles_.empty()) {
1034 LOG(ERROR) << "Cannot assign profile to service: no profiles exist!";
1035 } else {
1036 MoveServiceToProfile(to_update, profiles_.back());
1037 }
1038 } else {
1039 to_update->profile()->UpdateService(to_update);
1040 }
1041}
1042
Paul Stewart4d5efb72012-09-17 12:24:34 -07001043bool Manager::LoadProperties(const scoped_refptr<DefaultProfile> &profile) {
1044 if (!profile->LoadManagerProperties(&props_)) {
1045 return false;
1046 }
1047 SetIgnoredDNSSearchPaths(props_.ignored_dns_search_paths, NULL);
1048 return true;
1049}
1050
Darin Petkov3ec55342012-09-28 14:04:44 +02001051void Manager::AddTerminationAction(const string &name,
Gary Moraina9fb3252012-05-31 12:05:31 -07001052 const base::Closure &start) {
Darin Petkov3ec55342012-09-28 14:04:44 +02001053 if (termination_actions_.IsEmpty() && power_manager_.get()) {
1054 power_manager_->AddSuspendDelayCallback(
1055 kPowerManagerKey,
Daniel Erat0818cca2012-12-14 10:16:21 -08001056 Bind(&Manager::OnSuspendImminent, AsWeakPtr()));
1057 CHECK(!suspend_delay_registered_);
1058 suspend_delay_registered_ = power_manager_->RegisterSuspendDelay(
1059 base::TimeDelta::FromMilliseconds(
1060 kTerminationActionsTimeoutMilliseconds),
Daniel Eratf9753672013-01-24 10:17:02 -08001061 kSuspendDelayDescription,
Daniel Erat0818cca2012-12-14 10:16:21 -08001062 &suspend_delay_id_);
Darin Petkov3ec55342012-09-28 14:04:44 +02001063 }
Gary Moraina9fb3252012-05-31 12:05:31 -07001064 termination_actions_.Add(name, start);
1065}
1066
Darin Petkov3ec55342012-09-28 14:04:44 +02001067void Manager::TerminationActionComplete(const string &name) {
Gary Moraina9fb3252012-05-31 12:05:31 -07001068 termination_actions_.ActionComplete(name);
1069}
1070
Darin Petkov3ec55342012-09-28 14:04:44 +02001071void Manager::RemoveTerminationAction(const string &name) {
1072 if (termination_actions_.IsEmpty()) {
1073 return;
1074 }
Gary Moraina9fb3252012-05-31 12:05:31 -07001075 termination_actions_.Remove(name);
Darin Petkov3ec55342012-09-28 14:04:44 +02001076 if (termination_actions_.IsEmpty() && power_manager_.get()) {
Daniel Erat0818cca2012-12-14 10:16:21 -08001077 if (suspend_delay_registered_) {
1078 power_manager_->UnregisterSuspendDelay(suspend_delay_id_);
1079 suspend_delay_registered_ = false;
1080 suspend_delay_id_ = 0;
1081 }
Darin Petkov3ec55342012-09-28 14:04:44 +02001082 power_manager_->RemoveSuspendDelayCallback(kPowerManagerKey);
1083 }
Gary Moraina9fb3252012-05-31 12:05:31 -07001084}
1085
1086void Manager::RunTerminationActions(
Darin Petkov3ec55342012-09-28 14:04:44 +02001087 const base::Callback<void(const Error &)> &done) {
1088 LOG(INFO) << "Running termination actions.";
1089 termination_actions_.Run(kTerminationActionsTimeoutMilliseconds, done);
Gary Moraina9fb3252012-05-31 12:05:31 -07001090}
1091
Arman Ugurayab22c162012-10-08 19:08:38 -07001092bool Manager::RunTerminationActionsAndNotifyMetrics(
1093 const base::Callback<void(const Error &)> &done,
1094 Metrics::TerminationActionReason reason) {
1095 if (termination_actions_.IsEmpty())
1096 return false;
1097
1098 metrics_->NotifyTerminationActionsStarted(reason);
1099 RunTerminationActions(done);
1100 return true;
1101}
1102
Darin Petkova5e07ef2012-07-09 14:27:57 +02001103int Manager::RegisterDefaultServiceCallback(const ServiceCallback &callback) {
1104 default_service_callbacks_[++default_service_callback_tag_] = callback;
1105 return default_service_callback_tag_;
1106}
1107
1108void Manager::DeregisterDefaultServiceCallback(int tag) {
1109 default_service_callbacks_.erase(tag);
1110}
1111
Christopher Wiley0d9cf0c2013-02-19 19:24:57 -08001112void Manager::VerifyDestination(const string &certificate,
1113 const string &public_key,
1114 const string &nonce,
1115 const string &signed_data,
1116 const string &destination_udn,
Christopher Wileycdde79f2013-05-01 14:26:56 -07001117 const string &hotspot_ssid,
1118 const string &hotspot_bssid,
Christopher Wiley0d9cf0c2013-02-19 19:24:57 -08001119 const ResultBoolCallback &cb,
1120 Error *error) {
Christopher Wileycdde79f2013-05-01 14:26:56 -07001121 if (hotspot_bssid.length() > 32) {
1122 error->Populate(Error::kOperationFailed,
1123 "Invalid SSID given for verification.");
1124 return;
1125 }
Christopher Wiley83889862013-05-02 15:55:09 -07001126 vector<uint8_t> ssid;
1127 string bssid;
Christopher Wileycdde79f2013-05-01 14:26:56 -07001128 if (hotspot_ssid.length() || hotspot_bssid.length()) {
Christopher Wiley83889862013-05-02 15:55:09 -07001129 // If Chrome thinks this destination is already configured, service
1130 // will be an AP that both we and the destination are connected
1131 // to, and not the thing we should verify against.
Christopher Wileycdde79f2013-05-01 14:26:56 -07001132 ssid.assign(hotspot_ssid.begin(), hotspot_ssid.end());
1133 bssid = hotspot_bssid;
Christopher Wiley83889862013-05-02 15:55:09 -07001134 } else {
1135 // For now, we only support a single connected WiFi service. If we change
1136 // that, we'll need to revisit this.
1137 bool found_one = false;
1138 for (const auto &service : services_) {
1139 if (service->technology() == Technology::kWifi &&
1140 service->IsConnected()) {
1141 WiFiService *wifi = reinterpret_cast<WiFiService *>(&(*service));
1142 bssid = wifi->bssid();
1143 ssid = wifi->ssid();
1144 found_one = true;
1145 break;
1146 }
1147 }
1148 if (!found_one) {
1149 error->Populate(Error::kOperationFailed,
1150 "Unable to find connected WiFi service.");
1151 return;
1152
1153 }
Christopher Wileycdde79f2013-05-01 14:26:56 -07001154 }
Christopher Wiley1057cd72013-02-28 15:21:29 -08001155 crypto_util_proxy_->VerifyDestination(certificate, public_key, nonce,
1156 signed_data, destination_udn,
Christopher Wiley83889862013-05-02 15:55:09 -07001157 ssid, bssid, cb, error);
Christopher Wiley1057cd72013-02-28 15:21:29 -08001158}
1159
1160void Manager::VerifyToEncryptLink(string public_key,
1161 string data,
1162 ResultStringCallback cb,
1163 const Error &error,
1164 bool success) {
1165 if (!success || !error.IsSuccess()) {
1166 CHECK(error.IsFailure()) << "Return code from CryptoUtilProxy "
1167 << "inconsistent with error code.";
1168 cb.Run(error, "");
1169 return;
1170 }
1171 Error encrypt_error;
1172 if (!crypto_util_proxy_->EncryptData(public_key, data, cb, &encrypt_error)) {
Christopher Wileyb3e70d22013-04-26 17:28:37 -07001173 CHECK(encrypt_error.IsFailure()) << "CryptoUtilProxy::EncryptData returned "
1174 << "inconsistently.";
1175 cb.Run(encrypt_error, "");
Christopher Wiley1057cd72013-02-28 15:21:29 -08001176 }
Christopher Wiley0d9cf0c2013-02-19 19:24:57 -08001177}
1178
1179void Manager::VerifyAndEncryptData(const string &certificate,
1180 const string &public_key,
1181 const string &nonce,
1182 const string &signed_data,
1183 const string &destination_udn,
Christopher Wileycdde79f2013-05-01 14:26:56 -07001184 const string &hotspot_ssid,
1185 const string &hotspot_bssid,
Christopher Wiley0d9cf0c2013-02-19 19:24:57 -08001186 const string &data,
1187 const ResultStringCallback &cb,
1188 Error *error) {
Christopher Wiley1057cd72013-02-28 15:21:29 -08001189 ResultBoolCallback on_verification_success = Bind(
1190 &Manager::VerifyToEncryptLink, AsWeakPtr(), public_key, data, cb);
1191 VerifyDestination(certificate, public_key, nonce, signed_data,
Christopher Wileycdde79f2013-05-01 14:26:56 -07001192 destination_udn, hotspot_ssid, hotspot_bssid,
1193 on_verification_success, error);
Christopher Wiley0d9cf0c2013-02-19 19:24:57 -08001194}
1195
1196void Manager::VerifyAndEncryptCredentials(const string &certificate,
1197 const string &public_key,
1198 const string &nonce,
1199 const string &signed_data,
1200 const string &destination_udn,
Christopher Wileycdde79f2013-05-01 14:26:56 -07001201 const string &hotspot_ssid,
1202 const string &hotspot_bssid,
Christopher Wiley0d9cf0c2013-02-19 19:24:57 -08001203 const string &network_path,
1204 const ResultStringCallback &cb,
1205 Error *error) {
Christopher Wiley1057cd72013-02-28 15:21:29 -08001206 // This is intentionally left unimplemented until we have a security review.
Christopher Wiley0d9cf0c2013-02-19 19:24:57 -08001207 error->Populate(Error::kNotImplemented, "Not implemented");
1208}
1209
Darin Petkova5e07ef2012-07-09 14:27:57 +02001210void Manager::NotifyDefaultServiceChanged(const ServiceRefPtr &service) {
1211 for (map<int, ServiceCallback>::const_iterator it =
1212 default_service_callbacks_.begin();
1213 it != default_service_callbacks_.end(); ++it) {
1214 it->second.Run(service);
1215 }
1216 metrics_->NotifyDefaultServiceChanged(service);
Paul Stewart49739c02012-08-08 17:24:03 -07001217 EmitDefaultService();
1218}
1219
1220void Manager::EmitDefaultService() {
1221 RpcIdentifier rpc_identifier = GetDefaultServiceRpcIdentifier(NULL);
1222 if (rpc_identifier != default_service_rpc_identifier_) {
1223 adaptor_->EmitRpcIdentifierChanged(shill::kDefaultServiceProperty,
1224 rpc_identifier);
1225 default_service_rpc_identifier_ = rpc_identifier;
1226 }
Darin Petkova5e07ef2012-07-09 14:27:57 +02001227}
1228
Darin Petkovca621542012-07-25 14:25:56 +02001229void Manager::OnPowerStateChanged(
1230 PowerManagerProxyDelegate::SuspendState power_state) {
1231 if (power_state == PowerManagerProxyDelegate::kOn) {
Christopher Wiley0801d192012-09-24 11:57:15 -07001232 vector<ServiceRefPtr>::iterator sit;
1233 for (sit = services_.begin(); sit != services_.end(); ++sit) {
1234 (*sit)->OnAfterResume();
1235 }
Darin Petkovca621542012-07-25 14:25:56 +02001236 SortServices();
mukesh agrawal784566d2012-08-08 18:32:58 -07001237 vector<DeviceRefPtr>::iterator it;
1238 for (it = devices_.begin(); it != devices_.end(); ++it) {
1239 (*it)->OnAfterResume();
1240 }
1241 } else if (power_state == PowerManagerProxyDelegate::kMem) {
1242 vector<DeviceRefPtr>::iterator it;
1243 for (it = devices_.begin(); it != devices_.end(); ++it) {
1244 (*it)->OnBeforeSuspend();
1245 }
Darin Petkovca621542012-07-25 14:25:56 +02001246 }
1247}
1248
Daniel Erat0818cca2012-12-14 10:16:21 -08001249void Manager::OnSuspendImminent(int suspend_id) {
Arman Ugurayab22c162012-10-08 19:08:38 -07001250 if (!RunTerminationActionsAndNotifyMetrics(
Daniel Erat0818cca2012-12-14 10:16:21 -08001251 Bind(&Manager::OnSuspendActionsComplete, AsWeakPtr(), suspend_id),
Arman Ugurayab22c162012-10-08 19:08:38 -07001252 Metrics::kTerminationActionReasonSuspend)) {
1253 LOG(INFO) << "No suspend actions were run.";
Daniel Erat0818cca2012-12-14 10:16:21 -08001254 power_manager_->ReportSuspendReadiness(suspend_delay_id_, suspend_id);
Arman Ugurayab22c162012-10-08 19:08:38 -07001255 }
Darin Petkov3ec55342012-09-28 14:04:44 +02001256}
1257
Daniel Erat0818cca2012-12-14 10:16:21 -08001258void Manager::OnSuspendActionsComplete(int suspend_id, const Error &error) {
Darin Petkov3ec55342012-09-28 14:04:44 +02001259 LOG(INFO) << "Finished suspend actions. Result: " << error;
Arman Ugurayab22c162012-10-08 19:08:38 -07001260 metrics_->NotifyTerminationActionsCompleted(
1261 Metrics::kTerminationActionReasonSuspend, error.IsSuccess());
Daniel Erat0818cca2012-12-14 10:16:21 -08001262 power_manager_->ReportSuspendReadiness(suspend_delay_id_, suspend_id);
Darin Petkov3ec55342012-09-28 14:04:44 +02001263}
1264
Paul Stewartfdd16072011-09-16 12:41:35 -07001265void Manager::FilterByTechnology(Technology::Identifier tech,
Paul Stewart3c504012013-01-17 17:49:58 -08001266 vector<DeviceRefPtr> *found) const {
Chris Masone9be4a9d2011-05-16 15:44:09 -07001267 CHECK(found);
Paul Stewart3c504012013-01-17 17:49:58 -08001268 vector<DeviceRefPtr>::const_iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -07001269 for (it = devices_.begin(); it != devices_.end(); ++it) {
Joshua Krollda798622012-06-05 12:30:48 -07001270 if ((*it)->technology() == tech)
Chris Masone9be4a9d2011-05-16 15:44:09 -07001271 found->push_back(*it);
1272 }
1273}
1274
Darin Petkov457728b2013-01-09 09:49:08 +01001275ServiceRefPtr Manager::FindService(const string &name) {
Chris Masonec1e50412011-06-07 13:04:53 -07001276 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -07001277 for (it = services_.begin(); it != services_.end(); ++it) {
Darin Petkov457728b2013-01-09 09:49:08 +01001278 if (name == (*it)->unique_name())
Chris Masonee0dea762011-06-09 09:06:03 -07001279 return *it;
Chris Masone9be4a9d2011-05-16 15:44:09 -07001280 }
Chris Masonee0dea762011-06-09 09:06:03 -07001281 return NULL;
Chris Masone9be4a9d2011-05-16 15:44:09 -07001282}
1283
Paul Stewart49739c02012-08-08 17:24:03 -07001284void Manager::HelpRegisterConstDerivedRpcIdentifier(
1285 const string &name,
1286 RpcIdentifier(Manager::*get)(Error *error)) {
1287 store_.RegisterDerivedRpcIdentifier(
1288 name,
1289 RpcIdentifierAccessor(
1290 new CustomAccessor<Manager, RpcIdentifier>(this, get, NULL)));
1291}
1292
mukesh agrawal2366eed2012-03-20 18:21:50 -07001293void Manager::HelpRegisterConstDerivedRpcIdentifiers(
1294 const string &name,
Jason Glasgowdf7c5532012-05-14 14:41:45 -04001295 RpcIdentifiers(Manager::*get)(Error *error)) {
mukesh agrawal2366eed2012-03-20 18:21:50 -07001296 store_.RegisterDerivedRpcIdentifiers(
1297 name,
1298 RpcIdentifiersAccessor(
1299 new CustomAccessor<Manager, RpcIdentifiers>(this, get, NULL)));
1300}
1301
mukesh agrawalffa3d042011-10-06 15:26:10 -07001302void Manager::HelpRegisterDerivedString(
1303 const string &name,
Gaurav Shah1b7a6162011-11-09 11:41:01 -08001304 string(Manager::*get)(Error *),
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001305 bool(Manager::*set)(const string&, Error *)) {
Chris Masone27c4aa52011-07-02 13:10:14 -07001306 store_.RegisterDerivedString(
1307 name,
1308 StringAccessor(new CustomAccessor<Manager, string>(this, get, set)));
Chris Masoneb925cc82011-06-22 15:39:57 -07001309}
1310
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001311void Manager::HelpRegisterConstDerivedStrings(
mukesh agrawalffa3d042011-10-06 15:26:10 -07001312 const string &name,
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001313 Strings(Manager::*get)(Error *)) {
Chris Masone27c4aa52011-07-02 13:10:14 -07001314 store_.RegisterDerivedStrings(
1315 name,
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001316 StringsAccessor(new CustomAccessor<Manager, Strings>(this, get, NULL)));
Chris Masoneb925cc82011-06-22 15:39:57 -07001317}
1318
Paul Stewart22aa71b2011-09-16 12:15:11 -07001319void Manager::SortServices() {
Paul Stewartdfa46052012-06-26 09:44:14 -07001320 // We might be called in the middle of a series of events that
1321 // may result in multiple calls to Manager::SortServices, or within
1322 // an outer loop that may also be traversing the services_ list.
1323 // Defer this work to the event loop.
1324 if (sort_services_task_.IsCancelled()) {
1325 sort_services_task_.Reset(Bind(&Manager::SortServicesTask, AsWeakPtr()));
1326 dispatcher_->PostTask(sort_services_task_.callback());
1327 }
1328}
1329
1330void Manager::SortServicesTask() {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001331 SLOG(Manager, 4) << "In " << __func__;
Paul Stewartdfa46052012-06-26 09:44:14 -07001332 sort_services_task_.Cancel();
Thieu Lea20cbc22012-01-09 22:01:43 +00001333 ServiceRefPtr default_service;
1334
Paul Stewartc1dec4d2011-12-08 15:25:28 -08001335 if (!services_.empty()) {
Paul Stewarte2bad7c2012-03-14 08:55:33 -07001336 // Keep track of the service that is the candidate for the default
1337 // service. We have not yet tested to see if this service has a
1338 // connection.
Thieu Lea20cbc22012-01-09 22:01:43 +00001339 default_service = services_[0];
Paul Stewartc1dec4d2011-12-08 15:25:28 -08001340 }
Paul Stewart39db5ca2013-03-18 14:15:17 -07001341 const bool kCompareConnectivityState = true;
1342 sort(services_.begin(), services_.end(),
1343 ServiceSorter(kCompareConnectivityState, technology_order_));
Paul Stewarta41e38d2011-11-11 07:47:29 -08001344
Paul Stewarta41e38d2011-11-11 07:47:29 -08001345 adaptor_->EmitRpcIdentifierArrayChanged(flimflam::kServicesProperty,
Paul Stewartbfb82552012-10-24 16:48:48 -07001346 EnumerateAvailableServices(NULL));
1347 adaptor_->EmitRpcIdentifierArrayChanged(flimflam::kServiceWatchListProperty,
1348 EnumerateWatchedServices(NULL));
Gaurav Shah435de2c2011-11-17 19:01:07 -08001349
1350 Error error;
1351 adaptor_->EmitStringsChanged(flimflam::kConnectedTechnologiesProperty,
1352 ConnectedTechnologies(&error));
1353 adaptor_->EmitStringChanged(flimflam::kDefaultTechnologyProperty,
1354 DefaultTechnology(&error));
Paul Stewartc1dec4d2011-12-08 15:25:28 -08001355
1356 if (!services_.empty()) {
Thieu Lea20cbc22012-01-09 22:01:43 +00001357 ConnectionRefPtr default_connection = default_service->connection();
Darin Petkova5e07ef2012-07-09 14:27:57 +02001358 if (default_connection &&
1359 services_[0]->connection() != default_connection) {
Paul Stewartc1dec4d2011-12-08 15:25:28 -08001360 default_connection->SetIsDefault(false);
1361 }
Darin Petkova5e07ef2012-07-09 14:27:57 +02001362 if (services_[0]->connection()) {
Paul Stewartc1dec4d2011-12-08 15:25:28 -08001363 services_[0]->connection()->SetIsDefault(true);
Paul Stewart8596f9f2013-03-14 07:58:26 -07001364 if (default_service != services_[0]) {
1365 default_service = services_[0];
1366 LOG(INFO) << "Default service is now "
1367 << default_service->unique_name();
1368 }
Paul Stewarte2bad7c2012-03-14 08:55:33 -07001369 } else {
1370 default_service = NULL;
Paul Stewartc1dec4d2011-12-08 15:25:28 -08001371 }
1372 }
Darin Petkova5e07ef2012-07-09 14:27:57 +02001373 NotifyDefaultServiceChanged(default_service);
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001374 AutoConnect();
1375}
1376
Paul Stewart75225512012-01-26 22:51:33 -08001377bool Manager::MatchProfileWithService(const ServiceRefPtr &service) {
1378 vector<ProfileRefPtr>::reverse_iterator it;
1379 for (it = profiles_.rbegin(); it != profiles_.rend(); ++it) {
1380 if ((*it)->ConfigureService(service)) {
1381 break;
1382 }
1383 }
1384 if (it == profiles_.rend()) {
1385 ephemeral_profile_->AdoptService(service);
1386 return false;
1387 }
1388 return true;
1389}
1390
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001391void Manager::AutoConnect() {
Paul Stewart63864b62012-11-07 15:10:55 -08001392 if (!running_) {
1393 LOG(INFO) << "Auto-connect suppressed -- not running.";
1394 return;
1395 }
Darin Petkovca621542012-07-25 14:25:56 +02001396 if (power_manager_.get() &&
1397 power_manager_->power_state() != PowerManagerProxyDelegate::kOn &&
1398 power_manager_->power_state() != PowerManagerProxyDelegate::kUnknown) {
1399 LOG(INFO) << "Auto-connect suppressed -- power state is not 'on'.";
1400 return;
1401 }
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001402 if (services_.empty()) {
Darin Petkovca621542012-07-25 14:25:56 +02001403 LOG(INFO) << "Auto-connect suppressed -- no services.";
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001404 return;
1405 }
1406
Ben Chanfad4a0b2012-04-18 15:49:59 -07001407 if (SLOG_IS_ON(Manager, 4)) {
1408 SLOG(Manager, 4) << "Sorted service list: ";
mukesh agrawalddc378f2012-02-17 18:26:20 -08001409 for (size_t i = 0; i < services_.size(); ++i) {
1410 ServiceRefPtr service = services_[i];
1411 const char *compare_reason = NULL;
1412 if (i + 1 < services_.size()) {
Paul Stewart39db5ca2013-03-18 14:15:17 -07001413 const bool kCompareConnectivityState = true;
mukesh agrawalddc378f2012-02-17 18:26:20 -08001414 Service::Compare(
Paul Stewart39db5ca2013-03-18 14:15:17 -07001415 service, services_[i+1], kCompareConnectivityState,
1416 technology_order_, &compare_reason);
mukesh agrawalddc378f2012-02-17 18:26:20 -08001417 } else {
mukesh agrawalbf14e942012-03-02 14:36:34 -08001418 compare_reason = "last";
mukesh agrawalddc378f2012-02-17 18:26:20 -08001419 }
Darin Petkov457728b2013-01-09 09:49:08 +01001420 SLOG(Manager, 4) << "Service " << service->unique_name()
Ben Chanfad4a0b2012-04-18 15:49:59 -07001421 << " IsConnected: " << service->IsConnected()
1422 << " IsConnecting: " << service->IsConnecting()
1423 << " IsFailed: " << service->IsFailed()
1424 << " connectable: " << service->connectable()
1425 << " auto_connect: " << service->auto_connect()
1426 << " favorite: " << service->favorite()
1427 << " priority: " << service->priority()
mukesh agrawal43970a22013-02-15 16:00:07 -08001428 << " crypto_algorithm: " << service->crypto_algorithm()
1429 << " key_rotation: " << service->key_rotation()
1430 << " endpoint_auth: " << service->endpoint_auth()
Ben Chanfad4a0b2012-04-18 15:49:59 -07001431 << " strength: " << service->strength()
Ben Chanfad4a0b2012-04-18 15:49:59 -07001432 << " sorted: " << compare_reason;
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001433 }
1434 }
1435
Paul Stewart3d9bcf52011-12-12 15:02:22 -08001436 // Perform auto-connect.
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001437 for (vector<ServiceRefPtr>::iterator it = services_.begin();
1438 it != services_.end(); ++it) {
1439 if ((*it)->auto_connect()) {
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001440 (*it)->AutoConnect();
Paul Stewart3d9bcf52011-12-12 15:02:22 -08001441 }
1442 }
Paul Stewart22aa71b2011-09-16 12:15:11 -07001443}
1444
Paul Stewart39db5ca2013-03-18 14:15:17 -07001445void Manager::ConnectToBestServices(Error */*error*/) {
1446 dispatcher_->PostTask(Bind(&Manager::ConnectToBestServicesTask, AsWeakPtr()));
1447}
1448
1449void Manager::ConnectToBestServicesTask() {
1450 vector<ServiceRefPtr> services_copy = services_;
1451 const bool kCompareConnectivityState = false;
1452 sort(services_copy.begin(), services_copy.end(),
1453 ServiceSorter(kCompareConnectivityState, technology_order_));
1454 set<Technology::Identifier> connecting_technologies;
1455 for (vector<ServiceRefPtr>::const_iterator it = services_copy.begin();
1456 it != services_copy.end();
1457 ++it) {
1458 if (!(*it)->connectable()) {
1459 // Due to service sort order, it is guaranteed that no services beyond
1460 // this one will be connectable either.
1461 break;
1462 }
Paul Stewartf7d7d3f2013-04-24 14:47:44 -07001463 if (!(*it)->auto_connect() || !(*it)->IsVisible()) {
Paul Stewart39db5ca2013-03-18 14:15:17 -07001464 continue;
1465 }
1466 Technology::Identifier technology = (*it)->technology();
1467 if (!Technology::IsPrimaryConnectivityTechnology(technology) &&
1468 !IsOnline()) {
1469 // Non-primary services need some other service connected first.
1470 continue;
1471 }
1472 if (ContainsKey(connecting_technologies, technology)) {
1473 // We have already started a connection for this technology.
1474 continue;
1475 }
1476 connecting_technologies.insert(technology);
1477 if (!(*it)->IsConnected() && !(*it)->IsConnecting()) {
1478 // At first blush, it may seem that using Service::AutoConnect might
1479 // be the right choice, however Service::IsAutoConnectable and its
1480 // overridden implementations consider a host of conditions which
1481 // prevent it from attempting a connection which we'd like to ignore
1482 // for the purposes of this user-initiated action.
1483 Error error;
mukesh agrawaldc7b8442012-09-27 13:48:14 -07001484 (*it)->Connect(&error, __func__);
Paul Stewart39db5ca2013-03-18 14:15:17 -07001485 if (error.IsFailure()) {
1486 LOG(ERROR) << "Connection failed: " << error.message();
1487 }
1488 }
1489 }
1490}
1491
Darin Petkov4cbff5b2013-01-29 16:29:05 +01001492bool Manager::IsOnline() const {
Gary Morain028545d2012-04-07 14:55:52 -07001493 // |services_| is sorted such that connected services are first.
Darin Petkov4cbff5b2013-01-29 16:29:05 +01001494 return !services_.empty() && services_.front()->IsConnected();
1495}
1496
1497string Manager::CalculateState(Error */*error*/) {
1498 return IsOnline() ? flimflam::kStateOnline : flimflam::kStateOffline;
Chris Masoneb925cc82011-06-22 15:39:57 -07001499}
1500
Gaurav Shah1b7a6162011-11-09 11:41:01 -08001501vector<string> Manager::AvailableTechnologies(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -08001502 set<string> unique_technologies;
1503 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1504 it != devices_.end(); ++it) {
1505 unique_technologies.insert(
1506 Technology::NameFromIdentifier((*it)->technology()));
1507 }
1508 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -07001509}
1510
Gaurav Shah1b7a6162011-11-09 11:41:01 -08001511vector<string> Manager::ConnectedTechnologies(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -08001512 set<string> unique_technologies;
1513 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1514 it != devices_.end(); ++it) {
1515 if ((*it)->IsConnected())
1516 unique_technologies.insert(
1517 Technology::NameFromIdentifier((*it)->technology()));
1518 }
1519 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -07001520}
1521
Paul Stewart3c504012013-01-17 17:49:58 -08001522bool Manager::IsTechnologyConnected(Technology::Identifier technology) const {
1523 for (vector<DeviceRefPtr>::const_iterator it = devices_.begin();
1524 it != devices_.end(); ++it) {
1525 if ((*it)->technology() == technology && (*it)->IsConnected())
1526 return true;
1527 }
1528 return false;
1529}
1530
Darin Petkov58f0b6d2012-06-12 12:52:30 +02001531string Manager::DefaultTechnology(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -08001532 return (!services_.empty() && services_[0]->IsConnected()) ?
Darin Petkov58f0b6d2012-06-12 12:52:30 +02001533 services_[0]->GetTechnologyString() : "";
Chris Masoneb925cc82011-06-22 15:39:57 -07001534}
1535
Eric Shienbrood9a245532012-03-07 14:20:39 -05001536vector<string> Manager::EnabledTechnologies(Error */*error*/) {
1537 set<string> unique_technologies;
1538 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1539 it != devices_.end(); ++it) {
1540 if ((*it)->enabled())
1541 unique_technologies.insert(
1542 Technology::NameFromIdentifier((*it)->technology()));
1543 }
1544 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -07001545}
1546
Ben Chan5086b972013-01-15 21:51:38 -08001547vector<string> Manager::UninitializedTechnologies(Error */*error*/) {
1548 return device_info_.GetUninitializedTechnologies();
1549}
1550
Paul Stewartcb3eb892012-06-07 14:24:46 -07001551RpcIdentifiers Manager::EnumerateDevices(Error */*error*/) {
1552 RpcIdentifiers device_rpc_ids;
Chris Masone3c3f6a12011-07-01 10:01:41 -07001553 for (vector<DeviceRefPtr>::const_iterator it = devices_.begin();
1554 it != devices_.end();
1555 ++it) {
1556 device_rpc_ids.push_back((*it)->GetRpcIdentifier());
1557 }
1558 return device_rpc_ids;
1559}
1560
Paul Stewartcb3eb892012-06-07 14:24:46 -07001561RpcIdentifiers Manager::EnumerateProfiles(Error */*error*/) {
1562 RpcIdentifiers profile_rpc_ids;
Paul Stewart1b253142012-01-26 14:05:52 -08001563 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
1564 it != profiles_.end();
1565 ++it) {
1566 profile_rpc_ids.push_back((*it)->GetRpcIdentifier());
1567 }
1568 return profile_rpc_ids;
1569}
1570
Gaurav Shah1b7a6162011-11-09 11:41:01 -08001571vector<string> Manager::EnumerateAvailableServices(Error */*error*/) {
Chris Masone3c3f6a12011-07-01 10:01:41 -07001572 vector<string> service_rpc_ids;
1573 for (vector<ServiceRefPtr>::const_iterator it = services_.begin();
1574 it != services_.end();
1575 ++it) {
Paul Stewartbfb82552012-10-24 16:48:48 -07001576 if ((*it)->IsVisible()) {
1577 service_rpc_ids.push_back((*it)->GetRpcIdentifier());
1578 }
Chris Masone3c3f6a12011-07-01 10:01:41 -07001579 }
1580 return service_rpc_ids;
1581}
1582
Paul Stewart3c504012013-01-17 17:49:58 -08001583RpcIdentifiers Manager::EnumerateCompleteServices(Error */*error*/) {
1584 vector<string> service_rpc_ids;
1585 for (vector<ServiceRefPtr>::const_iterator it = services_.begin();
1586 it != services_.end();
1587 ++it) {
1588 service_rpc_ids.push_back((*it)->GetRpcIdentifier());
1589 }
1590 return service_rpc_ids;
1591}
1592
Paul Stewartbfb82552012-10-24 16:48:48 -07001593RpcIdentifiers Manager::EnumerateWatchedServices(Error */*error*/) {
1594 vector<string> service_rpc_ids;
1595 for (vector<ServiceRefPtr>::const_iterator it = services_.begin();
1596 it != services_.end();
1597 ++it) {
1598 if ((*it)->IsVisible() && (*it)->IsActive(NULL)) {
1599 service_rpc_ids.push_back((*it)->GetRpcIdentifier());
1600 }
1601 }
1602 return service_rpc_ids;
Chris Masone3c3f6a12011-07-01 10:01:41 -07001603}
1604
Paul Stewart1b253142012-01-26 14:05:52 -08001605string Manager::GetActiveProfileRpcIdentifier(Error */*error*/) {
1606 return ActiveProfile()->GetRpcIdentifier();
Chris Masone7aa5f902011-07-11 11:13:35 -07001607}
1608
Paul Stewart10e9e4e2012-04-26 19:46:28 -07001609string Manager::GetCheckPortalList(Error */*error*/) {
Jason Glasgowdf7c5532012-05-14 14:41:45 -04001610 return use_startup_portal_list_ ? startup_portal_list_ :
1611 props_.check_portal_list;
Paul Stewart10e9e4e2012-04-26 19:46:28 -07001612}
1613
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001614bool Manager::SetCheckPortalList(const string &portal_list, Error *error) {
Paul Stewart10e9e4e2012-04-26 19:46:28 -07001615 use_startup_portal_list_ = false;
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001616 if (props_.check_portal_list == portal_list) {
1617 return false;
1618 }
1619 props_.check_portal_list = portal_list;
1620 return true;
Paul Stewart10e9e4e2012-04-26 19:46:28 -07001621}
1622
Paul Stewart4d5efb72012-09-17 12:24:34 -07001623string Manager::GetIgnoredDNSSearchPaths(Error */*error*/) {
1624 return props_.ignored_dns_search_paths;
1625}
1626
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001627bool Manager::SetIgnoredDNSSearchPaths(const string &ignored_paths,
Paul Stewart4d5efb72012-09-17 12:24:34 -07001628 Error */*error*/) {
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001629 if (props_.ignored_dns_search_paths == ignored_paths) {
1630 return false;
1631 }
Paul Stewart4d5efb72012-09-17 12:24:34 -07001632 vector<string> ignored_path_list;
1633 if (!ignored_paths.empty()) {
1634 base::SplitString(ignored_paths, ',', &ignored_path_list);
1635 }
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001636 props_.ignored_dns_search_paths = ignored_paths;
Paul Stewart4d5efb72012-09-17 12:24:34 -07001637 resolver_->set_ignored_search_list(ignored_path_list);
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001638 return true;
Paul Stewart4d5efb72012-09-17 12:24:34 -07001639}
1640
mukesh agrawal32399322011-09-01 10:53:43 -07001641// called via RPC (e.g., from ManagerDBusAdaptor)
Darin Petkovb65c2452012-02-23 15:17:06 +01001642ServiceRefPtr Manager::GetService(const KeyValueStore &args, Error *error) {
Paul Stewart7f5ad572012-06-04 15:18:54 -07001643 if (args.ContainsString(flimflam::kTypeProperty) &&
1644 args.GetString(flimflam::kTypeProperty) == flimflam::kTypeVPN) {
1645 // GetService on a VPN service should actually perform ConfigureService.
1646 // TODO(pstew): Remove this hack and change Chrome to use ConfigureService
1647 // instead, when we no longer need to support flimflam. crosbug.com/31523
1648 return ConfigureService(args, error);
1649 }
Paul Stewart2c575d22012-12-07 12:28:57 -08001650
1651 ServiceRefPtr service = GetServiceInner(args, error);
1652 if (service) {
1653 // Configures the service using the rest of the passed-in arguments.
1654 service->Configure(args, error);
1655 }
1656
1657 return service;
Paul Stewart7f5ad572012-06-04 15:18:54 -07001658}
1659
1660ServiceRefPtr Manager::GetServiceInner(const KeyValueStore &args,
1661 Error *error) {
Paul Stewart13ed2252012-03-21 12:52:46 -07001662 if (args.ContainsString(flimflam::kGuidProperty)) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001663 SLOG(Manager, 2) << __func__ << ": searching by GUID";
Paul Stewart13ed2252012-03-21 12:52:46 -07001664 ServiceRefPtr service =
1665 GetServiceWithGUID(args.GetString(flimflam::kGuidProperty), NULL);
1666 if (service) {
Paul Stewart13ed2252012-03-21 12:52:46 -07001667 return service;
1668 }
1669 }
1670
Darin Petkovb65c2452012-02-23 15:17:06 +01001671 if (!args.ContainsString(flimflam::kTypeProperty)) {
Paul Stewart7f61e522012-03-22 11:13:45 -07001672 Error::PopulateAndLog(error, Error::kInvalidArguments, kErrorTypeRequired);
Darin Petkovb65c2452012-02-23 15:17:06 +01001673 return NULL;
1674 }
1675
1676 string type = args.GetString(flimflam::kTypeProperty);
Paul Stewart35eff132013-04-12 12:08:40 -07001677 if (type == kTypeEthernetEap) {
1678 SLOG(Manager, 2) << __func__ << ": getting Ethernet EAP Service";
1679 return ethernet_eap_provider_->service();
1680 }
Darin Petkovd1cd7972012-05-22 15:26:15 +02001681 if (type == flimflam::kTypeVPN) {
1682 SLOG(Manager, 2) << __func__ << ": getting VPN Service";
Darin Petkovc3505a52013-03-18 15:13:29 +01001683 return vpn_provider_->GetService(args, error);
Darin Petkovd1cd7972012-05-22 15:26:15 +02001684 }
Darin Petkovb65c2452012-02-23 15:17:06 +01001685 if (type == flimflam::kTypeWifi) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001686 SLOG(Manager, 2) << __func__ << ": getting WiFi Service";
Paul Stewart3c504012013-01-17 17:49:58 -08001687 return wifi_provider_->GetService(args, error);
Darin Petkovb65c2452012-02-23 15:17:06 +01001688 }
Darin Petkovd1cd7972012-05-22 15:26:15 +02001689 if (type == flimflam::kTypeWimax) {
1690 SLOG(Manager, 2) << __func__ << ": getting WiMAX Service";
1691 return wimax_provider_.GetService(args, error);
Darin Petkovb65c2452012-02-23 15:17:06 +01001692 }
mukesh agrawal06175d72012-04-23 16:46:01 -07001693 Error::PopulateAndLog(error, Error::kNotSupported,
1694 kErrorUnsupportedServiceType);
Darin Petkovb65c2452012-02-23 15:17:06 +01001695 return NULL;
1696}
1697
Paul Stewart7f61e522012-03-22 11:13:45 -07001698// called via RPC (e.g., from ManagerDBusAdaptor)
Paul Stewart7f5ad572012-06-04 15:18:54 -07001699ServiceRefPtr Manager::ConfigureService(const KeyValueStore &args,
1700 Error *error) {
Paul Stewart7f61e522012-03-22 11:13:45 -07001701 ProfileRefPtr profile = ActiveProfile();
1702 bool profile_specified = args.ContainsString(flimflam::kProfileProperty);
1703 if (profile_specified) {
1704 string profile_rpcid = args.GetString(flimflam::kProfileProperty);
1705 profile = LookupProfileByRpcIdentifier(profile_rpcid);
1706 if (!profile) {
1707 Error::PopulateAndLog(error, Error::kInvalidArguments,
1708 "Invalid profile name " + profile_rpcid);
Paul Stewart7f5ad572012-06-04 15:18:54 -07001709 return NULL;
Paul Stewart7f61e522012-03-22 11:13:45 -07001710 }
1711 }
1712
Paul Stewart7f5ad572012-06-04 15:18:54 -07001713 ServiceRefPtr service = GetServiceInner(args, error);
Paul Stewart7f61e522012-03-22 11:13:45 -07001714 if (error->IsFailure() || !service) {
1715 LOG(ERROR) << "GetService failed; returning upstream error.";
Paul Stewart7f5ad572012-06-04 15:18:54 -07001716 return NULL;
Paul Stewart7f61e522012-03-22 11:13:45 -07001717 }
1718
Paul Stewart2c575d22012-12-07 12:28:57 -08001719 // First pull in any stored configuration associated with the service.
1720 if (service->profile() == profile) {
Darin Petkov457728b2013-01-09 09:49:08 +01001721 SLOG(Manager, 2) << __func__ << ": service " << service->unique_name()
Paul Stewart2c575d22012-12-07 12:28:57 -08001722 << " is already a member of profile "
1723 << profile->GetFriendlyName()
1724 << " so a load is not necessary.";
1725 } else if (profile->LoadService(service)) {
1726 SLOG(Manager, 2) << __func__ << ": applied stored information from profile "
1727 << profile->GetFriendlyName()
1728 << " into service "
Darin Petkov457728b2013-01-09 09:49:08 +01001729 << service->unique_name();
Paul Stewart2c575d22012-12-07 12:28:57 -08001730 } else {
1731 SLOG(Manager, 2) << __func__ << ": no previous information in profile "
1732 << profile->GetFriendlyName()
1733 << " exists for service "
Darin Petkov457728b2013-01-09 09:49:08 +01001734 << service->unique_name();
Paul Stewart2c575d22012-12-07 12:28:57 -08001735 }
1736
1737 // Overlay this with the passed-in configuration parameters.
1738 service->Configure(args, error);
1739
mukesh agrawal06175d72012-04-23 16:46:01 -07001740 // Overwrite the profile data with the resulting configured service.
Paul Stewart7f61e522012-03-22 11:13:45 -07001741 if (!profile->UpdateService(service)) {
1742 Error::PopulateAndLog(error, Error::kInternalError,
1743 "Unable to save service to profile");
Paul Stewart7f5ad572012-06-04 15:18:54 -07001744 return NULL;
Paul Stewart7f61e522012-03-22 11:13:45 -07001745 }
1746
1747 if (HasService(service)) {
1748 // If the service has been registered (it may not be -- as is the case
1749 // with invisible WiFi networks), we can now transfer the service between
1750 // profiles.
Paul Stewart10ccbb32012-04-26 15:59:30 -07001751 if (IsServiceEphemeral(service) ||
Paul Stewart7f61e522012-03-22 11:13:45 -07001752 (profile_specified && service->profile() != profile)) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001753 SLOG(Manager, 2) << "Moving service to profile "
1754 << profile->GetFriendlyName();
Paul Stewart7f61e522012-03-22 11:13:45 -07001755 if (!MoveServiceToProfile(service, profile)) {
1756 Error::PopulateAndLog(error, Error::kInternalError,
1757 "Unable to move service to profile");
1758 }
1759 }
1760 }
Paul Stewart4357f4e2012-04-26 17:39:26 -07001761
1762 // Notify the service that a profile has been configured for it.
1763 service->OnProfileConfigured();
Paul Stewart7f5ad572012-06-04 15:18:54 -07001764
1765 return service;
Paul Stewart7f61e522012-03-22 11:13:45 -07001766}
1767
Paul Stewartd2e1c362013-03-03 19:06:07 -08001768// called via RPC (e.g., from ManagerDBusAdaptor)
1769ServiceRefPtr Manager::ConfigureServiceForProfile(
1770 const string &profile_rpcid, const KeyValueStore &args, Error *error) {
1771 if (args.LookupString(flimflam::kTypeProperty, "") != flimflam::kTypeWifi) {
1772 Error::PopulateAndLog(error, Error::kNotSupported,
1773 "This method only supports WiFi services");
1774 return NULL;
1775 }
1776
1777 ProfileRefPtr profile = LookupProfileByRpcIdentifier(profile_rpcid);
1778 if (!profile) {
1779 Error::PopulateAndLog(error, Error::kNotFound,
1780 "Profile specified was not found");
1781 return NULL;
1782 }
1783 if (args.LookupString(flimflam::kProfileProperty,
1784 profile_rpcid) != profile_rpcid) {
1785 Error::PopulateAndLog(error, Error::kInvalidArguments,
1786 "Profile argument does not match that in "
1787 "the configuration arguments");
1788 return NULL;
1789 }
1790
1791 ServiceRefPtr service;
1792 if (args.ContainsString(flimflam::kGuidProperty)) {
1793 SLOG(Manager, 2) << __func__ << ": searching by GUID";
1794 service = GetServiceWithGUID(args.GetString(flimflam::kGuidProperty), NULL);
1795 if (service && service->technology() != Technology::kWifi) {
1796 Error::PopulateAndLog(error, Error::kNotSupported,
1797 "This GUID matches a non-WiFi service");
1798 return NULL;
1799 }
1800 }
1801
1802 if (!service) {
1803 Error find_error;
1804 service = wifi_provider_->FindSimilarService(args, &find_error);
1805 }
1806
1807 // If no matching service exists, create a new service in the specified
1808 // profile using ConfigureService().
1809 if (!service) {
1810 KeyValueStore configure_args;
1811 configure_args.CopyFrom(args);
1812 configure_args.SetString(flimflam::kProfileProperty, profile_rpcid);
1813 return ConfigureService(configure_args, error);
1814 }
1815
1816 // The service already exists and is set to the desired profile,
1817 // the service is in the ephemeral profile, or the current profile
1818 // for the service appears before the desired profile, we need to
1819 // reassign the service to the new profile if necessary, leaving
1820 // the old profile intact (i.e, not calling Profile::AbandonService()).
1821 // Then, configure the properties on the service as well as its newly
1822 // associated profile.
1823 if (service->profile() == profile ||
1824 IsServiceEphemeral(service) ||
1825 IsProfileBefore(service->profile(), profile)) {
1826 SetupServiceInProfile(service, profile, args, error);
1827 return service;
1828 }
1829
1830 // The current profile for the service appears after the desired
1831 // profile. We must create a temporary service specifically for
1832 // the task of creating configuration data. This service will
1833 // neither inherit properties from the visible service, nor will
1834 // it exist after this function returns.
1835 service = wifi_provider_->CreateTemporaryService(args, error);
1836 if (!service || !error->IsSuccess()) {
1837 // Service::CreateTemporaryService() failed, and has set the error
1838 // appropriately.
1839 return NULL;
1840 }
1841
1842 // The profile may already have configuration for this service.
1843 profile->ConfigureService(service);
1844
1845 SetupServiceInProfile(service, profile, args, error);
1846
1847 // Although we have succeeded, this service will not exist, so its
1848 // path is of no use to the caller.
1849 DCHECK(service->HasOneRef());
1850 return NULL;
1851}
1852
1853void Manager::SetupServiceInProfile(ServiceRefPtr service,
1854 ProfileRefPtr profile,
1855 const KeyValueStore &args,
1856 Error *error) {
1857 service->SetProfile(profile);
1858 service->Configure(args, error);
1859 profile->UpdateService(service);
1860}
1861
Paul Stewart7a20aa42013-01-17 12:21:41 -08001862ServiceRefPtr Manager::FindMatchingService(const KeyValueStore &args,
1863 Error *error) {
1864 for (vector<ServiceRefPtr>::iterator it = services_.begin();
1865 it != services_.end(); ++it) {
1866 if ((*it)->DoPropertiesMatch(args)) {
1867 return *it;
1868 }
1869 }
1870 error->Populate(Error::kNotFound, "Matching service was not found");
1871 return NULL;
1872}
1873
Gaurav Shahb790aa22012-10-23 12:51:12 -07001874map<string, GeolocationInfos> Manager::GetNetworksForGeolocation() {
1875 map<string, GeolocationInfos> networks;
1876 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1877 it != devices_.end(); ++it) {
Wade Guthrie60a37062013-04-02 11:39:09 -07001878 switch ((*it)->technology()) {
Gaurav Shahb790aa22012-10-23 12:51:12 -07001879 // TODO(gauravsh): crosbug.com/35736 Need a strategy for combining
1880 // geolocation objects from multiple devices of the same technolgy.
1881 // Currently, we just pick the geolocation objects from the first found
1882 // device of each supported technology type.
1883 case Technology::kWifi:
1884 if (!ContainsKey(networks, kGeoWifiAccessPointsProperty))
1885 networks[kGeoWifiAccessPointsProperty] =
1886 (*it)->GetGeolocationObjects();
1887 break;
1888 case Technology::kCellular:
1889 if (!ContainsKey(networks, kGeoCellTowersProperty))
1890 networks[kGeoCellTowersProperty] = (*it)->GetGeolocationObjects();
1891 break;
1892 default:
1893 // Ignore other technologies.
1894 break;
1895 };
1896 }
1897 return networks;
1898};
1899
Paul Stewartc681fa02012-03-02 19:40:04 -08001900void Manager::RecheckPortal(Error */*error*/) {
1901 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1902 it != devices_.end(); ++it) {
1903 if ((*it)->RequestPortalDetection()) {
1904 // Only start Portal Detection on the device with the default connection.
1905 // We will get a "true" return value when we've found that device, and
1906 // can end our loop early as a result.
1907 break;
1908 }
1909 }
1910}
1911
Paul Stewartd215af62012-04-24 23:25:50 -07001912void Manager::RecheckPortalOnService(const ServiceRefPtr &service) {
1913 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1914 it != devices_.end(); ++it) {
1915 if ((*it)->IsConnectedToService(service)) {
1916 // As opposed to RecheckPortal() above, we explicitly stop and then
1917 // restart portal detection, since the service to recheck was explicitly
1918 // specified.
1919 (*it)->RestartPortalDetection();
1920 break;
1921 }
1922 }
1923}
1924
Wade Guthrie68d41092013-04-02 12:56:02 -07001925void Manager::RequestScan(Device::ScanType scan_type,
1926 const string &technology, Error *error) {
mukesh agrawal32399322011-09-01 10:53:43 -07001927 if (technology == flimflam::kTypeWifi || technology == "") {
1928 vector<DeviceRefPtr> wifi_devices;
Paul Stewartfdd16072011-09-16 12:41:35 -07001929 FilterByTechnology(Technology::kWifi, &wifi_devices);
mukesh agrawal32399322011-09-01 10:53:43 -07001930 for (vector<DeviceRefPtr>::iterator it = wifi_devices.begin();
1931 it != wifi_devices.end();
1932 ++it) {
Wade Guthrie68d41092013-04-02 12:56:02 -07001933 (*it)->Scan(scan_type, error);
mukesh agrawal32399322011-09-01 10:53:43 -07001934 }
1935 } else {
1936 // TODO(quiche): support scanning for other technologies?
Paul Stewartbe005172011-11-02 18:10:29 -07001937 Error::PopulateAndLog(error, Error::kInvalidArguments,
1938 "Unrecognized technology " + technology);
mukesh agrawal32399322011-09-01 10:53:43 -07001939 }
1940}
1941
Paul Stewart22aa71b2011-09-16 12:15:11 -07001942string Manager::GetTechnologyOrder() {
1943 vector<string> technology_names;
1944 for (vector<Technology::Identifier>::iterator it = technology_order_.begin();
1945 it != technology_order_.end();
1946 ++it) {
1947 technology_names.push_back(Technology::NameFromIdentifier(*it));
1948 }
1949
1950 return JoinString(technology_names, ',');
1951}
1952
1953void Manager::SetTechnologyOrder(const string &order, Error *error) {
1954 vector<Technology::Identifier> new_order;
Ben Chanfad4a0b2012-04-18 15:49:59 -07001955 SLOG(Manager, 2) << "Setting technology order to " << order;
Paul Stewart20088d82012-02-16 06:58:55 -08001956 if (!Technology::GetTechnologyVectorFromString(order, &new_order, error)) {
1957 return;
Paul Stewart22aa71b2011-09-16 12:15:11 -07001958 }
1959
1960 technology_order_ = new_order;
1961 SortServices();
1962}
1963
Paul Stewart75897df2011-04-27 09:05:53 -07001964} // namespace shill