blob: 55c6e1a8c313894206e269d319ab94f3728ff565 [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 Stewart26b327e2011-10-19 11:38:09 -070033#include "shill/event_dispatcher.h"
Gaurav Shahb790aa22012-10-23 12:51:12 -070034#include "shill/geolocation_info.h"
Gary Moraina9fb3252012-05-31 12:05:31 -070035#include "shill/hook_table.h"
Chris Masone9d779932011-08-25 16:33:41 -070036#include "shill/key_file_store.h"
Christopher Wileyb691efd2012-08-09 13:51:51 -070037#include "shill/logging.h"
Chris Masone7aa5f902011-07-11 11:13:35 -070038#include "shill/profile.h"
Chris Masoneb925cc82011-06-22 15:39:57 -070039#include "shill/property_accessor.h"
Gary Morainac1bdb42012-02-16 17:42:29 -080040#include "shill/proxy_factory.h"
Paul Stewarte6132022011-08-16 09:11:02 -070041#include "shill/resolver.h"
Chris Masone9be4a9d2011-05-16 15:44:09 -070042#include "shill/service.h"
Thieu Lea20cbc22012-01-09 22:01:43 +000043#include "shill/service_sorter.h"
Darin Petkovc3505a52013-03-18 15:13:29 +010044#include "shill/vpn_provider.h"
Darin Petkov33af05c2012-02-28 10:10:30 +010045#include "shill/vpn_service.h"
mukesh agrawal7a4e4002011-09-06 11:26:05 -070046#include "shill/wifi.h"
Paul Stewart3c504012013-01-17 17:49:58 -080047#include "shill/wifi_provider.h"
mukesh agrawal7a4e4002011-09-06 11:26:05 -070048#include "shill/wifi_service.h"
Darin Petkovd1cd7972012-05-22 15:26:15 +020049#include "shill/wimax_service.h"
Paul Stewart75897df2011-04-27 09:05:53 -070050
Eric Shienbrood3e20a232012-02-16 11:35:56 -050051using base::Bind;
Albert Chaulk0e1cdea2013-02-27 15:32:55 -080052using base::FilePath;
Eric Shienbrood3e20a232012-02-16 11:35:56 -050053using base::StringPrintf;
54using base::Unretained;
Darin Petkova5e07ef2012-07-09 14:27:57 +020055using std::map;
Gaurav Shah435de2c2011-11-17 19:01:07 -080056using std::set;
Paul Stewart75897df2011-04-27 09:05:53 -070057using std::string;
Chris Masone9be4a9d2011-05-16 15:44:09 -070058using std::vector;
Paul Stewart75897df2011-04-27 09:05:53 -070059
60namespace shill {
Paul Stewarte6132022011-08-16 09:11:02 -070061
Daniel Eratf9753672013-01-24 10:17:02 -080062namespace {
63
64// Human-readable string describing the suspend delay that is registered
65// with the power manager.
66const char kSuspendDelayDescription[] = "shill";
67
68} // namespace
69
Darin Petkovb65c2452012-02-23 15:17:06 +010070// statics
71const char Manager::kErrorNoDevice[] = "no wifi devices available";
72const char Manager::kErrorTypeRequired[] = "must specify service type";
73const char Manager::kErrorUnsupportedServiceType[] =
74 "service type is unsupported";
Arman Ugurayab22c162012-10-08 19:08:38 -070075// This timeout should be less than the upstart job timeout, otherwise
76// stats for termination actions might be lost.
77const int Manager::kTerminationActionsTimeoutMilliseconds = 4500;
Darin Petkov3ec55342012-09-28 14:04:44 +020078const char Manager::kPowerManagerKey[] = "manager";
mukesh agrawal7a4e4002011-09-06 11:26:05 -070079
Paul Stewart75897df2011-04-27 09:05:53 -070080Manager::Manager(ControlInterface *control_interface,
Darin Petkov887f2982011-07-14 16:10:17 -070081 EventDispatcher *dispatcher,
Thieu Le3426c8f2012-01-11 17:35:11 -080082 Metrics *metrics,
Chris Masone2ae797d2011-08-23 20:41:00 -070083 GLib *glib,
84 const string &run_directory,
85 const string &storage_directory,
86 const string &user_storage_format)
mukesh agrawal8a3188d2011-12-01 20:56:44 +000087 : dispatcher_(dispatcher),
mukesh agrawal8a3188d2011-12-01 20:56:44 +000088 run_path_(FilePath(run_directory)),
89 storage_path_(FilePath(storage_directory)),
90 user_storage_format_(user_storage_format),
91 adaptor_(control_interface->CreateManagerAdaptor(this)),
Thieu Le3426c8f2012-01-11 17:35:11 -080092 device_info_(control_interface, dispatcher, metrics, this),
93 modem_info_(control_interface, dispatcher, metrics, this, glib),
Darin Petkovc3505a52013-03-18 15:13:29 +010094 vpn_provider_(
95 new VPNProvider(control_interface, dispatcher, metrics, this)),
Paul Stewart3c504012013-01-17 17:49:58 -080096 wifi_provider_(
97 new WiFiProvider(control_interface, dispatcher, metrics, this)),
Darin Petkovb72b62e2012-05-15 16:55:36 +020098 wimax_provider_(control_interface, dispatcher, metrics, this),
Paul Stewart4d5efb72012-09-17 12:24:34 -070099 resolver_(Resolver::GetInstance()),
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000100 running_(false),
101 connect_profiles_to_rpc_(true),
Thieu Le5133b712013-02-19 14:47:21 -0800102 ephemeral_profile_(
103 new EphemeralProfile(control_interface, metrics, this)),
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000104 control_interface_(control_interface),
Thieu Le3426c8f2012-01-11 17:35:11 -0800105 metrics_(metrics),
Paul Stewart10e9e4e2012-04-26 19:46:28 -0700106 glib_(glib),
Gary Moraina9fb3252012-05-31 12:05:31 -0700107 use_startup_portal_list_(false),
Darin Petkova5e07ef2012-07-09 14:27:57 +0200108 termination_actions_(dispatcher),
Daniel Erat0818cca2012-12-14 10:16:21 -0800109 suspend_delay_registered_(false),
110 suspend_delay_id_(0),
Christopher Wiley1057cd72013-02-28 15:21:29 -0800111 default_service_callback_tag_(0),
112 crypto_util_proxy_(new CryptoUtilProxy(dispatcher, glib)) {
Chris Masone7aa5f902011-07-11 11:13:35 -0700113 HelpRegisterDerivedString(flimflam::kActiveProfileProperty,
Paul Stewart1b253142012-01-26 14:05:52 -0800114 &Manager::GetActiveProfileRpcIdentifier,
Chris Masone7aa5f902011-07-11 11:13:35 -0700115 NULL);
Paul Stewartd408fdf2012-05-07 17:15:57 -0700116 store_.RegisterBool(flimflam::kArpGatewayProperty, &props_.arp_gateway);
Chris Masone27c4aa52011-07-02 13:10:14 -0700117 HelpRegisterDerivedStrings(flimflam::kAvailableTechnologiesProperty,
118 &Manager::AvailableTechnologies,
119 NULL);
Paul Stewart10e9e4e2012-04-26 19:46:28 -0700120 HelpRegisterDerivedString(flimflam::kCheckPortalListProperty,
121 &Manager::GetCheckPortalList,
122 &Manager::SetCheckPortalList);
Chris Masone27c4aa52011-07-02 13:10:14 -0700123 HelpRegisterDerivedStrings(flimflam::kConnectedTechnologiesProperty,
124 &Manager::ConnectedTechnologies,
125 NULL);
Chris Masone88cbd5f2011-07-03 14:30:04 -0700126 store_.RegisterString(flimflam::kCountryProperty, &props_.country);
Chris Masone27c4aa52011-07-02 13:10:14 -0700127 HelpRegisterDerivedString(flimflam::kDefaultTechnologyProperty,
128 &Manager::DefaultTechnology,
129 NULL);
Paul Stewart49739c02012-08-08 17:24:03 -0700130 HelpRegisterConstDerivedRpcIdentifier(
131 shill::kDefaultServiceProperty,
132 &Manager::GetDefaultServiceRpcIdentifier);
Paul Stewartcb3eb892012-06-07 14:24:46 -0700133 HelpRegisterConstDerivedRpcIdentifiers(flimflam::kDevicesProperty,
134 &Manager::EnumerateDevices);
Chris Masone88cbd5f2011-07-03 14:30:04 -0700135 HelpRegisterDerivedStrings(flimflam::kEnabledTechnologiesProperty,
136 &Manager::EnabledTechnologies,
137 NULL);
Paul Stewart4d5efb72012-09-17 12:24:34 -0700138 HelpRegisterDerivedString(shill::kIgnoredDNSSearchPathsProperty,
139 &Manager::GetIgnoredDNSSearchPaths,
140 &Manager::SetIgnoredDNSSearchPaths);
Paul Stewart036dba02012-08-07 12:34:41 -0700141 store_.RegisterString(shill::kLinkMonitorTechnologiesProperty,
142 &props_.link_monitor_technologies);
Chris Masone88cbd5f2011-07-03 14:30:04 -0700143 store_.RegisterBool(flimflam::kOfflineModeProperty, &props_.offline_mode);
144 store_.RegisterString(flimflam::kPortalURLProperty, &props_.portal_url);
Paul Stewartc681fa02012-03-02 19:40:04 -0800145 store_.RegisterInt32(kPortalCheckIntervalProperty,
146 &props_.portal_check_interval_seconds);
Paul Stewartcb3eb892012-06-07 14:24:46 -0700147 HelpRegisterConstDerivedRpcIdentifiers(flimflam::kProfilesProperty,
148 &Manager::EnumerateProfiles);
Paul Stewartc681fa02012-03-02 19:40:04 -0800149 store_.RegisterString(kHostNameProperty, &props_.host_name);
Chris Masone88cbd5f2011-07-03 14:30:04 -0700150 HelpRegisterDerivedString(flimflam::kStateProperty,
151 &Manager::CalculateState,
152 NULL);
mukesh agrawal2366eed2012-03-20 18:21:50 -0700153 HelpRegisterConstDerivedRpcIdentifiers(flimflam::kServicesProperty,
154 &Manager::EnumerateAvailableServices);
Paul Stewart3c504012013-01-17 17:49:58 -0800155 HelpRegisterConstDerivedRpcIdentifiers(shill::kServiceCompleteListProperty,
156 &Manager::EnumerateCompleteServices);
Paul Stewartcb3eb892012-06-07 14:24:46 -0700157 HelpRegisterConstDerivedRpcIdentifiers(flimflam::kServiceWatchListProperty,
158 &Manager::EnumerateWatchedServices);
Ben Chan5086b972013-01-15 21:51:38 -0800159 HelpRegisterDerivedStrings(kUninitializedTechnologiesProperty,
160 &Manager::UninitializedTechnologies,
161 NULL);
Chris Masone3c3f6a12011-07-01 10:01:41 -0700162
mukesh agrawal84de5d22012-02-17 19:29:15 -0800163 // Set default technology order "by hand", to avoid invoking side
164 // effects of SetTechnologyOrder.
165 technology_order_.push_back(
Darin Petkov2f903b32012-04-18 12:56:43 +0200166 Technology::IdentifierFromName(flimflam::kTypeVPN));
167 technology_order_.push_back(
mukesh agrawal84de5d22012-02-17 19:29:15 -0800168 Technology::IdentifierFromName(flimflam::kTypeEthernet));
169 technology_order_.push_back(
170 Technology::IdentifierFromName(flimflam::kTypeWifi));
171 technology_order_.push_back(
Ben Chan3cafe382012-11-13 07:51:10 -0800172 Technology::IdentifierFromName(flimflam::kTypeWimax));
173 technology_order_.push_back(
mukesh agrawal84de5d22012-02-17 19:29:15 -0800174 Technology::IdentifierFromName(flimflam::kTypeCellular));
175
Ben Chanfad4a0b2012-04-18 15:49:59 -0700176 SLOG(Manager, 2) << "Manager initialized.";
Paul Stewart75897df2011-04-27 09:05:53 -0700177}
178
Darin Petkove7c6ad32012-06-29 10:22:09 +0200179Manager::~Manager() {}
Paul Stewart75897df2011-04-27 09:05:53 -0700180
mukesh agrawal8f317b62011-07-15 11:53:23 -0700181void Manager::AddDeviceToBlackList(const string &device_name) {
182 device_info_.AddDeviceToBlackList(device_name);
183}
184
Paul Stewart75897df2011-04-27 09:05:53 -0700185void Manager::Start() {
Paul Stewart0af98bf2011-05-10 17:38:08 -0700186 LOG(INFO) << "Manager started.";
Paul Stewarte6132022011-08-16 09:11:02 -0700187
Darin Petkov002c58e2012-06-19 02:56:05 +0200188 dbus_manager_.reset(new DBusManager());
189 dbus_manager_->Start();
190
Darin Petkov3ec55342012-09-28 14:04:44 +0200191 power_manager_.reset(
192 new PowerManager(dispatcher_, ProxyFactory::GetInstance()));
Darin Petkovca621542012-07-25 14:25:56 +0200193 power_manager_->AddStateChangeCallback(
Darin Petkov3ec55342012-09-28 14:04:44 +0200194 kPowerManagerKey,
Darin Petkovca621542012-07-25 14:25:56 +0200195 Bind(&Manager::OnPowerStateChanged, AsWeakPtr()));
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500196 // TODO(ers): weak ptr for metrics_?
197 PowerManager::PowerStateCallback cb =
198 Bind(&Metrics::NotifyPowerStateChange, Unretained(metrics_));
Thieu Leb84ba342012-03-02 15:15:19 -0800199 power_manager_->AddStateChangeCallback(Metrics::kMetricPowerManagerKey, cb);
200
Chris Masone2ae797d2011-08-23 20:41:00 -0700201 CHECK(file_util::CreateDirectory(run_path_)) << run_path_.value();
Paul Stewart4d5efb72012-09-17 12:24:34 -0700202 resolver_->set_path(run_path_.Append("resolv.conf"));
Chris Masone2ae797d2011-08-23 20:41:00 -0700203
Gaurav Shah71354762011-11-28 19:22:49 -0800204 InitializeProfiles();
Paul Stewart75897df2011-04-27 09:05:53 -0700205 running_ = true;
Chris Masone413a3192011-05-09 17:10:05 -0700206 adaptor_->UpdateRunning();
Paul Stewart0af98bf2011-05-10 17:38:08 -0700207 device_info_.Start();
Darin Petkov887f2982011-07-14 16:10:17 -0700208 modem_info_.Start();
Darin Petkovc3505a52013-03-18 15:13:29 +0100209 vpn_provider_->Start();
Paul Stewart3c504012013-01-17 17:49:58 -0800210 wifi_provider_->Start();
Darin Petkov9893d9c2012-05-17 15:27:31 -0700211 wimax_provider_.Start();
Paul Stewart75897df2011-04-27 09:05:53 -0700212}
213
214void Manager::Stop() {
215 running_ = false;
Paul Stewart212d60f2012-07-12 10:59:13 -0700216 // Persist device information to disk;
217 vector<DeviceRefPtr>::iterator devices_it;
218 for (devices_it = devices_.begin(); devices_it != devices_.end();
219 ++devices_it) {
220 UpdateDevice(*devices_it);
221 }
222
Wade Guthrie60a37062013-04-02 11:39:09 -0700223 UpdateWiFiProvider();
224
Paul Stewart212d60f2012-07-12 10:59:13 -0700225 // Persist profile, service information to disk.
226 vector<ProfileRefPtr>::iterator profiles_it;
227 for (profiles_it = profiles_.begin(); profiles_it != profiles_.end();
228 ++profiles_it) {
Paul Stewartd0a3b812012-03-28 22:48:22 -0700229 // Since this happens in a loop, the current manager state is stored to
230 // all default profiles in the stack. This is acceptable because the
231 // only time multiple default profiles are loaded are during autotests.
Paul Stewart212d60f2012-07-12 10:59:13 -0700232 (*profiles_it)->Save();
Chris Masone9d779932011-08-25 16:33:41 -0700233 }
Chris Masone9d779932011-08-25 16:33:41 -0700234
Thieu Le1271d682011-11-02 22:48:19 +0000235 vector<ServiceRefPtr>::iterator services_it;
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000236 Error e;
Thieu Le1271d682011-11-02 22:48:19 +0000237 for (services_it = services_.begin(); services_it != services_.end();
238 ++services_it) {
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000239 (*services_it)->Disconnect(&e);
Thieu Le1271d682011-11-02 22:48:19 +0000240 }
241
Chris Masone413a3192011-05-09 17:10:05 -0700242 adaptor_->UpdateRunning();
Darin Petkovb72b62e2012-05-15 16:55:36 +0200243 wimax_provider_.Stop();
Paul Stewart3c504012013-01-17 17:49:58 -0800244 wifi_provider_->Stop();
Darin Petkovc3505a52013-03-18 15:13:29 +0100245 vpn_provider_->Stop();
Darin Petkov887f2982011-07-14 16:10:17 -0700246 modem_info_.Stop();
247 device_info_.Stop();
Paul Stewartdfa46052012-06-26 09:44:14 -0700248 sort_services_task_.Cancel();
Darin Petkovca621542012-07-25 14:25:56 +0200249 power_manager_.reset();
Darin Petkov002c58e2012-06-19 02:56:05 +0200250 dbus_manager_.reset();
Paul Stewart75897df2011-04-27 09:05:53 -0700251}
252
Gaurav Shah71354762011-11-28 19:22:49 -0800253void Manager::InitializeProfiles() {
254 DCHECK(profiles_.empty());
255 // The default profile must go first on the stack.
256 CHECK(file_util::CreateDirectory(storage_path_)) << storage_path_.value();
Paul Stewart870523b2012-01-11 17:00:42 -0800257 scoped_refptr<DefaultProfile>
258 default_profile(new DefaultProfile(control_interface_,
Thieu Le5133b712013-02-19 14:47:21 -0800259 metrics_,
Gaurav Shah71354762011-11-28 19:22:49 -0800260 this,
261 storage_path_,
Paul Stewartd0a3b812012-03-28 22:48:22 -0700262 DefaultProfile::kDefaultId,
Gaurav Shah71354762011-11-28 19:22:49 -0800263 props_));
Thieu Le5133b712013-02-19 14:47:21 -0800264 // The default profile may fail to initialize if it's corrupted.
265 // If so, recreate the default profile.
266 if (!default_profile->InitStorage(
267 glib_, Profile::kCreateOrOpenExisting, NULL))
268 CHECK(default_profile->InitStorage(glib_, Profile::kCreateNew,
269 NULL));
Paul Stewart4d5efb72012-09-17 12:24:34 -0700270 CHECK(LoadProperties(default_profile));
Paul Stewart5ad16062013-02-21 18:10:48 -0800271 profiles_.push_back(default_profile);
Gaurav Shah71354762011-11-28 19:22:49 -0800272 Error error;
Paul Stewart19c871d2011-12-15 16:10:13 -0800273 string path;
Gaurav Shah71354762011-11-28 19:22:49 -0800274 for (vector<string>::iterator it = startup_profiles_.begin();
275 it != startup_profiles_.end(); ++it)
Paul Stewart19c871d2011-12-15 16:10:13 -0800276 PushProfile(*it, &path, &error);
Gaurav Shah71354762011-11-28 19:22:49 -0800277}
278
Paul Stewart19c871d2011-12-15 16:10:13 -0800279void Manager::CreateProfile(const string &name, string *path, Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700280 SLOG(Manager, 2) << __func__ << " " << name;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700281 Profile::Identifier ident;
282 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700283 Error::PopulateAndLog(error, Error::kInvalidArguments,
284 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700285 return;
286 }
Paul Stewartd0a3b812012-03-28 22:48:22 -0700287
Paul Stewartfc9a1da2012-06-27 15:54:52 -0700288 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
289 it != profiles_.end();
290 ++it) {
291 if ((*it)->MatchesIdentifier(ident)) {
292 Error::PopulateAndLog(error, Error::kAlreadyExists,
293 "Profile name " + name + " is already on stack");
294 *path = (*it)->GetRpcIdentifier();
295 return;
296 }
297 }
298
Paul Stewartd0a3b812012-03-28 22:48:22 -0700299 ProfileRefPtr profile;
300 if (ident.user.empty()) {
301 profile = new DefaultProfile(control_interface_,
Thieu Le5133b712013-02-19 14:47:21 -0800302 metrics_,
Paul Stewartd0a3b812012-03-28 22:48:22 -0700303 this,
304 storage_path_,
305 ident.identifier,
306 props_);
307 } else {
308 profile = new Profile(control_interface_,
Thieu Le5133b712013-02-19 14:47:21 -0800309 metrics_,
Paul Stewartd0a3b812012-03-28 22:48:22 -0700310 this,
311 ident,
312 user_storage_format_,
Gary Morainb672d352012-04-25 09:19:06 -0700313 true);
Paul Stewartd0a3b812012-03-28 22:48:22 -0700314 }
315
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700316 if (!profile->InitStorage(glib_, Profile::kCreateNew, error)) {
Paul Stewart19c871d2011-12-15 16:10:13 -0800317 // |error| will have been populated by InitStorage().
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700318 return;
319 }
320
321 // Save profile data out, and then let the scoped pointer fall out of scope.
322 if (!profile->Save()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700323 Error::PopulateAndLog(error, Error::kInternalError,
324 "Profile name " + name + " could not be saved");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700325 return;
326 }
Paul Stewart19c871d2011-12-15 16:10:13 -0800327
328 *path = profile->GetRpcIdentifier();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700329}
330
Paul Stewart19c871d2011-12-15 16:10:13 -0800331void Manager::PushProfile(const string &name, string *path, Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700332 SLOG(Manager, 2) << __func__ << " " << name;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700333 Profile::Identifier ident;
334 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700335 Error::PopulateAndLog(error, Error::kInvalidArguments,
336 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700337 return;
338 }
339
340 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
341 it != profiles_.end();
342 ++it) {
343 if ((*it)->MatchesIdentifier(ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700344 Error::PopulateAndLog(error, Error::kAlreadyExists,
345 "Profile name " + name + " is already on stack");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700346 return;
347 }
348 }
349
Paul Stewartd0a3b812012-03-28 22:48:22 -0700350 ProfileRefPtr profile;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700351 if (ident.user.empty()) {
Paul Stewartd0a3b812012-03-28 22:48:22 -0700352 // Allow a machine-wide-profile to be pushed on the stack only if the
353 // profile stack is empty, or if the topmost profile on the stack is
354 // also a machine-wide (non-user) profile.
355 if (!profiles_.empty() && !profiles_.back()->GetUser().empty()) {
356 Error::PopulateAndLog(error, Error::kInvalidArguments,
357 "Cannot load non-default global profile " + name +
358 " on top of a user profile");
359 return;
360 }
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700361
Paul Stewartd0a3b812012-03-28 22:48:22 -0700362 scoped_refptr<DefaultProfile>
363 default_profile(new DefaultProfile(control_interface_,
Thieu Le5133b712013-02-19 14:47:21 -0800364 metrics_,
Paul Stewartd0a3b812012-03-28 22:48:22 -0700365 this,
366 storage_path_,
367 ident.identifier,
368 props_));
369 if (!default_profile->InitStorage(glib_, Profile::kOpenExisting, error)) {
370 // |error| will have been populated by InitStorage().
371 return;
372 }
373
Paul Stewart4d5efb72012-09-17 12:24:34 -0700374 if (!LoadProperties(default_profile)) {
Paul Stewartd0a3b812012-03-28 22:48:22 -0700375 Error::PopulateAndLog(error, Error::kInvalidArguments,
376 "Could not load Manager properties from profile " +
377 name);
378 return;
379 }
380 profile = default_profile;
381 } else {
382 profile = new Profile(control_interface_,
Thieu Le5133b712013-02-19 14:47:21 -0800383 metrics_,
Paul Stewartd0a3b812012-03-28 22:48:22 -0700384 this,
385 ident,
386 user_storage_format_,
387 connect_profiles_to_rpc_);
388 if (!profile->InitStorage(glib_, Profile::kOpenExisting, error)) {
389 // |error| will have been populated by InitStorage().
390 return;
391 }
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700392 }
393
Paul Stewarta849a3d2011-11-03 05:54:09 -0700394 profiles_.push_back(profile);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700395
396 // Offer each registered Service the opportunity to join this new Profile.
Paul Stewarta41e38d2011-11-11 07:47:29 -0800397 for (vector<ServiceRefPtr>::iterator it = services_.begin();
398 it != services_.end(); ++it) {
Paul Stewartbba6a5b2011-11-02 18:45:59 -0700399 profile->ConfigureService(*it);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700400 }
401
Paul Stewart3c504012013-01-17 17:49:58 -0800402 // Shop the Profile contents around to Devices which may have configuration
403 // stored in these profiles.
Paul Stewarta41e38d2011-11-11 07:47:29 -0800404 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
405 it != devices_.end(); ++it) {
406 profile->ConfigureDevice(*it);
407 }
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800408
Darin Petkovc63dcf02012-05-24 11:51:43 +0200409 // Offer the Profile contents to the service/device providers which will
410 // create new services if necessary.
Darin Petkovc3505a52013-03-18 15:13:29 +0100411 vpn_provider_->CreateServicesFromProfile(profile);
Paul Stewart3c504012013-01-17 17:49:58 -0800412 wifi_provider_->CreateServicesFromProfile(profile);
Darin Petkovc63dcf02012-05-24 11:51:43 +0200413 wimax_provider_.CreateServicesFromProfile(profile);
Paul Stewart66815332012-04-09 18:09:36 -0700414
Paul Stewart19c871d2011-12-15 16:10:13 -0800415 *path = profile->GetRpcIdentifier();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800416 SortServices();
Philipp Neubeck79173602012-11-13 21:10:09 +0100417
418 Error unused_error;
419 adaptor_->EmitStringsChanged(flimflam::kProfilesProperty,
420 EnumerateProfiles(&unused_error));
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700421}
422
423void Manager::PopProfileInternal() {
424 CHECK(!profiles_.empty());
425 ProfileRefPtr active_profile = profiles_.back();
426 profiles_.pop_back();
Paul Stewart75225512012-01-26 22:51:33 -0800427 vector<ServiceRefPtr>::iterator it;
Paul Stewart65512e12012-03-26 18:01:08 -0700428 for (it = services_.begin(); it != services_.end();) {
429 if ((*it)->profile().get() != active_profile.get() ||
430 MatchProfileWithService(*it) ||
431 !UnloadService(&it)) {
432 LOG(ERROR) << "Skipping unload of service";
433 ++it;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700434 }
435 }
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800436 SortServices();
Philipp Neubeck79173602012-11-13 21:10:09 +0100437
438 Error unused_error;
439 adaptor_->EmitStringsChanged(flimflam::kProfilesProperty,
440 EnumerateProfiles(&unused_error));
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700441}
442
Paul Stewarta41e38d2011-11-11 07:47:29 -0800443void Manager::PopProfile(const string &name, Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700444 SLOG(Manager, 2) << __func__ << " " << name;
Christopher Wiley3e7635e2012-08-15 09:46:17 -0700445 // This signal is sent when a user logs out of a session. Regardless of
446 // whether we find their profile to remove, lets clear the network related
447 // logs.
448 MemoryLog::GetInstance()->Clear();
449 LOG(INFO) << "Cleared the memory log on logout event.";
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700450 Profile::Identifier ident;
451 if (profiles_.empty()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700452 Error::PopulateAndLog(error, Error::kNotFound, "Profile stack is empty");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700453 return;
454 }
455 ProfileRefPtr active_profile = profiles_.back();
456 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700457 Error::PopulateAndLog(error, Error::kInvalidArguments,
458 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700459 return;
460 }
461 if (!active_profile->MatchesIdentifier(ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700462 Error::PopulateAndLog(error, Error::kNotSupported,
463 name + " is not the active profile");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700464 return;
465 }
466 PopProfileInternal();
467}
468
469void Manager::PopAnyProfile(Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700470 SLOG(Manager, 2) << __func__;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700471 Profile::Identifier ident;
472 if (profiles_.empty()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700473 Error::PopulateAndLog(error, Error::kNotFound, "Profile stack is empty");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700474 return;
475 }
476 PopProfileInternal();
477}
478
Paul Stewart307c2502013-03-23 12:32:10 -0700479void Manager::PopAllUserProfiles(Error */*error*/) {
480 SLOG(Manager, 2) << __func__;
481 // This signal is sent when a user logs out of a session. Regardless of
482 // whether we find their profile to remove, lets clear the network related
483 // logs.
484 MemoryLog::GetInstance()->Clear();
485 LOG(INFO) << "Cleared the memory log on logout event.";
486 while (!profiles_.empty() && !profiles_.back()->GetUser().empty()) {
487 PopProfileInternal();
488 }
489}
490
Paul Stewarte73d05c2012-03-29 16:26:05 -0700491void Manager::RemoveProfile(const string &name, Error *error) {
492 Profile::Identifier ident;
493 if (!Profile::ParseIdentifier(name, &ident)) {
494 Error::PopulateAndLog(error, Error::kInvalidArguments,
495 "Invalid profile name " + name);
496 return;
497 }
498
499 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
500 it != profiles_.end();
501 ++it) {
502 if ((*it)->MatchesIdentifier(ident)) {
503 Error::PopulateAndLog(error, Error::kInvalidArguments,
504 "Cannot remove profile name " + name +
505 " since it is on stack");
506 return;
507 }
508 }
509
510 ProfileRefPtr profile;
511 if (ident.user.empty()) {
512 profile = new DefaultProfile(control_interface_,
Thieu Le5133b712013-02-19 14:47:21 -0800513 metrics_,
Paul Stewarte73d05c2012-03-29 16:26:05 -0700514 this,
515 storage_path_,
516 ident.identifier,
517 props_);
518 } else {
519 profile = new Profile(control_interface_,
Thieu Le5133b712013-02-19 14:47:21 -0800520 metrics_,
Paul Stewarte73d05c2012-03-29 16:26:05 -0700521 this,
522 ident,
523 user_storage_format_,
524 false);
525 }
526
527
528 // |error| will have been populated if RemoveStorage fails.
529 profile->RemoveStorage(glib_, error);
530
531 return;
532}
533
Paul Stewart75225512012-01-26 22:51:33 -0800534bool Manager::HandleProfileEntryDeletion(const ProfileRefPtr &profile,
535 const std::string &entry_name) {
536 bool moved_services = false;
537 for (vector<ServiceRefPtr>::iterator it = services_.begin();
Paul Stewart65512e12012-03-26 18:01:08 -0700538 it != services_.end();) {
Paul Stewart75225512012-01-26 22:51:33 -0800539 if ((*it)->profile().get() == profile.get() &&
540 (*it)->GetStorageIdentifier() == entry_name) {
541 profile->AbandonService(*it);
Paul Stewart65512e12012-03-26 18:01:08 -0700542 if (MatchProfileWithService(*it) ||
543 !UnloadService(&it)) {
544 ++it;
Paul Stewart75225512012-01-26 22:51:33 -0800545 }
546 moved_services = true;
Paul Stewart65512e12012-03-26 18:01:08 -0700547 } else {
548 ++it;
Paul Stewart75225512012-01-26 22:51:33 -0800549 }
550 }
551 return moved_services;
552}
553
Paul Stewart0756db92012-01-27 08:34:47 -0800554ServiceRefPtr Manager::GetServiceWithStorageIdentifier(
555 const ProfileRefPtr &profile, const std::string &entry_name, Error *error) {
556 for (vector<ServiceRefPtr>::iterator it = services_.begin();
557 it != services_.end(); ++it) {
558 if ((*it)->profile().get() == profile.get() &&
559 (*it)->GetStorageIdentifier() == entry_name) {
560 return *it;
561 }
562 }
563
Paul Stewart76a89cb2012-09-14 06:06:48 -0700564 string error_string(
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500565 StringPrintf("Entry %s is not registered in the manager",
566 entry_name.c_str()));
Paul Stewart76a89cb2012-09-14 06:06:48 -0700567 if (error) {
568 error->Populate(Error::kNotFound, error_string);
569 }
570 SLOG(Manager, 2) << error_string;
Paul Stewart0756db92012-01-27 08:34:47 -0800571 return NULL;
572}
573
Paul Stewart13ed2252012-03-21 12:52:46 -0700574ServiceRefPtr Manager::GetServiceWithGUID(
575 const std::string &guid, Error *error) {
576 for (vector<ServiceRefPtr>::iterator it = services_.begin();
577 it != services_.end(); ++it) {
578 if ((*it)->guid() == guid) {
579 return *it;
580 }
581 }
582
Paul Stewart76a89cb2012-09-14 06:06:48 -0700583 string error_string(
Paul Stewart13ed2252012-03-21 12:52:46 -0700584 StringPrintf("Service wth GUID %s is not registered in the manager",
585 guid.c_str()));
Paul Stewart76a89cb2012-09-14 06:06:48 -0700586 if (error) {
587 error->Populate(Error::kNotFound, error_string);
588 }
589 SLOG(Manager, 2) << error_string;
Paul Stewart13ed2252012-03-21 12:52:46 -0700590 return NULL;
591}
592
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700593ServiceRefPtr Manager::GetDefaultService() const {
Arman Uguray32c76402012-11-27 14:01:13 -0800594 SLOG(Manager, 2) << __func__;
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700595 if (services_.empty() || !services_[0]->connection().get()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700596 SLOG(Manager, 2) << "In " << __func__ << ": No default connection exists.";
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700597 return NULL;
598 }
599 return services_[0];
600}
601
Paul Stewart49739c02012-08-08 17:24:03 -0700602RpcIdentifier Manager::GetDefaultServiceRpcIdentifier(Error */*error*/) {
603 ServiceRefPtr default_service = GetDefaultService();
604 return default_service ? default_service->GetRpcIdentifier() : "/";
605}
606
Paul Stewart036dba02012-08-07 12:34:41 -0700607bool Manager::IsTechnologyInList(const string &technology_list,
608 Technology::Identifier tech) const {
Paul Stewart20088d82012-02-16 06:58:55 -0800609 Error error;
Paul Stewart036dba02012-08-07 12:34:41 -0700610 vector<Technology::Identifier> technologies;
611 return Technology::GetTechnologyVectorFromString(technology_list,
612 &technologies,
Paul Stewart20088d82012-02-16 06:58:55 -0800613 &error) &&
Paul Stewart036dba02012-08-07 12:34:41 -0700614 std::find(technologies.begin(), technologies.end(), tech) !=
615 technologies.end();
616}
617
618bool Manager::IsPortalDetectionEnabled(Technology::Identifier tech) {
619 return IsTechnologyInList(GetCheckPortalList(NULL), tech);
Paul Stewart20088d82012-02-16 06:58:55 -0800620}
621
Paul Stewart10e9e4e2012-04-26 19:46:28 -0700622void Manager::SetStartupPortalList(const string &portal_list) {
623 startup_portal_list_ = portal_list;
624 use_startup_portal_list_ = true;
625}
626
Paul Stewartd2e1c362013-03-03 19:06:07 -0800627bool Manager::IsProfileBefore(const ProfileRefPtr &a,
628 const ProfileRefPtr &b) const {
629 DCHECK(a != b);
630 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
631 it != profiles_.end();
632 ++it) {
633 if (*it == a) {
634 return true;
635 }
636 if (*it == b) {
637 return false;
638 }
639 }
640 NOTREACHED() << "We should have found both profiles in the profiles_ list!";
641 return false;
642}
643
Paul Stewart10ccbb32012-04-26 15:59:30 -0700644bool Manager::IsServiceEphemeral(const ServiceConstRefPtr &service) const {
645 return service->profile() == ephemeral_profile_;
646}
647
Paul Stewart036dba02012-08-07 12:34:41 -0700648bool Manager::IsTechnologyLinkMonitorEnabled(
649 Technology::Identifier technology) const {
650 return IsTechnologyInList(props_.link_monitor_technologies, technology);
Paul Stewartbf667612012-06-29 14:49:54 -0700651}
652
Paul Stewart3c504012013-01-17 17:49:58 -0800653bool Manager::IsDefaultProfile(StoreInterface *storage) {
654 return profiles_.empty() || storage == profiles_.front()->GetConstStorage();
655}
656
657void Manager::OnProfileStorageInitialized(StoreInterface *storage) {
Wade Guthrie60a37062013-04-02 11:39:09 -0700658 wifi_provider_->LoadAndFixupServiceEntries(storage,
659 IsDefaultProfile(storage));
Paul Stewart3c504012013-01-17 17:49:58 -0800660}
661
662DeviceRefPtr Manager::GetEnabledDeviceWithTechnology(
663 Technology::Identifier technology) const {
664 vector<DeviceRefPtr> devices;
665 FilterByTechnology(technology, &devices);
666 for (vector<DeviceRefPtr>::const_iterator it = devices.begin();
667 it != devices.end(); ++it) {
668 if ((*it)->enabled()) {
669 return *it;
670 }
Paul Stewart85aea152013-01-22 09:31:56 -0800671 }
Paul Stewart3c504012013-01-17 17:49:58 -0800672 return NULL;
Paul Stewart85aea152013-01-22 09:31:56 -0800673}
674
Paul Stewart1b253142012-01-26 14:05:52 -0800675const ProfileRefPtr &Manager::ActiveProfile() const {
Eric Shienbroodc74cf9c2012-03-02 15:00:35 -0500676 DCHECK_NE(profiles_.size(), 0U);
Chris Masone7aa5f902011-07-11 11:13:35 -0700677 return profiles_.back();
678}
679
Paul Stewart1b253142012-01-26 14:05:52 -0800680bool Manager::IsActiveProfile(const ProfileRefPtr &profile) const {
681 return (profiles_.size() > 0 &&
682 ActiveProfile().get() == profile.get());
683}
684
Chris Masone6515aab2011-10-12 16:19:09 -0700685bool Manager::MoveServiceToProfile(const ServiceRefPtr &to_move,
686 const ProfileRefPtr &destination) {
687 const ProfileRefPtr from = to_move->profile();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700688 SLOG(Manager, 2) << "Moving service "
Darin Petkov457728b2013-01-09 09:49:08 +0100689 << to_move->unique_name()
Ben Chanfad4a0b2012-04-18 15:49:59 -0700690 << " to profile "
691 << destination->GetFriendlyName()
692 << " from "
693 << from->GetFriendlyName();
Darin Petkov457728b2013-01-09 09:49:08 +0100694 return destination->AdoptService(to_move) && from->AbandonService(to_move);
Chris Masone6791a432011-07-12 13:23:19 -0700695}
696
Paul Stewart7f61e522012-03-22 11:13:45 -0700697ProfileRefPtr Manager::LookupProfileByRpcIdentifier(
698 const string &profile_rpcid) {
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800699 for (vector<ProfileRefPtr>::iterator it = profiles_.begin();
700 it != profiles_.end();
701 ++it) {
702 if (profile_rpcid == (*it)->GetRpcIdentifier()) {
Paul Stewart7f61e522012-03-22 11:13:45 -0700703 return *it;
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800704 }
705 }
Paul Stewart7f61e522012-03-22 11:13:45 -0700706 return NULL;
707}
708
709void Manager::SetProfileForService(const ServiceRefPtr &to_set,
710 const string &profile_rpcid,
711 Error *error) {
712 ProfileRefPtr profile = LookupProfileByRpcIdentifier(profile_rpcid);
713 if (!profile) {
714 Error::PopulateAndLog(error, Error::kInvalidArguments,
715 StringPrintf("Unknown Profile %s requested for "
716 "Service", profile_rpcid.c_str()));
717 return;
718 }
719
Paul Stewart649f3a42012-04-24 23:22:16 -0700720 if (!to_set->profile()) {
721 // We are being asked to set the profile property of a service that
722 // has never been registered. Now is a good time to register it.
723 RegisterService(to_set);
724 }
725
Paul Stewart7f61e522012-03-22 11:13:45 -0700726 if (to_set->profile().get() == profile.get()) {
727 Error::PopulateAndLog(error, Error::kInvalidArguments,
728 "Service is already connected to this profile");
729 } else if (!MoveServiceToProfile(to_set, profile)) {
730 Error::PopulateAndLog(error, Error::kInternalError,
731 "Unable to move service to profile");
732 }
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800733}
734
Eric Shienbrood9a245532012-03-07 14:20:39 -0500735void Manager::EnableTechnology(const std::string &technology_name,
736 Error *error,
737 const ResultCallback &callback) {
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400738 CHECK(error != NULL);
739 DCHECK(error->IsOngoing());
Eric Shienbrood9a245532012-03-07 14:20:39 -0500740 Technology::Identifier id = Technology::IdentifierFromName(technology_name);
741 if (id == Technology::kUnknown) {
742 error->Populate(Error::kInvalidArguments, "Unknown technology");
743 return;
744 }
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400745 bool deferred = false;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500746 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
747 it != devices_.end(); ++it) {
748 DeviceRefPtr device = *it;
Joshua Krollda798622012-06-05 12:30:48 -0700749 if (device->technology() == id && !device->enabled()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500750 device->SetEnabledPersistent(true, error, callback);
751 // Continue with other devices even if one fails
752 // TODO(ers): Decide whether an error should be returned
753 // for the overall EnableTechnology operation if some
754 // devices succeed and some fail.
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400755 if (error->IsOngoing())
756 deferred = true;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500757 }
758 }
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400759 // If no device has deferred work, then clear the error to
760 // communicate to the caller that all work is done.
761 if (!deferred)
762 error->Reset();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500763}
764
765void Manager::DisableTechnology(const std::string &technology_name,
766 Error *error,
767 const ResultCallback &callback) {
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400768 CHECK(error != NULL);
769 DCHECK(error->IsOngoing());
Eric Shienbrood9a245532012-03-07 14:20:39 -0500770 Technology::Identifier id = Technology::IdentifierFromName(technology_name);
771 if (id == Technology::kUnknown) {
772 error->Populate(Error::kInvalidArguments, "Unknown technology");
773 return;
774 }
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400775 bool deferred = false;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500776 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
777 it != devices_.end(); ++it) {
778 DeviceRefPtr device = *it;
Joshua Krollda798622012-06-05 12:30:48 -0700779 if (device->technology() == id && device->enabled()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500780 device->SetEnabledPersistent(false, error, callback);
781 // Continue with other devices even if one fails
782 // TODO(ers): Decide whether an error should be returned
783 // for the overall DisableTechnology operation if some
784 // devices succeed and some fail.
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400785 if (error->IsOngoing())
786 deferred = true;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500787 }
788 }
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400789 // If no device has deferred work, then clear the error to
790 // communicate to the caller that all work is done.
791 if (!deferred)
792 error->Reset();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500793}
794
795void Manager::UpdateEnabledTechnologies() {
796 Error error;
797 adaptor_->EmitStringsChanged(flimflam::kEnabledTechnologiesProperty,
798 EnabledTechnologies(&error));
799}
800
Ben Chan5086b972013-01-15 21:51:38 -0800801void Manager::UpdateUninitializedTechnologies() {
802 Error error;
803 adaptor_->EmitStringsChanged(kUninitializedTechnologiesProperty,
804 UninitializedTechnologies(&error));
805}
806
Chris Masone2b105542011-06-22 10:58:09 -0700807void Manager::RegisterDevice(const DeviceRefPtr &to_manage) {
Darin Petkove7c6ad32012-06-29 10:22:09 +0200808 LOG(INFO) << "Device " << to_manage->FriendlyName() << " registered.";
809 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
810 it != devices_.end(); ++it) {
Chris Masonec1e50412011-06-07 13:04:53 -0700811 if (to_manage.get() == it->get())
Chris Masone9be4a9d2011-05-16 15:44:09 -0700812 return;
813 }
Chris Masonec1e50412011-06-07 13:04:53 -0700814 devices_.push_back(to_manage);
Paul Stewartf1ce5d22011-05-19 13:10:20 -0700815
Paul Stewart87a4ae82012-10-26 15:49:32 -0700816 LoadDeviceFromProfiles(to_manage);
Paul Stewarta41e38d2011-11-11 07:47:29 -0800817
Darin Petkove7c6ad32012-06-29 10:22:09 +0200818 // If |to_manage| is new, it needs to be persisted.
819 UpdateDevice(to_manage);
820
Paul Stewarta41e38d2011-11-11 07:47:29 -0800821 // In normal usage, running_ will always be true when we are here, however
822 // unit tests sometimes do things in otherwise invalid states.
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400823 if (running_ && (to_manage->enabled_persistent() ||
824 to_manage->IsUnderlyingDeviceEnabled()))
Eric Shienbrood9a245532012-03-07 14:20:39 -0500825 to_manage->SetEnabled(true);
Gaurav Shah435de2c2011-11-17 19:01:07 -0800826
Eric Shienbrood8839a892012-03-29 10:33:48 -0400827 EmitDeviceProperties();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700828}
829
mukesh agrawal5029c6c2011-08-25 11:12:40 -0700830void Manager::DeregisterDevice(const DeviceRefPtr &to_forget) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700831 SLOG(Manager, 2) << __func__ << "(" << to_forget->FriendlyName() << ")";
Chris Masonec1e50412011-06-07 13:04:53 -0700832 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700833 for (it = devices_.begin(); it != devices_.end(); ++it) {
Chris Masonec1e50412011-06-07 13:04:53 -0700834 if (to_forget.get() == it->get()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700835 SLOG(Manager, 2) << "Deregistered device: " << to_forget->UniqueName();
Paul Stewart212d60f2012-07-12 10:59:13 -0700836 UpdateDevice(to_forget);
Eric Shienbrood9a245532012-03-07 14:20:39 -0500837 to_forget->SetEnabled(false);
Chris Masone9be4a9d2011-05-16 15:44:09 -0700838 devices_.erase(it);
Eric Shienbrood8839a892012-03-29 10:33:48 -0400839 EmitDeviceProperties();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700840 return;
841 }
842 }
Ben Chanfad4a0b2012-04-18 15:49:59 -0700843 SLOG(Manager, 2) << __func__ << " unknown device: "
844 << to_forget->UniqueName();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700845}
846
Paul Stewart87a4ae82012-10-26 15:49:32 -0700847void Manager::LoadDeviceFromProfiles(const DeviceRefPtr &device) {
848 // We are applying device properties from the DefaultProfile, and adding the
849 // union of hidden services in all loaded profiles to the device.
850 for (vector<ProfileRefPtr>::iterator it = profiles_.begin();
851 it != profiles_.end(); ++it) {
852 // Load device configuration, if any exists, as well as hidden services.
853 (*it)->ConfigureDevice(device);
854 }
855}
856
Eric Shienbrood8839a892012-03-29 10:33:48 -0400857void Manager::EmitDeviceProperties() {
858 vector<DeviceRefPtr>::iterator it;
859 vector<string> device_paths;
860 for (it = devices_.begin(); it != devices_.end(); ++it) {
861 device_paths.push_back((*it)->GetRpcIdentifier());
862 }
863 adaptor_->EmitRpcIdentifierArrayChanged(flimflam::kDevicesProperty,
864 device_paths);
865 Error error;
866 adaptor_->EmitStringsChanged(flimflam::kAvailableTechnologiesProperty,
867 AvailableTechnologies(&error));
868 adaptor_->EmitStringsChanged(flimflam::kEnabledTechnologiesProperty,
869 EnabledTechnologies(&error));
Ben Chan5086b972013-01-15 21:51:38 -0800870 adaptor_->EmitStringsChanged(kUninitializedTechnologiesProperty,
871 UninitializedTechnologies(&error));
Eric Shienbrood8839a892012-03-29 10:33:48 -0400872}
873
mukesh agrawal4eb4d782011-12-05 17:34:37 +0000874bool Manager::HasService(const ServiceRefPtr &service) {
875 vector<ServiceRefPtr>::iterator it;
876 for (it = services_.begin(); it != services_.end(); ++it) {
Darin Petkov457728b2013-01-09 09:49:08 +0100877 if ((*it)->unique_name() == service->unique_name())
mukesh agrawal4eb4d782011-12-05 17:34:37 +0000878 return true;
879 }
880 return false;
881}
882
Chris Masone2b105542011-06-22 10:58:09 -0700883void Manager::RegisterService(const ServiceRefPtr &to_manage) {
Darin Petkov457728b2013-01-09 09:49:08 +0100884 SLOG(Manager, 2) << "Registering service " << to_manage->unique_name();
mukesh agrawald835b202011-10-07 15:26:47 -0700885
Paul Stewart75225512012-01-26 22:51:33 -0800886 MatchProfileWithService(to_manage);
Chris Masone6791a432011-07-12 13:23:19 -0700887
888 // Now add to OUR list.
Chris Masonec1e50412011-06-07 13:04:53 -0700889 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700890 for (it = services_.begin(); it != services_.end(); ++it) {
Darin Petkov457728b2013-01-09 09:49:08 +0100891 CHECK(to_manage->unique_name() != (*it)->unique_name());
Chris Masone9be4a9d2011-05-16 15:44:09 -0700892 }
Chris Masonec1e50412011-06-07 13:04:53 -0700893 services_.push_back(to_manage);
Paul Stewart22aa71b2011-09-16 12:15:11 -0700894 SortServices();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700895}
896
Chris Masone6515aab2011-10-12 16:19:09 -0700897void Manager::DeregisterService(const ServiceRefPtr &to_forget) {
Chris Masonec1e50412011-06-07 13:04:53 -0700898 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700899 for (it = services_.begin(); it != services_.end(); ++it) {
Darin Petkov457728b2013-01-09 09:49:08 +0100900 if (to_forget->unique_name() == (*it)->unique_name()) {
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800901 DCHECK(!(*it)->connection());
Paul Stewartfc9a1da2012-06-27 15:54:52 -0700902 (*it)->Unload();
Philipp Neubeck79173602012-11-13 21:10:09 +0100903 (*it)->SetProfile(NULL);
Chris Masone9be4a9d2011-05-16 15:44:09 -0700904 services_.erase(it);
Paul Stewart22aa71b2011-09-16 12:15:11 -0700905 SortServices();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700906 return;
907 }
908 }
909}
910
Paul Stewart65512e12012-03-26 18:01:08 -0700911bool Manager::UnloadService(vector<ServiceRefPtr>::iterator *service_iterator) {
912 if (!(**service_iterator)->Unload()) {
913 return false;
914 }
915
916 DCHECK(!(**service_iterator)->connection());
Philipp Neubeck79173602012-11-13 21:10:09 +0100917 (**service_iterator)->SetProfile(NULL);
Paul Stewart65512e12012-03-26 18:01:08 -0700918 *service_iterator = services_.erase(*service_iterator);
919
920 return true;
921}
922
mukesh agrawal00917ce2011-11-22 23:56:55 +0000923void Manager::UpdateService(const ServiceRefPtr &to_update) {
924 CHECK(to_update);
Darin Petkov457728b2013-01-09 09:49:08 +0100925 LOG(INFO) << "Service " << to_update->unique_name() << " updated;"
Gaurav Shahc6d6c722011-11-17 18:59:39 -0800926 << " state: " << Service::ConnectStateToString(to_update->state())
927 << " failure: "
928 << Service::ConnectFailureToString(to_update->failure());
Ben Chanfad4a0b2012-04-18 15:49:59 -0700929 SLOG(Manager, 2) << "IsConnected(): " << to_update->IsConnected();
930 SLOG(Manager, 2) << "IsConnecting(): " << to_update->IsConnecting();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800931 if (to_update->IsConnected()) {
mukesh agrawal00917ce2011-11-22 23:56:55 +0000932 to_update->MakeFavorite();
Gary Moraind93615e2012-04-27 11:50:03 -0700933 // Persists the updated favorite setting in the profile.
934 SaveServiceToProfile(to_update);
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800935 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700936 SortServices();
Paul Stewart03dba0b2011-08-22 16:32:45 -0700937}
938
Darin Petkove7c6ad32012-06-29 10:22:09 +0200939void Manager::UpdateDevice(const DeviceRefPtr &to_update) {
940 LOG(INFO) << "Device " << to_update->link_name() << " updated: "
941 << (to_update->enabled_persistent() ? "enabled" : "disabled");
Wade Guthrie60a37062013-04-02 11:39:09 -0700942 // Saves the device to the topmost profile that accepts it (ordinary
943 // profiles don't update but default profiles do). Normally, the topmost
944 // updating profile would be the DefaultProfile at the bottom of the stack.
945 // Autotests, differ from the normal scenario, however, in that they push a
946 // second test-only DefaultProfile.
Darin Petkove7c6ad32012-06-29 10:22:09 +0200947 for (vector<ProfileRefPtr>::reverse_iterator rit = profiles_.rbegin();
948 rit != profiles_.rend(); ++rit) {
949 if ((*rit)->UpdateDevice(to_update)) {
950 return;
951 }
952 }
953}
954
Wade Guthrie60a37062013-04-02 11:39:09 -0700955void Manager::UpdateWiFiProvider() {
956 // Saves |wifi_provider_| to the topmost profile that accepts it (ordinary
957 // profiles don't update but default profiles do). Normally, the topmost
958 // updating profile would be the DefaultProfile at the bottom of the stack.
959 // Autotests, differ from the normal scenario, however, in that they push a
960 // second test-only DefaultProfile.
961 for (vector<ProfileRefPtr>::reverse_iterator rit = profiles_.rbegin();
962 rit != profiles_.rend(); ++rit) {
963 if ((*rit)->UpdateWiFiProvider(*wifi_provider_)) {
964 return;
965 }
966 }
967}
968
Gary Moraind93615e2012-04-27 11:50:03 -0700969void Manager::SaveServiceToProfile(const ServiceRefPtr &to_update) {
970 if (IsServiceEphemeral(to_update)) {
971 if (profiles_.empty()) {
972 LOG(ERROR) << "Cannot assign profile to service: no profiles exist!";
973 } else {
974 MoveServiceToProfile(to_update, profiles_.back());
975 }
976 } else {
977 to_update->profile()->UpdateService(to_update);
978 }
979}
980
Paul Stewart4d5efb72012-09-17 12:24:34 -0700981bool Manager::LoadProperties(const scoped_refptr<DefaultProfile> &profile) {
982 if (!profile->LoadManagerProperties(&props_)) {
983 return false;
984 }
985 SetIgnoredDNSSearchPaths(props_.ignored_dns_search_paths, NULL);
986 return true;
987}
988
Darin Petkov3ec55342012-09-28 14:04:44 +0200989void Manager::AddTerminationAction(const string &name,
Gary Moraina9fb3252012-05-31 12:05:31 -0700990 const base::Closure &start) {
Darin Petkov3ec55342012-09-28 14:04:44 +0200991 if (termination_actions_.IsEmpty() && power_manager_.get()) {
992 power_manager_->AddSuspendDelayCallback(
993 kPowerManagerKey,
Daniel Erat0818cca2012-12-14 10:16:21 -0800994 Bind(&Manager::OnSuspendImminent, AsWeakPtr()));
995 CHECK(!suspend_delay_registered_);
996 suspend_delay_registered_ = power_manager_->RegisterSuspendDelay(
997 base::TimeDelta::FromMilliseconds(
998 kTerminationActionsTimeoutMilliseconds),
Daniel Eratf9753672013-01-24 10:17:02 -0800999 kSuspendDelayDescription,
Daniel Erat0818cca2012-12-14 10:16:21 -08001000 &suspend_delay_id_);
Darin Petkov3ec55342012-09-28 14:04:44 +02001001 }
Gary Moraina9fb3252012-05-31 12:05:31 -07001002 termination_actions_.Add(name, start);
1003}
1004
Darin Petkov3ec55342012-09-28 14:04:44 +02001005void Manager::TerminationActionComplete(const string &name) {
Gary Moraina9fb3252012-05-31 12:05:31 -07001006 termination_actions_.ActionComplete(name);
1007}
1008
Darin Petkov3ec55342012-09-28 14:04:44 +02001009void Manager::RemoveTerminationAction(const string &name) {
1010 if (termination_actions_.IsEmpty()) {
1011 return;
1012 }
Gary Moraina9fb3252012-05-31 12:05:31 -07001013 termination_actions_.Remove(name);
Darin Petkov3ec55342012-09-28 14:04:44 +02001014 if (termination_actions_.IsEmpty() && power_manager_.get()) {
Daniel Erat0818cca2012-12-14 10:16:21 -08001015 if (suspend_delay_registered_) {
1016 power_manager_->UnregisterSuspendDelay(suspend_delay_id_);
1017 suspend_delay_registered_ = false;
1018 suspend_delay_id_ = 0;
1019 }
Darin Petkov3ec55342012-09-28 14:04:44 +02001020 power_manager_->RemoveSuspendDelayCallback(kPowerManagerKey);
1021 }
Gary Moraina9fb3252012-05-31 12:05:31 -07001022}
1023
1024void Manager::RunTerminationActions(
Darin Petkov3ec55342012-09-28 14:04:44 +02001025 const base::Callback<void(const Error &)> &done) {
1026 LOG(INFO) << "Running termination actions.";
1027 termination_actions_.Run(kTerminationActionsTimeoutMilliseconds, done);
Gary Moraina9fb3252012-05-31 12:05:31 -07001028}
1029
Arman Ugurayab22c162012-10-08 19:08:38 -07001030bool Manager::RunTerminationActionsAndNotifyMetrics(
1031 const base::Callback<void(const Error &)> &done,
1032 Metrics::TerminationActionReason reason) {
1033 if (termination_actions_.IsEmpty())
1034 return false;
1035
1036 metrics_->NotifyTerminationActionsStarted(reason);
1037 RunTerminationActions(done);
1038 return true;
1039}
1040
Darin Petkova5e07ef2012-07-09 14:27:57 +02001041int Manager::RegisterDefaultServiceCallback(const ServiceCallback &callback) {
1042 default_service_callbacks_[++default_service_callback_tag_] = callback;
1043 return default_service_callback_tag_;
1044}
1045
1046void Manager::DeregisterDefaultServiceCallback(int tag) {
1047 default_service_callbacks_.erase(tag);
1048}
1049
Christopher Wiley0d9cf0c2013-02-19 19:24:57 -08001050void Manager::VerifyDestination(const string &certificate,
1051 const string &public_key,
1052 const string &nonce,
1053 const string &signed_data,
1054 const string &destination_udn,
1055 const ResultBoolCallback &cb,
1056 Error *error) {
Christopher Wiley1057cd72013-02-28 15:21:29 -08001057 vector<ServiceRefPtr>::iterator sit;
1058 // For now, we only support a single connected WiFi service. If we change
1059 // that, we'll need to revisit this.
1060 for (sit = services_.begin(); sit != services_.end(); ++sit) {
1061 if ((*sit)->technology() != Technology::kWifi || !(*sit)->IsConnected()) {
1062 continue;
1063 }
1064 break;
1065 }
1066 if (sit == services_.end()) {
1067 error->Populate(Error::kOperationFailed,
1068 "Unable to find connected WiFi service.");
1069 return;
1070 }
1071 WiFiService *service = reinterpret_cast<WiFiService *>(&(*(*sit)));
1072 crypto_util_proxy_->VerifyDestination(certificate, public_key, nonce,
1073 signed_data, destination_udn,
1074 service->ssid(), service->bssid(),
1075 cb, error);
1076}
1077
1078void Manager::VerifyToEncryptLink(string public_key,
1079 string data,
1080 ResultStringCallback cb,
1081 const Error &error,
1082 bool success) {
1083 if (!success || !error.IsSuccess()) {
1084 CHECK(error.IsFailure()) << "Return code from CryptoUtilProxy "
1085 << "inconsistent with error code.";
1086 cb.Run(error, "");
1087 return;
1088 }
1089 Error encrypt_error;
1090 if (!crypto_util_proxy_->EncryptData(public_key, data, cb, &encrypt_error)) {
1091 CHECK(error.IsFailure()) << "CryptoUtilProxy::EncryptData returned "
1092 << "inconsistently.";
1093 cb.Run(error, "");
1094 }
Christopher Wiley0d9cf0c2013-02-19 19:24:57 -08001095}
1096
1097void Manager::VerifyAndEncryptData(const string &certificate,
1098 const string &public_key,
1099 const string &nonce,
1100 const string &signed_data,
1101 const string &destination_udn,
1102 const string &data,
1103 const ResultStringCallback &cb,
1104 Error *error) {
Christopher Wiley1057cd72013-02-28 15:21:29 -08001105 ResultBoolCallback on_verification_success = Bind(
1106 &Manager::VerifyToEncryptLink, AsWeakPtr(), public_key, data, cb);
1107 VerifyDestination(certificate, public_key, nonce, signed_data,
1108 destination_udn, on_verification_success, error);
Christopher Wiley0d9cf0c2013-02-19 19:24:57 -08001109}
1110
1111void Manager::VerifyAndEncryptCredentials(const string &certificate,
1112 const string &public_key,
1113 const string &nonce,
1114 const string &signed_data,
1115 const string &destination_udn,
1116 const string &network_path,
1117 const ResultStringCallback &cb,
1118 Error *error) {
Christopher Wiley1057cd72013-02-28 15:21:29 -08001119 // This is intentionally left unimplemented until we have a security review.
Christopher Wiley0d9cf0c2013-02-19 19:24:57 -08001120 error->Populate(Error::kNotImplemented, "Not implemented");
1121}
1122
Darin Petkova5e07ef2012-07-09 14:27:57 +02001123void Manager::NotifyDefaultServiceChanged(const ServiceRefPtr &service) {
1124 for (map<int, ServiceCallback>::const_iterator it =
1125 default_service_callbacks_.begin();
1126 it != default_service_callbacks_.end(); ++it) {
1127 it->second.Run(service);
1128 }
1129 metrics_->NotifyDefaultServiceChanged(service);
Paul Stewart49739c02012-08-08 17:24:03 -07001130 EmitDefaultService();
1131}
1132
1133void Manager::EmitDefaultService() {
1134 RpcIdentifier rpc_identifier = GetDefaultServiceRpcIdentifier(NULL);
1135 if (rpc_identifier != default_service_rpc_identifier_) {
1136 adaptor_->EmitRpcIdentifierChanged(shill::kDefaultServiceProperty,
1137 rpc_identifier);
1138 default_service_rpc_identifier_ = rpc_identifier;
1139 }
Darin Petkova5e07ef2012-07-09 14:27:57 +02001140}
1141
Darin Petkovca621542012-07-25 14:25:56 +02001142void Manager::OnPowerStateChanged(
1143 PowerManagerProxyDelegate::SuspendState power_state) {
1144 if (power_state == PowerManagerProxyDelegate::kOn) {
Christopher Wiley0801d192012-09-24 11:57:15 -07001145 vector<ServiceRefPtr>::iterator sit;
1146 for (sit = services_.begin(); sit != services_.end(); ++sit) {
1147 (*sit)->OnAfterResume();
1148 }
Darin Petkovca621542012-07-25 14:25:56 +02001149 SortServices();
mukesh agrawal784566d2012-08-08 18:32:58 -07001150 vector<DeviceRefPtr>::iterator it;
1151 for (it = devices_.begin(); it != devices_.end(); ++it) {
1152 (*it)->OnAfterResume();
1153 }
1154 } else if (power_state == PowerManagerProxyDelegate::kMem) {
1155 vector<DeviceRefPtr>::iterator it;
1156 for (it = devices_.begin(); it != devices_.end(); ++it) {
1157 (*it)->OnBeforeSuspend();
1158 }
Darin Petkovca621542012-07-25 14:25:56 +02001159 }
1160}
1161
Daniel Erat0818cca2012-12-14 10:16:21 -08001162void Manager::OnSuspendImminent(int suspend_id) {
Arman Ugurayab22c162012-10-08 19:08:38 -07001163 if (!RunTerminationActionsAndNotifyMetrics(
Daniel Erat0818cca2012-12-14 10:16:21 -08001164 Bind(&Manager::OnSuspendActionsComplete, AsWeakPtr(), suspend_id),
Arman Ugurayab22c162012-10-08 19:08:38 -07001165 Metrics::kTerminationActionReasonSuspend)) {
1166 LOG(INFO) << "No suspend actions were run.";
Daniel Erat0818cca2012-12-14 10:16:21 -08001167 power_manager_->ReportSuspendReadiness(suspend_delay_id_, suspend_id);
Arman Ugurayab22c162012-10-08 19:08:38 -07001168 }
Darin Petkov3ec55342012-09-28 14:04:44 +02001169}
1170
Daniel Erat0818cca2012-12-14 10:16:21 -08001171void Manager::OnSuspendActionsComplete(int suspend_id, const Error &error) {
Darin Petkov3ec55342012-09-28 14:04:44 +02001172 LOG(INFO) << "Finished suspend actions. Result: " << error;
Arman Ugurayab22c162012-10-08 19:08:38 -07001173 metrics_->NotifyTerminationActionsCompleted(
1174 Metrics::kTerminationActionReasonSuspend, error.IsSuccess());
Daniel Erat0818cca2012-12-14 10:16:21 -08001175 power_manager_->ReportSuspendReadiness(suspend_delay_id_, suspend_id);
Darin Petkov3ec55342012-09-28 14:04:44 +02001176}
1177
Paul Stewartfdd16072011-09-16 12:41:35 -07001178void Manager::FilterByTechnology(Technology::Identifier tech,
Paul Stewart3c504012013-01-17 17:49:58 -08001179 vector<DeviceRefPtr> *found) const {
Chris Masone9be4a9d2011-05-16 15:44:09 -07001180 CHECK(found);
Paul Stewart3c504012013-01-17 17:49:58 -08001181 vector<DeviceRefPtr>::const_iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -07001182 for (it = devices_.begin(); it != devices_.end(); ++it) {
Joshua Krollda798622012-06-05 12:30:48 -07001183 if ((*it)->technology() == tech)
Chris Masone9be4a9d2011-05-16 15:44:09 -07001184 found->push_back(*it);
1185 }
1186}
1187
Darin Petkov457728b2013-01-09 09:49:08 +01001188ServiceRefPtr Manager::FindService(const string &name) {
Chris Masonec1e50412011-06-07 13:04:53 -07001189 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -07001190 for (it = services_.begin(); it != services_.end(); ++it) {
Darin Petkov457728b2013-01-09 09:49:08 +01001191 if (name == (*it)->unique_name())
Chris Masonee0dea762011-06-09 09:06:03 -07001192 return *it;
Chris Masone9be4a9d2011-05-16 15:44:09 -07001193 }
Chris Masonee0dea762011-06-09 09:06:03 -07001194 return NULL;
Chris Masone9be4a9d2011-05-16 15:44:09 -07001195}
1196
Paul Stewart49739c02012-08-08 17:24:03 -07001197void Manager::HelpRegisterConstDerivedRpcIdentifier(
1198 const string &name,
1199 RpcIdentifier(Manager::*get)(Error *error)) {
1200 store_.RegisterDerivedRpcIdentifier(
1201 name,
1202 RpcIdentifierAccessor(
1203 new CustomAccessor<Manager, RpcIdentifier>(this, get, NULL)));
1204}
1205
mukesh agrawal2366eed2012-03-20 18:21:50 -07001206void Manager::HelpRegisterConstDerivedRpcIdentifiers(
1207 const string &name,
Jason Glasgowdf7c5532012-05-14 14:41:45 -04001208 RpcIdentifiers(Manager::*get)(Error *error)) {
mukesh agrawal2366eed2012-03-20 18:21:50 -07001209 store_.RegisterDerivedRpcIdentifiers(
1210 name,
1211 RpcIdentifiersAccessor(
1212 new CustomAccessor<Manager, RpcIdentifiers>(this, get, NULL)));
1213}
1214
mukesh agrawalffa3d042011-10-06 15:26:10 -07001215void Manager::HelpRegisterDerivedString(
1216 const string &name,
Gaurav Shah1b7a6162011-11-09 11:41:01 -08001217 string(Manager::*get)(Error *),
mukesh agrawalffa3d042011-10-06 15:26:10 -07001218 void(Manager::*set)(const string&, Error *)) {
Chris Masone27c4aa52011-07-02 13:10:14 -07001219 store_.RegisterDerivedString(
1220 name,
1221 StringAccessor(new CustomAccessor<Manager, string>(this, get, set)));
Chris Masoneb925cc82011-06-22 15:39:57 -07001222}
1223
mukesh agrawalffa3d042011-10-06 15:26:10 -07001224void Manager::HelpRegisterDerivedStrings(
1225 const string &name,
Gaurav Shah1b7a6162011-11-09 11:41:01 -08001226 Strings(Manager::*get)(Error *),
mukesh agrawalffa3d042011-10-06 15:26:10 -07001227 void(Manager::*set)(const Strings &, Error *)) {
Chris Masone27c4aa52011-07-02 13:10:14 -07001228 store_.RegisterDerivedStrings(
1229 name,
1230 StringsAccessor(new CustomAccessor<Manager, Strings>(this, get, set)));
Chris Masoneb925cc82011-06-22 15:39:57 -07001231}
1232
Paul Stewart22aa71b2011-09-16 12:15:11 -07001233void Manager::SortServices() {
Paul Stewartdfa46052012-06-26 09:44:14 -07001234 // We might be called in the middle of a series of events that
1235 // may result in multiple calls to Manager::SortServices, or within
1236 // an outer loop that may also be traversing the services_ list.
1237 // Defer this work to the event loop.
1238 if (sort_services_task_.IsCancelled()) {
1239 sort_services_task_.Reset(Bind(&Manager::SortServicesTask, AsWeakPtr()));
1240 dispatcher_->PostTask(sort_services_task_.callback());
1241 }
1242}
1243
1244void Manager::SortServicesTask() {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001245 SLOG(Manager, 4) << "In " << __func__;
Paul Stewartdfa46052012-06-26 09:44:14 -07001246 sort_services_task_.Cancel();
Thieu Lea20cbc22012-01-09 22:01:43 +00001247 ServiceRefPtr default_service;
1248
Paul Stewartc1dec4d2011-12-08 15:25:28 -08001249 if (!services_.empty()) {
Paul Stewarte2bad7c2012-03-14 08:55:33 -07001250 // Keep track of the service that is the candidate for the default
1251 // service. We have not yet tested to see if this service has a
1252 // connection.
Thieu Lea20cbc22012-01-09 22:01:43 +00001253 default_service = services_[0];
Paul Stewartc1dec4d2011-12-08 15:25:28 -08001254 }
Paul Stewart39db5ca2013-03-18 14:15:17 -07001255 const bool kCompareConnectivityState = true;
1256 sort(services_.begin(), services_.end(),
1257 ServiceSorter(kCompareConnectivityState, technology_order_));
Paul Stewarta41e38d2011-11-11 07:47:29 -08001258
Paul Stewarta41e38d2011-11-11 07:47:29 -08001259 adaptor_->EmitRpcIdentifierArrayChanged(flimflam::kServicesProperty,
Paul Stewartbfb82552012-10-24 16:48:48 -07001260 EnumerateAvailableServices(NULL));
1261 adaptor_->EmitRpcIdentifierArrayChanged(flimflam::kServiceWatchListProperty,
1262 EnumerateWatchedServices(NULL));
Gaurav Shah435de2c2011-11-17 19:01:07 -08001263
1264 Error error;
1265 adaptor_->EmitStringsChanged(flimflam::kConnectedTechnologiesProperty,
1266 ConnectedTechnologies(&error));
1267 adaptor_->EmitStringChanged(flimflam::kDefaultTechnologyProperty,
1268 DefaultTechnology(&error));
Paul Stewartc1dec4d2011-12-08 15:25:28 -08001269
1270 if (!services_.empty()) {
Thieu Lea20cbc22012-01-09 22:01:43 +00001271 ConnectionRefPtr default_connection = default_service->connection();
Darin Petkova5e07ef2012-07-09 14:27:57 +02001272 if (default_connection &&
1273 services_[0]->connection() != default_connection) {
Paul Stewartc1dec4d2011-12-08 15:25:28 -08001274 default_connection->SetIsDefault(false);
1275 }
Darin Petkova5e07ef2012-07-09 14:27:57 +02001276 if (services_[0]->connection()) {
Paul Stewartc1dec4d2011-12-08 15:25:28 -08001277 services_[0]->connection()->SetIsDefault(true);
Paul Stewart8596f9f2013-03-14 07:58:26 -07001278 if (default_service != services_[0]) {
1279 default_service = services_[0];
1280 LOG(INFO) << "Default service is now "
1281 << default_service->unique_name();
1282 }
Paul Stewarte2bad7c2012-03-14 08:55:33 -07001283 } else {
1284 default_service = NULL;
Paul Stewartc1dec4d2011-12-08 15:25:28 -08001285 }
1286 }
Darin Petkova5e07ef2012-07-09 14:27:57 +02001287 NotifyDefaultServiceChanged(default_service);
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001288 AutoConnect();
1289}
1290
Paul Stewart75225512012-01-26 22:51:33 -08001291bool Manager::MatchProfileWithService(const ServiceRefPtr &service) {
1292 vector<ProfileRefPtr>::reverse_iterator it;
1293 for (it = profiles_.rbegin(); it != profiles_.rend(); ++it) {
1294 if ((*it)->ConfigureService(service)) {
1295 break;
1296 }
1297 }
1298 if (it == profiles_.rend()) {
1299 ephemeral_profile_->AdoptService(service);
1300 return false;
1301 }
1302 return true;
1303}
1304
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001305void Manager::AutoConnect() {
Paul Stewart63864b62012-11-07 15:10:55 -08001306 if (!running_) {
1307 LOG(INFO) << "Auto-connect suppressed -- not running.";
1308 return;
1309 }
Darin Petkovca621542012-07-25 14:25:56 +02001310 if (power_manager_.get() &&
1311 power_manager_->power_state() != PowerManagerProxyDelegate::kOn &&
1312 power_manager_->power_state() != PowerManagerProxyDelegate::kUnknown) {
1313 LOG(INFO) << "Auto-connect suppressed -- power state is not 'on'.";
1314 return;
1315 }
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001316 if (services_.empty()) {
Darin Petkovca621542012-07-25 14:25:56 +02001317 LOG(INFO) << "Auto-connect suppressed -- no services.";
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001318 return;
1319 }
1320
Ben Chanfad4a0b2012-04-18 15:49:59 -07001321 if (SLOG_IS_ON(Manager, 4)) {
1322 SLOG(Manager, 4) << "Sorted service list: ";
mukesh agrawalddc378f2012-02-17 18:26:20 -08001323 for (size_t i = 0; i < services_.size(); ++i) {
1324 ServiceRefPtr service = services_[i];
1325 const char *compare_reason = NULL;
1326 if (i + 1 < services_.size()) {
Paul Stewart39db5ca2013-03-18 14:15:17 -07001327 const bool kCompareConnectivityState = true;
mukesh agrawalddc378f2012-02-17 18:26:20 -08001328 Service::Compare(
Paul Stewart39db5ca2013-03-18 14:15:17 -07001329 service, services_[i+1], kCompareConnectivityState,
1330 technology_order_, &compare_reason);
mukesh agrawalddc378f2012-02-17 18:26:20 -08001331 } else {
mukesh agrawalbf14e942012-03-02 14:36:34 -08001332 compare_reason = "last";
mukesh agrawalddc378f2012-02-17 18:26:20 -08001333 }
Darin Petkov457728b2013-01-09 09:49:08 +01001334 SLOG(Manager, 4) << "Service " << service->unique_name()
Ben Chanfad4a0b2012-04-18 15:49:59 -07001335 << " IsConnected: " << service->IsConnected()
1336 << " IsConnecting: " << service->IsConnecting()
1337 << " IsFailed: " << service->IsFailed()
1338 << " connectable: " << service->connectable()
1339 << " auto_connect: " << service->auto_connect()
1340 << " favorite: " << service->favorite()
1341 << " priority: " << service->priority()
mukesh agrawal43970a22013-02-15 16:00:07 -08001342 << " crypto_algorithm: " << service->crypto_algorithm()
1343 << " key_rotation: " << service->key_rotation()
1344 << " endpoint_auth: " << service->endpoint_auth()
Ben Chanfad4a0b2012-04-18 15:49:59 -07001345 << " strength: " << service->strength()
Ben Chanfad4a0b2012-04-18 15:49:59 -07001346 << " sorted: " << compare_reason;
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001347 }
1348 }
1349
Paul Stewart3d9bcf52011-12-12 15:02:22 -08001350 // Perform auto-connect.
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001351 for (vector<ServiceRefPtr>::iterator it = services_.begin();
1352 it != services_.end(); ++it) {
1353 if ((*it)->auto_connect()) {
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001354 (*it)->AutoConnect();
Paul Stewart3d9bcf52011-12-12 15:02:22 -08001355 }
1356 }
Paul Stewart22aa71b2011-09-16 12:15:11 -07001357}
1358
Paul Stewart39db5ca2013-03-18 14:15:17 -07001359void Manager::ConnectToBestServices(Error */*error*/) {
1360 dispatcher_->PostTask(Bind(&Manager::ConnectToBestServicesTask, AsWeakPtr()));
1361}
1362
1363void Manager::ConnectToBestServicesTask() {
1364 vector<ServiceRefPtr> services_copy = services_;
1365 const bool kCompareConnectivityState = false;
1366 sort(services_copy.begin(), services_copy.end(),
1367 ServiceSorter(kCompareConnectivityState, technology_order_));
1368 set<Technology::Identifier> connecting_technologies;
1369 for (vector<ServiceRefPtr>::const_iterator it = services_copy.begin();
1370 it != services_copy.end();
1371 ++it) {
1372 if (!(*it)->connectable()) {
1373 // Due to service sort order, it is guaranteed that no services beyond
1374 // this one will be connectable either.
1375 break;
1376 }
1377 if (!(*it)->auto_connect()) {
1378 continue;
1379 }
1380 Technology::Identifier technology = (*it)->technology();
1381 if (!Technology::IsPrimaryConnectivityTechnology(technology) &&
1382 !IsOnline()) {
1383 // Non-primary services need some other service connected first.
1384 continue;
1385 }
1386 if (ContainsKey(connecting_technologies, technology)) {
1387 // We have already started a connection for this technology.
1388 continue;
1389 }
1390 connecting_technologies.insert(technology);
1391 if (!(*it)->IsConnected() && !(*it)->IsConnecting()) {
1392 // At first blush, it may seem that using Service::AutoConnect might
1393 // be the right choice, however Service::IsAutoConnectable and its
1394 // overridden implementations consider a host of conditions which
1395 // prevent it from attempting a connection which we'd like to ignore
1396 // for the purposes of this user-initiated action.
1397 Error error;
mukesh agrawaldc7b8442012-09-27 13:48:14 -07001398 (*it)->Connect(&error, __func__);
Paul Stewart39db5ca2013-03-18 14:15:17 -07001399 if (error.IsFailure()) {
1400 LOG(ERROR) << "Connection failed: " << error.message();
1401 }
1402 }
1403 }
1404}
1405
Darin Petkov4cbff5b2013-01-29 16:29:05 +01001406bool Manager::IsOnline() const {
Gary Morain028545d2012-04-07 14:55:52 -07001407 // |services_| is sorted such that connected services are first.
Darin Petkov4cbff5b2013-01-29 16:29:05 +01001408 return !services_.empty() && services_.front()->IsConnected();
1409}
1410
1411string Manager::CalculateState(Error */*error*/) {
1412 return IsOnline() ? flimflam::kStateOnline : flimflam::kStateOffline;
Chris Masoneb925cc82011-06-22 15:39:57 -07001413}
1414
Gaurav Shah1b7a6162011-11-09 11:41:01 -08001415vector<string> Manager::AvailableTechnologies(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -08001416 set<string> unique_technologies;
1417 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1418 it != devices_.end(); ++it) {
1419 unique_technologies.insert(
1420 Technology::NameFromIdentifier((*it)->technology()));
1421 }
1422 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -07001423}
1424
Gaurav Shah1b7a6162011-11-09 11:41:01 -08001425vector<string> Manager::ConnectedTechnologies(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -08001426 set<string> unique_technologies;
1427 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1428 it != devices_.end(); ++it) {
1429 if ((*it)->IsConnected())
1430 unique_technologies.insert(
1431 Technology::NameFromIdentifier((*it)->technology()));
1432 }
1433 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -07001434}
1435
Paul Stewart3c504012013-01-17 17:49:58 -08001436bool Manager::IsTechnologyConnected(Technology::Identifier technology) const {
1437 for (vector<DeviceRefPtr>::const_iterator it = devices_.begin();
1438 it != devices_.end(); ++it) {
1439 if ((*it)->technology() == technology && (*it)->IsConnected())
1440 return true;
1441 }
1442 return false;
1443}
1444
Darin Petkov58f0b6d2012-06-12 12:52:30 +02001445string Manager::DefaultTechnology(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -08001446 return (!services_.empty() && services_[0]->IsConnected()) ?
Darin Petkov58f0b6d2012-06-12 12:52:30 +02001447 services_[0]->GetTechnologyString() : "";
Chris Masoneb925cc82011-06-22 15:39:57 -07001448}
1449
Eric Shienbrood9a245532012-03-07 14:20:39 -05001450vector<string> Manager::EnabledTechnologies(Error */*error*/) {
1451 set<string> unique_technologies;
1452 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1453 it != devices_.end(); ++it) {
1454 if ((*it)->enabled())
1455 unique_technologies.insert(
1456 Technology::NameFromIdentifier((*it)->technology()));
1457 }
1458 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -07001459}
1460
Ben Chan5086b972013-01-15 21:51:38 -08001461vector<string> Manager::UninitializedTechnologies(Error */*error*/) {
1462 return device_info_.GetUninitializedTechnologies();
1463}
1464
Paul Stewartcb3eb892012-06-07 14:24:46 -07001465RpcIdentifiers Manager::EnumerateDevices(Error */*error*/) {
1466 RpcIdentifiers device_rpc_ids;
Chris Masone3c3f6a12011-07-01 10:01:41 -07001467 for (vector<DeviceRefPtr>::const_iterator it = devices_.begin();
1468 it != devices_.end();
1469 ++it) {
1470 device_rpc_ids.push_back((*it)->GetRpcIdentifier());
1471 }
1472 return device_rpc_ids;
1473}
1474
Paul Stewartcb3eb892012-06-07 14:24:46 -07001475RpcIdentifiers Manager::EnumerateProfiles(Error */*error*/) {
1476 RpcIdentifiers profile_rpc_ids;
Paul Stewart1b253142012-01-26 14:05:52 -08001477 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
1478 it != profiles_.end();
1479 ++it) {
1480 profile_rpc_ids.push_back((*it)->GetRpcIdentifier());
1481 }
1482 return profile_rpc_ids;
1483}
1484
Gaurav Shah1b7a6162011-11-09 11:41:01 -08001485vector<string> Manager::EnumerateAvailableServices(Error */*error*/) {
Chris Masone3c3f6a12011-07-01 10:01:41 -07001486 vector<string> service_rpc_ids;
1487 for (vector<ServiceRefPtr>::const_iterator it = services_.begin();
1488 it != services_.end();
1489 ++it) {
Paul Stewartbfb82552012-10-24 16:48:48 -07001490 if ((*it)->IsVisible()) {
1491 service_rpc_ids.push_back((*it)->GetRpcIdentifier());
1492 }
Chris Masone3c3f6a12011-07-01 10:01:41 -07001493 }
1494 return service_rpc_ids;
1495}
1496
Paul Stewart3c504012013-01-17 17:49:58 -08001497RpcIdentifiers Manager::EnumerateCompleteServices(Error */*error*/) {
1498 vector<string> service_rpc_ids;
1499 for (vector<ServiceRefPtr>::const_iterator it = services_.begin();
1500 it != services_.end();
1501 ++it) {
1502 service_rpc_ids.push_back((*it)->GetRpcIdentifier());
1503 }
1504 return service_rpc_ids;
1505}
1506
Paul Stewartbfb82552012-10-24 16:48:48 -07001507RpcIdentifiers Manager::EnumerateWatchedServices(Error */*error*/) {
1508 vector<string> service_rpc_ids;
1509 for (vector<ServiceRefPtr>::const_iterator it = services_.begin();
1510 it != services_.end();
1511 ++it) {
1512 if ((*it)->IsVisible() && (*it)->IsActive(NULL)) {
1513 service_rpc_ids.push_back((*it)->GetRpcIdentifier());
1514 }
1515 }
1516 return service_rpc_ids;
Chris Masone3c3f6a12011-07-01 10:01:41 -07001517}
1518
Paul Stewart1b253142012-01-26 14:05:52 -08001519string Manager::GetActiveProfileRpcIdentifier(Error */*error*/) {
1520 return ActiveProfile()->GetRpcIdentifier();
Chris Masone7aa5f902011-07-11 11:13:35 -07001521}
1522
Paul Stewart10e9e4e2012-04-26 19:46:28 -07001523string Manager::GetCheckPortalList(Error */*error*/) {
Jason Glasgowdf7c5532012-05-14 14:41:45 -04001524 return use_startup_portal_list_ ? startup_portal_list_ :
1525 props_.check_portal_list;
Paul Stewart10e9e4e2012-04-26 19:46:28 -07001526}
1527
1528void Manager::SetCheckPortalList(const string &portal_list, Error *error) {
1529 props_.check_portal_list = portal_list;
1530 use_startup_portal_list_ = false;
1531}
1532
Paul Stewart4d5efb72012-09-17 12:24:34 -07001533string Manager::GetIgnoredDNSSearchPaths(Error */*error*/) {
1534 return props_.ignored_dns_search_paths;
1535}
1536
1537void Manager::SetIgnoredDNSSearchPaths(const string &ignored_paths,
1538 Error */*error*/) {
1539 props_.ignored_dns_search_paths = ignored_paths;
1540 vector<string> ignored_path_list;
1541 if (!ignored_paths.empty()) {
1542 base::SplitString(ignored_paths, ',', &ignored_path_list);
1543 }
1544 resolver_->set_ignored_search_list(ignored_path_list);
1545}
1546
mukesh agrawal32399322011-09-01 10:53:43 -07001547// called via RPC (e.g., from ManagerDBusAdaptor)
Darin Petkovb65c2452012-02-23 15:17:06 +01001548ServiceRefPtr Manager::GetService(const KeyValueStore &args, Error *error) {
Paul Stewart7f5ad572012-06-04 15:18:54 -07001549 if (args.ContainsString(flimflam::kTypeProperty) &&
1550 args.GetString(flimflam::kTypeProperty) == flimflam::kTypeVPN) {
1551 // GetService on a VPN service should actually perform ConfigureService.
1552 // TODO(pstew): Remove this hack and change Chrome to use ConfigureService
1553 // instead, when we no longer need to support flimflam. crosbug.com/31523
1554 return ConfigureService(args, error);
1555 }
Paul Stewart2c575d22012-12-07 12:28:57 -08001556
1557 ServiceRefPtr service = GetServiceInner(args, error);
1558 if (service) {
1559 // Configures the service using the rest of the passed-in arguments.
1560 service->Configure(args, error);
1561 }
1562
1563 return service;
Paul Stewart7f5ad572012-06-04 15:18:54 -07001564}
1565
1566ServiceRefPtr Manager::GetServiceInner(const KeyValueStore &args,
1567 Error *error) {
Paul Stewart13ed2252012-03-21 12:52:46 -07001568 if (args.ContainsString(flimflam::kGuidProperty)) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001569 SLOG(Manager, 2) << __func__ << ": searching by GUID";
Paul Stewart13ed2252012-03-21 12:52:46 -07001570 ServiceRefPtr service =
1571 GetServiceWithGUID(args.GetString(flimflam::kGuidProperty), NULL);
1572 if (service) {
Paul Stewart13ed2252012-03-21 12:52:46 -07001573 return service;
1574 }
1575 }
1576
Darin Petkovb65c2452012-02-23 15:17:06 +01001577 if (!args.ContainsString(flimflam::kTypeProperty)) {
Paul Stewart7f61e522012-03-22 11:13:45 -07001578 Error::PopulateAndLog(error, Error::kInvalidArguments, kErrorTypeRequired);
Darin Petkovb65c2452012-02-23 15:17:06 +01001579 return NULL;
1580 }
1581
1582 string type = args.GetString(flimflam::kTypeProperty);
Darin Petkovd1cd7972012-05-22 15:26:15 +02001583 if (type == flimflam::kTypeVPN) {
1584 SLOG(Manager, 2) << __func__ << ": getting VPN Service";
Darin Petkovc3505a52013-03-18 15:13:29 +01001585 return vpn_provider_->GetService(args, error);
Darin Petkovd1cd7972012-05-22 15:26:15 +02001586 }
Darin Petkovb65c2452012-02-23 15:17:06 +01001587 if (type == flimflam::kTypeWifi) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001588 SLOG(Manager, 2) << __func__ << ": getting WiFi Service";
Paul Stewart3c504012013-01-17 17:49:58 -08001589 return wifi_provider_->GetService(args, error);
Darin Petkovb65c2452012-02-23 15:17:06 +01001590 }
Darin Petkovd1cd7972012-05-22 15:26:15 +02001591 if (type == flimflam::kTypeWimax) {
1592 SLOG(Manager, 2) << __func__ << ": getting WiMAX Service";
1593 return wimax_provider_.GetService(args, error);
Darin Petkovb65c2452012-02-23 15:17:06 +01001594 }
mukesh agrawal06175d72012-04-23 16:46:01 -07001595 Error::PopulateAndLog(error, Error::kNotSupported,
1596 kErrorUnsupportedServiceType);
Darin Petkovb65c2452012-02-23 15:17:06 +01001597 return NULL;
1598}
1599
Paul Stewart7f61e522012-03-22 11:13:45 -07001600// called via RPC (e.g., from ManagerDBusAdaptor)
Paul Stewart7f5ad572012-06-04 15:18:54 -07001601ServiceRefPtr Manager::ConfigureService(const KeyValueStore &args,
1602 Error *error) {
Paul Stewart7f61e522012-03-22 11:13:45 -07001603 ProfileRefPtr profile = ActiveProfile();
1604 bool profile_specified = args.ContainsString(flimflam::kProfileProperty);
1605 if (profile_specified) {
1606 string profile_rpcid = args.GetString(flimflam::kProfileProperty);
1607 profile = LookupProfileByRpcIdentifier(profile_rpcid);
1608 if (!profile) {
1609 Error::PopulateAndLog(error, Error::kInvalidArguments,
1610 "Invalid profile name " + profile_rpcid);
Paul Stewart7f5ad572012-06-04 15:18:54 -07001611 return NULL;
Paul Stewart7f61e522012-03-22 11:13:45 -07001612 }
1613 }
1614
Paul Stewart7f5ad572012-06-04 15:18:54 -07001615 ServiceRefPtr service = GetServiceInner(args, error);
Paul Stewart7f61e522012-03-22 11:13:45 -07001616 if (error->IsFailure() || !service) {
1617 LOG(ERROR) << "GetService failed; returning upstream error.";
Paul Stewart7f5ad572012-06-04 15:18:54 -07001618 return NULL;
Paul Stewart7f61e522012-03-22 11:13:45 -07001619 }
1620
Paul Stewart2c575d22012-12-07 12:28:57 -08001621 // First pull in any stored configuration associated with the service.
1622 if (service->profile() == profile) {
Darin Petkov457728b2013-01-09 09:49:08 +01001623 SLOG(Manager, 2) << __func__ << ": service " << service->unique_name()
Paul Stewart2c575d22012-12-07 12:28:57 -08001624 << " is already a member of profile "
1625 << profile->GetFriendlyName()
1626 << " so a load is not necessary.";
1627 } else if (profile->LoadService(service)) {
1628 SLOG(Manager, 2) << __func__ << ": applied stored information from profile "
1629 << profile->GetFriendlyName()
1630 << " into service "
Darin Petkov457728b2013-01-09 09:49:08 +01001631 << service->unique_name();
Paul Stewart2c575d22012-12-07 12:28:57 -08001632 } else {
1633 SLOG(Manager, 2) << __func__ << ": no previous information in profile "
1634 << profile->GetFriendlyName()
1635 << " exists for service "
Darin Petkov457728b2013-01-09 09:49:08 +01001636 << service->unique_name();
Paul Stewart2c575d22012-12-07 12:28:57 -08001637 }
1638
1639 // Overlay this with the passed-in configuration parameters.
1640 service->Configure(args, error);
1641
mukesh agrawal06175d72012-04-23 16:46:01 -07001642 // Overwrite the profile data with the resulting configured service.
Paul Stewart7f61e522012-03-22 11:13:45 -07001643 if (!profile->UpdateService(service)) {
1644 Error::PopulateAndLog(error, Error::kInternalError,
1645 "Unable to save service to profile");
Paul Stewart7f5ad572012-06-04 15:18:54 -07001646 return NULL;
Paul Stewart7f61e522012-03-22 11:13:45 -07001647 }
1648
1649 if (HasService(service)) {
1650 // If the service has been registered (it may not be -- as is the case
1651 // with invisible WiFi networks), we can now transfer the service between
1652 // profiles.
Paul Stewart10ccbb32012-04-26 15:59:30 -07001653 if (IsServiceEphemeral(service) ||
Paul Stewart7f61e522012-03-22 11:13:45 -07001654 (profile_specified && service->profile() != profile)) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001655 SLOG(Manager, 2) << "Moving service to profile "
1656 << profile->GetFriendlyName();
Paul Stewart7f61e522012-03-22 11:13:45 -07001657 if (!MoveServiceToProfile(service, profile)) {
1658 Error::PopulateAndLog(error, Error::kInternalError,
1659 "Unable to move service to profile");
1660 }
1661 }
1662 }
Paul Stewart4357f4e2012-04-26 17:39:26 -07001663
1664 // Notify the service that a profile has been configured for it.
1665 service->OnProfileConfigured();
Paul Stewart7f5ad572012-06-04 15:18:54 -07001666
1667 return service;
Paul Stewart7f61e522012-03-22 11:13:45 -07001668}
1669
Paul Stewartd2e1c362013-03-03 19:06:07 -08001670// called via RPC (e.g., from ManagerDBusAdaptor)
1671ServiceRefPtr Manager::ConfigureServiceForProfile(
1672 const string &profile_rpcid, const KeyValueStore &args, Error *error) {
1673 if (args.LookupString(flimflam::kTypeProperty, "") != flimflam::kTypeWifi) {
1674 Error::PopulateAndLog(error, Error::kNotSupported,
1675 "This method only supports WiFi services");
1676 return NULL;
1677 }
1678
1679 ProfileRefPtr profile = LookupProfileByRpcIdentifier(profile_rpcid);
1680 if (!profile) {
1681 Error::PopulateAndLog(error, Error::kNotFound,
1682 "Profile specified was not found");
1683 return NULL;
1684 }
1685 if (args.LookupString(flimflam::kProfileProperty,
1686 profile_rpcid) != profile_rpcid) {
1687 Error::PopulateAndLog(error, Error::kInvalidArguments,
1688 "Profile argument does not match that in "
1689 "the configuration arguments");
1690 return NULL;
1691 }
1692
1693 ServiceRefPtr service;
1694 if (args.ContainsString(flimflam::kGuidProperty)) {
1695 SLOG(Manager, 2) << __func__ << ": searching by GUID";
1696 service = GetServiceWithGUID(args.GetString(flimflam::kGuidProperty), NULL);
1697 if (service && service->technology() != Technology::kWifi) {
1698 Error::PopulateAndLog(error, Error::kNotSupported,
1699 "This GUID matches a non-WiFi service");
1700 return NULL;
1701 }
1702 }
1703
1704 if (!service) {
1705 Error find_error;
1706 service = wifi_provider_->FindSimilarService(args, &find_error);
1707 }
1708
1709 // If no matching service exists, create a new service in the specified
1710 // profile using ConfigureService().
1711 if (!service) {
1712 KeyValueStore configure_args;
1713 configure_args.CopyFrom(args);
1714 configure_args.SetString(flimflam::kProfileProperty, profile_rpcid);
1715 return ConfigureService(configure_args, error);
1716 }
1717
1718 // The service already exists and is set to the desired profile,
1719 // the service is in the ephemeral profile, or the current profile
1720 // for the service appears before the desired profile, we need to
1721 // reassign the service to the new profile if necessary, leaving
1722 // the old profile intact (i.e, not calling Profile::AbandonService()).
1723 // Then, configure the properties on the service as well as its newly
1724 // associated profile.
1725 if (service->profile() == profile ||
1726 IsServiceEphemeral(service) ||
1727 IsProfileBefore(service->profile(), profile)) {
1728 SetupServiceInProfile(service, profile, args, error);
1729 return service;
1730 }
1731
1732 // The current profile for the service appears after the desired
1733 // profile. We must create a temporary service specifically for
1734 // the task of creating configuration data. This service will
1735 // neither inherit properties from the visible service, nor will
1736 // it exist after this function returns.
1737 service = wifi_provider_->CreateTemporaryService(args, error);
1738 if (!service || !error->IsSuccess()) {
1739 // Service::CreateTemporaryService() failed, and has set the error
1740 // appropriately.
1741 return NULL;
1742 }
1743
1744 // The profile may already have configuration for this service.
1745 profile->ConfigureService(service);
1746
1747 SetupServiceInProfile(service, profile, args, error);
1748
1749 // Although we have succeeded, this service will not exist, so its
1750 // path is of no use to the caller.
1751 DCHECK(service->HasOneRef());
1752 return NULL;
1753}
1754
1755void Manager::SetupServiceInProfile(ServiceRefPtr service,
1756 ProfileRefPtr profile,
1757 const KeyValueStore &args,
1758 Error *error) {
1759 service->SetProfile(profile);
1760 service->Configure(args, error);
1761 profile->UpdateService(service);
1762}
1763
Paul Stewart7a20aa42013-01-17 12:21:41 -08001764ServiceRefPtr Manager::FindMatchingService(const KeyValueStore &args,
1765 Error *error) {
1766 for (vector<ServiceRefPtr>::iterator it = services_.begin();
1767 it != services_.end(); ++it) {
1768 if ((*it)->DoPropertiesMatch(args)) {
1769 return *it;
1770 }
1771 }
1772 error->Populate(Error::kNotFound, "Matching service was not found");
1773 return NULL;
1774}
1775
Gaurav Shahb790aa22012-10-23 12:51:12 -07001776map<string, GeolocationInfos> Manager::GetNetworksForGeolocation() {
1777 map<string, GeolocationInfos> networks;
1778 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1779 it != devices_.end(); ++it) {
Wade Guthrie60a37062013-04-02 11:39:09 -07001780 switch ((*it)->technology()) {
Gaurav Shahb790aa22012-10-23 12:51:12 -07001781 // TODO(gauravsh): crosbug.com/35736 Need a strategy for combining
1782 // geolocation objects from multiple devices of the same technolgy.
1783 // Currently, we just pick the geolocation objects from the first found
1784 // device of each supported technology type.
1785 case Technology::kWifi:
1786 if (!ContainsKey(networks, kGeoWifiAccessPointsProperty))
1787 networks[kGeoWifiAccessPointsProperty] =
1788 (*it)->GetGeolocationObjects();
1789 break;
1790 case Technology::kCellular:
1791 if (!ContainsKey(networks, kGeoCellTowersProperty))
1792 networks[kGeoCellTowersProperty] = (*it)->GetGeolocationObjects();
1793 break;
1794 default:
1795 // Ignore other technologies.
1796 break;
1797 };
1798 }
1799 return networks;
1800};
1801
Paul Stewartc681fa02012-03-02 19:40:04 -08001802void Manager::RecheckPortal(Error */*error*/) {
1803 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1804 it != devices_.end(); ++it) {
1805 if ((*it)->RequestPortalDetection()) {
1806 // Only start Portal Detection on the device with the default connection.
1807 // We will get a "true" return value when we've found that device, and
1808 // can end our loop early as a result.
1809 break;
1810 }
1811 }
1812}
1813
Paul Stewartd215af62012-04-24 23:25:50 -07001814void Manager::RecheckPortalOnService(const ServiceRefPtr &service) {
1815 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1816 it != devices_.end(); ++it) {
1817 if ((*it)->IsConnectedToService(service)) {
1818 // As opposed to RecheckPortal() above, we explicitly stop and then
1819 // restart portal detection, since the service to recheck was explicitly
1820 // specified.
1821 (*it)->RestartPortalDetection();
1822 break;
1823 }
1824 }
1825}
1826
Wade Guthrie68d41092013-04-02 12:56:02 -07001827void Manager::RequestScan(Device::ScanType scan_type,
1828 const string &technology, Error *error) {
mukesh agrawal32399322011-09-01 10:53:43 -07001829 if (technology == flimflam::kTypeWifi || technology == "") {
1830 vector<DeviceRefPtr> wifi_devices;
Paul Stewartfdd16072011-09-16 12:41:35 -07001831 FilterByTechnology(Technology::kWifi, &wifi_devices);
mukesh agrawal32399322011-09-01 10:53:43 -07001832 for (vector<DeviceRefPtr>::iterator it = wifi_devices.begin();
1833 it != wifi_devices.end();
1834 ++it) {
Wade Guthrie68d41092013-04-02 12:56:02 -07001835 (*it)->Scan(scan_type, error);
mukesh agrawal32399322011-09-01 10:53:43 -07001836 }
1837 } else {
1838 // TODO(quiche): support scanning for other technologies?
Paul Stewartbe005172011-11-02 18:10:29 -07001839 Error::PopulateAndLog(error, Error::kInvalidArguments,
1840 "Unrecognized technology " + technology);
mukesh agrawal32399322011-09-01 10:53:43 -07001841 }
1842}
1843
Paul Stewart22aa71b2011-09-16 12:15:11 -07001844string Manager::GetTechnologyOrder() {
1845 vector<string> technology_names;
1846 for (vector<Technology::Identifier>::iterator it = technology_order_.begin();
1847 it != technology_order_.end();
1848 ++it) {
1849 technology_names.push_back(Technology::NameFromIdentifier(*it));
1850 }
1851
1852 return JoinString(technology_names, ',');
1853}
1854
1855void Manager::SetTechnologyOrder(const string &order, Error *error) {
1856 vector<Technology::Identifier> new_order;
Ben Chanfad4a0b2012-04-18 15:49:59 -07001857 SLOG(Manager, 2) << "Setting technology order to " << order;
Paul Stewart20088d82012-02-16 06:58:55 -08001858 if (!Technology::GetTechnologyVectorFromString(order, &new_order, error)) {
1859 return;
Paul Stewart22aa71b2011-09-16 12:15:11 -07001860 }
1861
1862 technology_order_ = new_order;
1863 SortServices();
1864}
1865
Paul Stewart75897df2011-04-27 09:05:53 -07001866} // namespace shill