blob: 537166c0aa82c2a5a44219ae9ab82016915965e7 [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 Petkov33af05c2012-02-28 10:10:30 +010044#include "shill/vpn_service.h"
mukesh agrawal7a4e4002011-09-06 11:26:05 -070045#include "shill/wifi.h"
46#include "shill/wifi_service.h"
Darin Petkovd1cd7972012-05-22 15:26:15 +020047#include "shill/wimax_service.h"
Paul Stewart75897df2011-04-27 09:05:53 -070048
Eric Shienbrood3e20a232012-02-16 11:35:56 -050049using base::Bind;
50using base::StringPrintf;
51using base::Unretained;
Darin Petkova5e07ef2012-07-09 14:27:57 +020052using std::map;
Gaurav Shah435de2c2011-11-17 19:01:07 -080053using std::set;
Paul Stewart75897df2011-04-27 09:05:53 -070054using std::string;
Chris Masone9be4a9d2011-05-16 15:44:09 -070055using std::vector;
Paul Stewart75897df2011-04-27 09:05:53 -070056
57namespace shill {
Paul Stewarte6132022011-08-16 09:11:02 -070058
Darin Petkovb65c2452012-02-23 15:17:06 +010059// statics
60const char Manager::kErrorNoDevice[] = "no wifi devices available";
61const char Manager::kErrorTypeRequired[] = "must specify service type";
62const char Manager::kErrorUnsupportedServiceType[] =
63 "service type is unsupported";
Arman Ugurayab22c162012-10-08 19:08:38 -070064// This timeout should be less than the upstart job timeout, otherwise
65// stats for termination actions might be lost.
66const int Manager::kTerminationActionsTimeoutMilliseconds = 4500;
Darin Petkov3ec55342012-09-28 14:04:44 +020067const char Manager::kPowerManagerKey[] = "manager";
mukesh agrawal7a4e4002011-09-06 11:26:05 -070068
Paul Stewart75897df2011-04-27 09:05:53 -070069Manager::Manager(ControlInterface *control_interface,
Darin Petkov887f2982011-07-14 16:10:17 -070070 EventDispatcher *dispatcher,
Thieu Le3426c8f2012-01-11 17:35:11 -080071 Metrics *metrics,
Chris Masone2ae797d2011-08-23 20:41:00 -070072 GLib *glib,
73 const string &run_directory,
74 const string &storage_directory,
75 const string &user_storage_format)
mukesh agrawal8a3188d2011-12-01 20:56:44 +000076 : dispatcher_(dispatcher),
mukesh agrawal8a3188d2011-12-01 20:56:44 +000077 run_path_(FilePath(run_directory)),
78 storage_path_(FilePath(storage_directory)),
79 user_storage_format_(user_storage_format),
80 adaptor_(control_interface->CreateManagerAdaptor(this)),
Thieu Le3426c8f2012-01-11 17:35:11 -080081 device_info_(control_interface, dispatcher, metrics, this),
82 modem_info_(control_interface, dispatcher, metrics, this, glib),
Darin Petkov33af05c2012-02-28 10:10:30 +010083 vpn_provider_(control_interface, dispatcher, metrics, this),
Darin Petkovb72b62e2012-05-15 16:55:36 +020084 wimax_provider_(control_interface, dispatcher, metrics, this),
Paul Stewart4d5efb72012-09-17 12:24:34 -070085 resolver_(Resolver::GetInstance()),
mukesh agrawal8a3188d2011-12-01 20:56:44 +000086 running_(false),
87 connect_profiles_to_rpc_(true),
88 ephemeral_profile_(new EphemeralProfile(control_interface, this)),
89 control_interface_(control_interface),
Thieu Le3426c8f2012-01-11 17:35:11 -080090 metrics_(metrics),
Paul Stewart10e9e4e2012-04-26 19:46:28 -070091 glib_(glib),
Gary Moraina9fb3252012-05-31 12:05:31 -070092 use_startup_portal_list_(false),
Darin Petkova5e07ef2012-07-09 14:27:57 +020093 termination_actions_(dispatcher),
Daniel Erat0818cca2012-12-14 10:16:21 -080094 suspend_delay_registered_(false),
95 suspend_delay_id_(0),
Darin Petkova5e07ef2012-07-09 14:27:57 +020096 default_service_callback_tag_(0) {
Chris Masone7aa5f902011-07-11 11:13:35 -070097 HelpRegisterDerivedString(flimflam::kActiveProfileProperty,
Paul Stewart1b253142012-01-26 14:05:52 -080098 &Manager::GetActiveProfileRpcIdentifier,
Chris Masone7aa5f902011-07-11 11:13:35 -070099 NULL);
Paul Stewartd408fdf2012-05-07 17:15:57 -0700100 store_.RegisterBool(flimflam::kArpGatewayProperty, &props_.arp_gateway);
Chris Masone27c4aa52011-07-02 13:10:14 -0700101 HelpRegisterDerivedStrings(flimflam::kAvailableTechnologiesProperty,
102 &Manager::AvailableTechnologies,
103 NULL);
Paul Stewart10e9e4e2012-04-26 19:46:28 -0700104 HelpRegisterDerivedString(flimflam::kCheckPortalListProperty,
105 &Manager::GetCheckPortalList,
106 &Manager::SetCheckPortalList);
Chris Masone27c4aa52011-07-02 13:10:14 -0700107 HelpRegisterDerivedStrings(flimflam::kConnectedTechnologiesProperty,
108 &Manager::ConnectedTechnologies,
109 NULL);
Chris Masone88cbd5f2011-07-03 14:30:04 -0700110 store_.RegisterString(flimflam::kCountryProperty, &props_.country);
Chris Masone27c4aa52011-07-02 13:10:14 -0700111 HelpRegisterDerivedString(flimflam::kDefaultTechnologyProperty,
112 &Manager::DefaultTechnology,
113 NULL);
Paul Stewart49739c02012-08-08 17:24:03 -0700114 HelpRegisterConstDerivedRpcIdentifier(
115 shill::kDefaultServiceProperty,
116 &Manager::GetDefaultServiceRpcIdentifier);
Paul Stewartcb3eb892012-06-07 14:24:46 -0700117 HelpRegisterConstDerivedRpcIdentifiers(flimflam::kDevicesProperty,
118 &Manager::EnumerateDevices);
Chris Masone88cbd5f2011-07-03 14:30:04 -0700119 HelpRegisterDerivedStrings(flimflam::kEnabledTechnologiesProperty,
120 &Manager::EnabledTechnologies,
121 NULL);
Paul Stewart4d5efb72012-09-17 12:24:34 -0700122 HelpRegisterDerivedString(shill::kIgnoredDNSSearchPathsProperty,
123 &Manager::GetIgnoredDNSSearchPaths,
124 &Manager::SetIgnoredDNSSearchPaths);
Paul Stewart036dba02012-08-07 12:34:41 -0700125 store_.RegisterString(shill::kLinkMonitorTechnologiesProperty,
126 &props_.link_monitor_technologies);
Chris Masone88cbd5f2011-07-03 14:30:04 -0700127 store_.RegisterBool(flimflam::kOfflineModeProperty, &props_.offline_mode);
128 store_.RegisterString(flimflam::kPortalURLProperty, &props_.portal_url);
Paul Stewartc681fa02012-03-02 19:40:04 -0800129 store_.RegisterInt32(kPortalCheckIntervalProperty,
130 &props_.portal_check_interval_seconds);
Paul Stewartcb3eb892012-06-07 14:24:46 -0700131 HelpRegisterConstDerivedRpcIdentifiers(flimflam::kProfilesProperty,
132 &Manager::EnumerateProfiles);
Paul Stewartc681fa02012-03-02 19:40:04 -0800133 store_.RegisterString(kHostNameProperty, &props_.host_name);
Chris Masone88cbd5f2011-07-03 14:30:04 -0700134 HelpRegisterDerivedString(flimflam::kStateProperty,
135 &Manager::CalculateState,
136 NULL);
mukesh agrawal2366eed2012-03-20 18:21:50 -0700137 HelpRegisterConstDerivedRpcIdentifiers(flimflam::kServicesProperty,
138 &Manager::EnumerateAvailableServices);
Paul Stewartcb3eb892012-06-07 14:24:46 -0700139 HelpRegisterConstDerivedRpcIdentifiers(flimflam::kServiceWatchListProperty,
140 &Manager::EnumerateWatchedServices);
Paul Stewartbf667612012-06-29 14:49:54 -0700141 store_.RegisterString(shill::kShortDNSTimeoutTechnologiesProperty,
142 &props_.short_dns_timeout_technologies);
Chris Masone3c3f6a12011-07-01 10:01:41 -0700143
mukesh agrawal84de5d22012-02-17 19:29:15 -0800144 // Set default technology order "by hand", to avoid invoking side
145 // effects of SetTechnologyOrder.
146 technology_order_.push_back(
Darin Petkov2f903b32012-04-18 12:56:43 +0200147 Technology::IdentifierFromName(flimflam::kTypeVPN));
148 technology_order_.push_back(
mukesh agrawal84de5d22012-02-17 19:29:15 -0800149 Technology::IdentifierFromName(flimflam::kTypeEthernet));
150 technology_order_.push_back(
151 Technology::IdentifierFromName(flimflam::kTypeWifi));
152 technology_order_.push_back(
Ben Chan3cafe382012-11-13 07:51:10 -0800153 Technology::IdentifierFromName(flimflam::kTypeWimax));
154 technology_order_.push_back(
mukesh agrawal84de5d22012-02-17 19:29:15 -0800155 Technology::IdentifierFromName(flimflam::kTypeCellular));
156
Ben Chanfad4a0b2012-04-18 15:49:59 -0700157 SLOG(Manager, 2) << "Manager initialized.";
Paul Stewart75897df2011-04-27 09:05:53 -0700158}
159
Darin Petkove7c6ad32012-06-29 10:22:09 +0200160Manager::~Manager() {}
Paul Stewart75897df2011-04-27 09:05:53 -0700161
mukesh agrawal8f317b62011-07-15 11:53:23 -0700162void Manager::AddDeviceToBlackList(const string &device_name) {
163 device_info_.AddDeviceToBlackList(device_name);
164}
165
Paul Stewart75897df2011-04-27 09:05:53 -0700166void Manager::Start() {
Paul Stewart0af98bf2011-05-10 17:38:08 -0700167 LOG(INFO) << "Manager started.";
Paul Stewarte6132022011-08-16 09:11:02 -0700168
Darin Petkov002c58e2012-06-19 02:56:05 +0200169 dbus_manager_.reset(new DBusManager());
170 dbus_manager_->Start();
171
Darin Petkov3ec55342012-09-28 14:04:44 +0200172 power_manager_.reset(
173 new PowerManager(dispatcher_, ProxyFactory::GetInstance()));
Darin Petkovca621542012-07-25 14:25:56 +0200174 power_manager_->AddStateChangeCallback(
Darin Petkov3ec55342012-09-28 14:04:44 +0200175 kPowerManagerKey,
Darin Petkovca621542012-07-25 14:25:56 +0200176 Bind(&Manager::OnPowerStateChanged, AsWeakPtr()));
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500177 // TODO(ers): weak ptr for metrics_?
178 PowerManager::PowerStateCallback cb =
179 Bind(&Metrics::NotifyPowerStateChange, Unretained(metrics_));
Thieu Leb84ba342012-03-02 15:15:19 -0800180 power_manager_->AddStateChangeCallback(Metrics::kMetricPowerManagerKey, cb);
181
Chris Masone2ae797d2011-08-23 20:41:00 -0700182 CHECK(file_util::CreateDirectory(run_path_)) << run_path_.value();
Paul Stewart4d5efb72012-09-17 12:24:34 -0700183 resolver_->set_path(run_path_.Append("resolv.conf"));
Chris Masone2ae797d2011-08-23 20:41:00 -0700184
Gaurav Shah71354762011-11-28 19:22:49 -0800185 InitializeProfiles();
Paul Stewart75897df2011-04-27 09:05:53 -0700186 running_ = true;
Chris Masone413a3192011-05-09 17:10:05 -0700187 adaptor_->UpdateRunning();
Paul Stewart0af98bf2011-05-10 17:38:08 -0700188 device_info_.Start();
Darin Petkov887f2982011-07-14 16:10:17 -0700189 modem_info_.Start();
Darin Petkov33af05c2012-02-28 10:10:30 +0100190 vpn_provider_.Start();
Darin Petkov9893d9c2012-05-17 15:27:31 -0700191 wimax_provider_.Start();
Paul Stewart75897df2011-04-27 09:05:53 -0700192}
193
194void Manager::Stop() {
195 running_ = false;
Paul Stewart212d60f2012-07-12 10:59:13 -0700196 // Persist device information to disk;
197 vector<DeviceRefPtr>::iterator devices_it;
198 for (devices_it = devices_.begin(); devices_it != devices_.end();
199 ++devices_it) {
200 UpdateDevice(*devices_it);
201 }
202
203 // Persist profile, service information to disk.
204 vector<ProfileRefPtr>::iterator profiles_it;
205 for (profiles_it = profiles_.begin(); profiles_it != profiles_.end();
206 ++profiles_it) {
Paul Stewartd0a3b812012-03-28 22:48:22 -0700207 // Since this happens in a loop, the current manager state is stored to
208 // all default profiles in the stack. This is acceptable because the
209 // only time multiple default profiles are loaded are during autotests.
Paul Stewart212d60f2012-07-12 10:59:13 -0700210 (*profiles_it)->Save();
Chris Masone9d779932011-08-25 16:33:41 -0700211 }
Chris Masone9d779932011-08-25 16:33:41 -0700212
Thieu Le1271d682011-11-02 22:48:19 +0000213 vector<ServiceRefPtr>::iterator services_it;
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000214 Error e;
Thieu Le1271d682011-11-02 22:48:19 +0000215 for (services_it = services_.begin(); services_it != services_.end();
216 ++services_it) {
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000217 (*services_it)->Disconnect(&e);
Thieu Le1271d682011-11-02 22:48:19 +0000218 }
219
Chris Masone413a3192011-05-09 17:10:05 -0700220 adaptor_->UpdateRunning();
Darin Petkovb72b62e2012-05-15 16:55:36 +0200221 wimax_provider_.Stop();
Darin Petkov33af05c2012-02-28 10:10:30 +0100222 vpn_provider_.Stop();
Darin Petkov887f2982011-07-14 16:10:17 -0700223 modem_info_.Stop();
224 device_info_.Stop();
Paul Stewartdfa46052012-06-26 09:44:14 -0700225 sort_services_task_.Cancel();
Darin Petkovca621542012-07-25 14:25:56 +0200226 power_manager_.reset();
Darin Petkov002c58e2012-06-19 02:56:05 +0200227 dbus_manager_.reset();
Paul Stewart75897df2011-04-27 09:05:53 -0700228}
229
Gaurav Shah71354762011-11-28 19:22:49 -0800230void Manager::InitializeProfiles() {
231 DCHECK(profiles_.empty());
232 // The default profile must go first on the stack.
233 CHECK(file_util::CreateDirectory(storage_path_)) << storage_path_.value();
Paul Stewart870523b2012-01-11 17:00:42 -0800234 scoped_refptr<DefaultProfile>
235 default_profile(new DefaultProfile(control_interface_,
Gaurav Shah71354762011-11-28 19:22:49 -0800236 this,
237 storage_path_,
Paul Stewartd0a3b812012-03-28 22:48:22 -0700238 DefaultProfile::kDefaultId,
Gaurav Shah71354762011-11-28 19:22:49 -0800239 props_));
Paul Stewart870523b2012-01-11 17:00:42 -0800240 CHECK(default_profile->InitStorage(glib_, Profile::kCreateOrOpenExisting,
241 NULL));
Paul Stewart4d5efb72012-09-17 12:24:34 -0700242 CHECK(LoadProperties(default_profile));
Paul Stewart870523b2012-01-11 17:00:42 -0800243 profiles_.push_back(default_profile.release());
Gaurav Shah71354762011-11-28 19:22:49 -0800244 Error error;
Paul Stewart19c871d2011-12-15 16:10:13 -0800245 string path;
Gaurav Shah71354762011-11-28 19:22:49 -0800246 for (vector<string>::iterator it = startup_profiles_.begin();
247 it != startup_profiles_.end(); ++it)
Paul Stewart19c871d2011-12-15 16:10:13 -0800248 PushProfile(*it, &path, &error);
Gaurav Shah71354762011-11-28 19:22:49 -0800249}
250
Paul Stewart19c871d2011-12-15 16:10:13 -0800251void Manager::CreateProfile(const string &name, string *path, Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700252 SLOG(Manager, 2) << __func__ << " " << name;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700253 Profile::Identifier ident;
254 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700255 Error::PopulateAndLog(error, Error::kInvalidArguments,
256 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700257 return;
258 }
Paul Stewartd0a3b812012-03-28 22:48:22 -0700259
Paul Stewartfc9a1da2012-06-27 15:54:52 -0700260 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
261 it != profiles_.end();
262 ++it) {
263 if ((*it)->MatchesIdentifier(ident)) {
264 Error::PopulateAndLog(error, Error::kAlreadyExists,
265 "Profile name " + name + " is already on stack");
266 *path = (*it)->GetRpcIdentifier();
267 return;
268 }
269 }
270
Paul Stewartd0a3b812012-03-28 22:48:22 -0700271 ProfileRefPtr profile;
272 if (ident.user.empty()) {
273 profile = new DefaultProfile(control_interface_,
274 this,
275 storage_path_,
276 ident.identifier,
277 props_);
278 } else {
279 profile = new Profile(control_interface_,
280 this,
281 ident,
282 user_storage_format_,
Gary Morainb672d352012-04-25 09:19:06 -0700283 true);
Paul Stewartd0a3b812012-03-28 22:48:22 -0700284 }
285
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700286 if (!profile->InitStorage(glib_, Profile::kCreateNew, error)) {
Paul Stewart19c871d2011-12-15 16:10:13 -0800287 // |error| will have been populated by InitStorage().
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700288 return;
289 }
290
291 // Save profile data out, and then let the scoped pointer fall out of scope.
292 if (!profile->Save()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700293 Error::PopulateAndLog(error, Error::kInternalError,
294 "Profile name " + name + " could not be saved");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700295 return;
296 }
Paul Stewart19c871d2011-12-15 16:10:13 -0800297
298 *path = profile->GetRpcIdentifier();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700299}
300
Paul Stewart19c871d2011-12-15 16:10:13 -0800301void Manager::PushProfile(const string &name, string *path, Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700302 SLOG(Manager, 2) << __func__ << " " << name;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700303 Profile::Identifier ident;
304 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700305 Error::PopulateAndLog(error, Error::kInvalidArguments,
306 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700307 return;
308 }
309
310 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
311 it != profiles_.end();
312 ++it) {
313 if ((*it)->MatchesIdentifier(ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700314 Error::PopulateAndLog(error, Error::kAlreadyExists,
315 "Profile name " + name + " is already on stack");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700316 return;
317 }
318 }
319
Paul Stewartd0a3b812012-03-28 22:48:22 -0700320 ProfileRefPtr profile;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700321 if (ident.user.empty()) {
Paul Stewartd0a3b812012-03-28 22:48:22 -0700322 // Allow a machine-wide-profile to be pushed on the stack only if the
323 // profile stack is empty, or if the topmost profile on the stack is
324 // also a machine-wide (non-user) profile.
325 if (!profiles_.empty() && !profiles_.back()->GetUser().empty()) {
326 Error::PopulateAndLog(error, Error::kInvalidArguments,
327 "Cannot load non-default global profile " + name +
328 " on top of a user profile");
329 return;
330 }
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700331
Paul Stewartd0a3b812012-03-28 22:48:22 -0700332 scoped_refptr<DefaultProfile>
333 default_profile(new DefaultProfile(control_interface_,
334 this,
335 storage_path_,
336 ident.identifier,
337 props_));
338 if (!default_profile->InitStorage(glib_, Profile::kOpenExisting, error)) {
339 // |error| will have been populated by InitStorage().
340 return;
341 }
342
Paul Stewart4d5efb72012-09-17 12:24:34 -0700343 if (!LoadProperties(default_profile)) {
Paul Stewartd0a3b812012-03-28 22:48:22 -0700344 Error::PopulateAndLog(error, Error::kInvalidArguments,
345 "Could not load Manager properties from profile " +
346 name);
347 return;
348 }
349 profile = default_profile;
350 } else {
351 profile = new Profile(control_interface_,
352 this,
353 ident,
354 user_storage_format_,
355 connect_profiles_to_rpc_);
356 if (!profile->InitStorage(glib_, Profile::kOpenExisting, error)) {
357 // |error| will have been populated by InitStorage().
358 return;
359 }
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700360 }
361
Paul Stewarta849a3d2011-11-03 05:54:09 -0700362 profiles_.push_back(profile);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700363
364 // Offer each registered Service the opportunity to join this new Profile.
Paul Stewarta41e38d2011-11-11 07:47:29 -0800365 for (vector<ServiceRefPtr>::iterator it = services_.begin();
366 it != services_.end(); ++it) {
Paul Stewartbba6a5b2011-11-02 18:45:59 -0700367 profile->ConfigureService(*it);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700368 }
369
Paul Stewarta41e38d2011-11-11 07:47:29 -0800370 // Shop the Profile contents around to Devices which can create
371 // non-visible services.
372 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
373 it != devices_.end(); ++it) {
374 profile->ConfigureDevice(*it);
375 }
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800376
Darin Petkovc63dcf02012-05-24 11:51:43 +0200377 // Offer the Profile contents to the service/device providers which will
378 // create new services if necessary.
Paul Stewart66815332012-04-09 18:09:36 -0700379 vpn_provider_.CreateServicesFromProfile(profile);
Darin Petkovc63dcf02012-05-24 11:51:43 +0200380 wimax_provider_.CreateServicesFromProfile(profile);
Paul Stewart66815332012-04-09 18:09:36 -0700381
Paul Stewart19c871d2011-12-15 16:10:13 -0800382 *path = profile->GetRpcIdentifier();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800383 SortServices();
Philipp Neubeck79173602012-11-13 21:10:09 +0100384
385 Error unused_error;
386 adaptor_->EmitStringsChanged(flimflam::kProfilesProperty,
387 EnumerateProfiles(&unused_error));
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700388}
389
390void Manager::PopProfileInternal() {
391 CHECK(!profiles_.empty());
392 ProfileRefPtr active_profile = profiles_.back();
393 profiles_.pop_back();
Paul Stewart75225512012-01-26 22:51:33 -0800394 vector<ServiceRefPtr>::iterator it;
Paul Stewart65512e12012-03-26 18:01:08 -0700395 for (it = services_.begin(); it != services_.end();) {
396 if ((*it)->profile().get() != active_profile.get() ||
397 MatchProfileWithService(*it) ||
398 !UnloadService(&it)) {
399 LOG(ERROR) << "Skipping unload of service";
400 ++it;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700401 }
402 }
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800403 SortServices();
Philipp Neubeck79173602012-11-13 21:10:09 +0100404
405 Error unused_error;
406 adaptor_->EmitStringsChanged(flimflam::kProfilesProperty,
407 EnumerateProfiles(&unused_error));
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700408}
409
Paul Stewarta41e38d2011-11-11 07:47:29 -0800410void Manager::PopProfile(const string &name, Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700411 SLOG(Manager, 2) << __func__ << " " << name;
Christopher Wiley3e7635e2012-08-15 09:46:17 -0700412 // This signal is sent when a user logs out of a session. Regardless of
413 // whether we find their profile to remove, lets clear the network related
414 // logs.
415 MemoryLog::GetInstance()->Clear();
416 LOG(INFO) << "Cleared the memory log on logout event.";
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700417 Profile::Identifier ident;
418 if (profiles_.empty()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700419 Error::PopulateAndLog(error, Error::kNotFound, "Profile stack is empty");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700420 return;
421 }
422 ProfileRefPtr active_profile = profiles_.back();
423 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700424 Error::PopulateAndLog(error, Error::kInvalidArguments,
425 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700426 return;
427 }
428 if (!active_profile->MatchesIdentifier(ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700429 Error::PopulateAndLog(error, Error::kNotSupported,
430 name + " is not the active profile");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700431 return;
432 }
433 PopProfileInternal();
434}
435
436void Manager::PopAnyProfile(Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700437 SLOG(Manager, 2) << __func__;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700438 Profile::Identifier ident;
439 if (profiles_.empty()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700440 Error::PopulateAndLog(error, Error::kNotFound, "Profile stack is empty");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700441 return;
442 }
443 PopProfileInternal();
444}
445
Paul Stewarte73d05c2012-03-29 16:26:05 -0700446void Manager::RemoveProfile(const string &name, Error *error) {
447 Profile::Identifier ident;
448 if (!Profile::ParseIdentifier(name, &ident)) {
449 Error::PopulateAndLog(error, Error::kInvalidArguments,
450 "Invalid profile name " + name);
451 return;
452 }
453
454 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
455 it != profiles_.end();
456 ++it) {
457 if ((*it)->MatchesIdentifier(ident)) {
458 Error::PopulateAndLog(error, Error::kInvalidArguments,
459 "Cannot remove profile name " + name +
460 " since it is on stack");
461 return;
462 }
463 }
464
465 ProfileRefPtr profile;
466 if (ident.user.empty()) {
467 profile = new DefaultProfile(control_interface_,
468 this,
469 storage_path_,
470 ident.identifier,
471 props_);
472 } else {
473 profile = new Profile(control_interface_,
474 this,
475 ident,
476 user_storage_format_,
477 false);
478 }
479
480
481 // |error| will have been populated if RemoveStorage fails.
482 profile->RemoveStorage(glib_, error);
483
484 return;
485}
486
Paul Stewart75225512012-01-26 22:51:33 -0800487bool Manager::HandleProfileEntryDeletion(const ProfileRefPtr &profile,
488 const std::string &entry_name) {
489 bool moved_services = false;
490 for (vector<ServiceRefPtr>::iterator it = services_.begin();
Paul Stewart65512e12012-03-26 18:01:08 -0700491 it != services_.end();) {
Paul Stewart75225512012-01-26 22:51:33 -0800492 if ((*it)->profile().get() == profile.get() &&
493 (*it)->GetStorageIdentifier() == entry_name) {
494 profile->AbandonService(*it);
Paul Stewart65512e12012-03-26 18:01:08 -0700495 if (MatchProfileWithService(*it) ||
496 !UnloadService(&it)) {
497 ++it;
Paul Stewart75225512012-01-26 22:51:33 -0800498 }
499 moved_services = true;
Paul Stewart65512e12012-03-26 18:01:08 -0700500 } else {
501 ++it;
Paul Stewart75225512012-01-26 22:51:33 -0800502 }
503 }
504 return moved_services;
505}
506
Paul Stewart0756db92012-01-27 08:34:47 -0800507ServiceRefPtr Manager::GetServiceWithStorageIdentifier(
508 const ProfileRefPtr &profile, const std::string &entry_name, Error *error) {
509 for (vector<ServiceRefPtr>::iterator it = services_.begin();
510 it != services_.end(); ++it) {
511 if ((*it)->profile().get() == profile.get() &&
512 (*it)->GetStorageIdentifier() == entry_name) {
513 return *it;
514 }
515 }
516
Paul Stewart76a89cb2012-09-14 06:06:48 -0700517 string error_string(
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500518 StringPrintf("Entry %s is not registered in the manager",
519 entry_name.c_str()));
Paul Stewart76a89cb2012-09-14 06:06:48 -0700520 if (error) {
521 error->Populate(Error::kNotFound, error_string);
522 }
523 SLOG(Manager, 2) << error_string;
Paul Stewart0756db92012-01-27 08:34:47 -0800524 return NULL;
525}
526
Paul Stewart13ed2252012-03-21 12:52:46 -0700527ServiceRefPtr Manager::GetServiceWithGUID(
528 const std::string &guid, Error *error) {
529 for (vector<ServiceRefPtr>::iterator it = services_.begin();
530 it != services_.end(); ++it) {
531 if ((*it)->guid() == guid) {
532 return *it;
533 }
534 }
535
Paul Stewart76a89cb2012-09-14 06:06:48 -0700536 string error_string(
Paul Stewart13ed2252012-03-21 12:52:46 -0700537 StringPrintf("Service wth GUID %s is not registered in the manager",
538 guid.c_str()));
Paul Stewart76a89cb2012-09-14 06:06:48 -0700539 if (error) {
540 error->Populate(Error::kNotFound, error_string);
541 }
542 SLOG(Manager, 2) << error_string;
Paul Stewart13ed2252012-03-21 12:52:46 -0700543 return NULL;
544}
545
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700546ServiceRefPtr Manager::GetDefaultService() const {
Arman Uguray32c76402012-11-27 14:01:13 -0800547 SLOG(Manager, 2) << __func__;
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700548 if (services_.empty() || !services_[0]->connection().get()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700549 SLOG(Manager, 2) << "In " << __func__ << ": No default connection exists.";
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700550 return NULL;
551 }
552 return services_[0];
553}
554
Paul Stewart49739c02012-08-08 17:24:03 -0700555RpcIdentifier Manager::GetDefaultServiceRpcIdentifier(Error */*error*/) {
556 ServiceRefPtr default_service = GetDefaultService();
557 return default_service ? default_service->GetRpcIdentifier() : "/";
558}
559
Paul Stewart036dba02012-08-07 12:34:41 -0700560bool Manager::IsTechnologyInList(const string &technology_list,
561 Technology::Identifier tech) const {
Paul Stewart20088d82012-02-16 06:58:55 -0800562 Error error;
Paul Stewart036dba02012-08-07 12:34:41 -0700563 vector<Technology::Identifier> technologies;
564 return Technology::GetTechnologyVectorFromString(technology_list,
565 &technologies,
Paul Stewart20088d82012-02-16 06:58:55 -0800566 &error) &&
Paul Stewart036dba02012-08-07 12:34:41 -0700567 std::find(technologies.begin(), technologies.end(), tech) !=
568 technologies.end();
569}
570
571bool Manager::IsPortalDetectionEnabled(Technology::Identifier tech) {
572 return IsTechnologyInList(GetCheckPortalList(NULL), tech);
Paul Stewart20088d82012-02-16 06:58:55 -0800573}
574
Paul Stewart10e9e4e2012-04-26 19:46:28 -0700575void Manager::SetStartupPortalList(const string &portal_list) {
576 startup_portal_list_ = portal_list;
577 use_startup_portal_list_ = true;
578}
579
Paul Stewart10ccbb32012-04-26 15:59:30 -0700580bool Manager::IsServiceEphemeral(const ServiceConstRefPtr &service) const {
581 return service->profile() == ephemeral_profile_;
582}
583
Paul Stewartbf667612012-06-29 14:49:54 -0700584bool Manager::IsTechnologyShortDNSTimeoutEnabled(
Paul Stewart036dba02012-08-07 12:34:41 -0700585 Technology::Identifier technology) const {
586 return IsTechnologyInList(props_.short_dns_timeout_technologies, technology);
587}
588
589bool Manager::IsTechnologyLinkMonitorEnabled(
590 Technology::Identifier technology) const {
591 return IsTechnologyInList(props_.link_monitor_technologies, technology);
Paul Stewartbf667612012-06-29 14:49:54 -0700592}
593
Paul Stewart1b253142012-01-26 14:05:52 -0800594const ProfileRefPtr &Manager::ActiveProfile() const {
Eric Shienbroodc74cf9c2012-03-02 15:00:35 -0500595 DCHECK_NE(profiles_.size(), 0U);
Chris Masone7aa5f902011-07-11 11:13:35 -0700596 return profiles_.back();
597}
598
Paul Stewart1b253142012-01-26 14:05:52 -0800599bool Manager::IsActiveProfile(const ProfileRefPtr &profile) const {
600 return (profiles_.size() > 0 &&
601 ActiveProfile().get() == profile.get());
602}
603
Chris Masone6515aab2011-10-12 16:19:09 -0700604bool Manager::MoveServiceToProfile(const ServiceRefPtr &to_move,
605 const ProfileRefPtr &destination) {
606 const ProfileRefPtr from = to_move->profile();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700607 SLOG(Manager, 2) << "Moving service "
Darin Petkov457728b2013-01-09 09:49:08 +0100608 << to_move->unique_name()
Ben Chanfad4a0b2012-04-18 15:49:59 -0700609 << " to profile "
610 << destination->GetFriendlyName()
611 << " from "
612 << from->GetFriendlyName();
Darin Petkov457728b2013-01-09 09:49:08 +0100613 return destination->AdoptService(to_move) && from->AbandonService(to_move);
Chris Masone6791a432011-07-12 13:23:19 -0700614}
615
Paul Stewart7f61e522012-03-22 11:13:45 -0700616ProfileRefPtr Manager::LookupProfileByRpcIdentifier(
617 const string &profile_rpcid) {
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800618 for (vector<ProfileRefPtr>::iterator it = profiles_.begin();
619 it != profiles_.end();
620 ++it) {
621 if (profile_rpcid == (*it)->GetRpcIdentifier()) {
Paul Stewart7f61e522012-03-22 11:13:45 -0700622 return *it;
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800623 }
624 }
Paul Stewart7f61e522012-03-22 11:13:45 -0700625 return NULL;
626}
627
628void Manager::SetProfileForService(const ServiceRefPtr &to_set,
629 const string &profile_rpcid,
630 Error *error) {
631 ProfileRefPtr profile = LookupProfileByRpcIdentifier(profile_rpcid);
632 if (!profile) {
633 Error::PopulateAndLog(error, Error::kInvalidArguments,
634 StringPrintf("Unknown Profile %s requested for "
635 "Service", profile_rpcid.c_str()));
636 return;
637 }
638
Paul Stewart649f3a42012-04-24 23:22:16 -0700639 if (!to_set->profile()) {
640 // We are being asked to set the profile property of a service that
641 // has never been registered. Now is a good time to register it.
642 RegisterService(to_set);
643 }
644
Paul Stewart7f61e522012-03-22 11:13:45 -0700645 if (to_set->profile().get() == profile.get()) {
646 Error::PopulateAndLog(error, Error::kInvalidArguments,
647 "Service is already connected to this profile");
648 } else if (!MoveServiceToProfile(to_set, profile)) {
649 Error::PopulateAndLog(error, Error::kInternalError,
650 "Unable to move service to profile");
651 }
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800652}
653
Eric Shienbrood9a245532012-03-07 14:20:39 -0500654void Manager::EnableTechnology(const std::string &technology_name,
655 Error *error,
656 const ResultCallback &callback) {
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400657 CHECK(error != NULL);
658 DCHECK(error->IsOngoing());
Eric Shienbrood9a245532012-03-07 14:20:39 -0500659 Technology::Identifier id = Technology::IdentifierFromName(technology_name);
660 if (id == Technology::kUnknown) {
661 error->Populate(Error::kInvalidArguments, "Unknown technology");
662 return;
663 }
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400664 bool deferred = false;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500665 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
666 it != devices_.end(); ++it) {
667 DeviceRefPtr device = *it;
Joshua Krollda798622012-06-05 12:30:48 -0700668 if (device->technology() == id && !device->enabled()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500669 device->SetEnabledPersistent(true, error, callback);
670 // Continue with other devices even if one fails
671 // TODO(ers): Decide whether an error should be returned
672 // for the overall EnableTechnology operation if some
673 // devices succeed and some fail.
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400674 if (error->IsOngoing())
675 deferred = true;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500676 }
677 }
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400678 // If no device has deferred work, then clear the error to
679 // communicate to the caller that all work is done.
680 if (!deferred)
681 error->Reset();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500682}
683
684void Manager::DisableTechnology(const std::string &technology_name,
685 Error *error,
686 const ResultCallback &callback) {
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400687 CHECK(error != NULL);
688 DCHECK(error->IsOngoing());
Eric Shienbrood9a245532012-03-07 14:20:39 -0500689 Technology::Identifier id = Technology::IdentifierFromName(technology_name);
690 if (id == Technology::kUnknown) {
691 error->Populate(Error::kInvalidArguments, "Unknown technology");
692 return;
693 }
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400694 bool deferred = false;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500695 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
696 it != devices_.end(); ++it) {
697 DeviceRefPtr device = *it;
Joshua Krollda798622012-06-05 12:30:48 -0700698 if (device->technology() == id && device->enabled()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500699 device->SetEnabledPersistent(false, error, callback);
700 // Continue with other devices even if one fails
701 // TODO(ers): Decide whether an error should be returned
702 // for the overall DisableTechnology operation if some
703 // devices succeed and some fail.
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400704 if (error->IsOngoing())
705 deferred = true;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500706 }
707 }
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400708 // If no device has deferred work, then clear the error to
709 // communicate to the caller that all work is done.
710 if (!deferred)
711 error->Reset();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500712}
713
714void Manager::UpdateEnabledTechnologies() {
715 Error error;
716 adaptor_->EmitStringsChanged(flimflam::kEnabledTechnologiesProperty,
717 EnabledTechnologies(&error));
718}
719
Chris Masone2b105542011-06-22 10:58:09 -0700720void Manager::RegisterDevice(const DeviceRefPtr &to_manage) {
Darin Petkove7c6ad32012-06-29 10:22:09 +0200721 LOG(INFO) << "Device " << to_manage->FriendlyName() << " registered.";
722 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
723 it != devices_.end(); ++it) {
Chris Masonec1e50412011-06-07 13:04:53 -0700724 if (to_manage.get() == it->get())
Chris Masone9be4a9d2011-05-16 15:44:09 -0700725 return;
726 }
Chris Masonec1e50412011-06-07 13:04:53 -0700727 devices_.push_back(to_manage);
Paul Stewartf1ce5d22011-05-19 13:10:20 -0700728
Paul Stewart87a4ae82012-10-26 15:49:32 -0700729 LoadDeviceFromProfiles(to_manage);
Paul Stewarta41e38d2011-11-11 07:47:29 -0800730
Darin Petkove7c6ad32012-06-29 10:22:09 +0200731 // If |to_manage| is new, it needs to be persisted.
732 UpdateDevice(to_manage);
733
Paul Stewarta41e38d2011-11-11 07:47:29 -0800734 // In normal usage, running_ will always be true when we are here, however
735 // unit tests sometimes do things in otherwise invalid states.
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400736 if (running_ && (to_manage->enabled_persistent() ||
737 to_manage->IsUnderlyingDeviceEnabled()))
Eric Shienbrood9a245532012-03-07 14:20:39 -0500738 to_manage->SetEnabled(true);
Gaurav Shah435de2c2011-11-17 19:01:07 -0800739
Eric Shienbrood8839a892012-03-29 10:33:48 -0400740 EmitDeviceProperties();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700741}
742
mukesh agrawal5029c6c2011-08-25 11:12:40 -0700743void Manager::DeregisterDevice(const DeviceRefPtr &to_forget) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700744 SLOG(Manager, 2) << __func__ << "(" << to_forget->FriendlyName() << ")";
Chris Masonec1e50412011-06-07 13:04:53 -0700745 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700746 for (it = devices_.begin(); it != devices_.end(); ++it) {
Chris Masonec1e50412011-06-07 13:04:53 -0700747 if (to_forget.get() == it->get()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700748 SLOG(Manager, 2) << "Deregistered device: " << to_forget->UniqueName();
Paul Stewart212d60f2012-07-12 10:59:13 -0700749 UpdateDevice(to_forget);
Eric Shienbrood9a245532012-03-07 14:20:39 -0500750 to_forget->SetEnabled(false);
Chris Masone9be4a9d2011-05-16 15:44:09 -0700751 devices_.erase(it);
Eric Shienbrood8839a892012-03-29 10:33:48 -0400752 EmitDeviceProperties();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700753 return;
754 }
755 }
Ben Chanfad4a0b2012-04-18 15:49:59 -0700756 SLOG(Manager, 2) << __func__ << " unknown device: "
757 << to_forget->UniqueName();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700758}
759
Paul Stewart87a4ae82012-10-26 15:49:32 -0700760void Manager::LoadDeviceFromProfiles(const DeviceRefPtr &device) {
761 // We are applying device properties from the DefaultProfile, and adding the
762 // union of hidden services in all loaded profiles to the device.
763 for (vector<ProfileRefPtr>::iterator it = profiles_.begin();
764 it != profiles_.end(); ++it) {
765 // Load device configuration, if any exists, as well as hidden services.
766 (*it)->ConfigureDevice(device);
767 }
768}
769
Eric Shienbrood8839a892012-03-29 10:33:48 -0400770void Manager::EmitDeviceProperties() {
771 vector<DeviceRefPtr>::iterator it;
772 vector<string> device_paths;
773 for (it = devices_.begin(); it != devices_.end(); ++it) {
774 device_paths.push_back((*it)->GetRpcIdentifier());
775 }
776 adaptor_->EmitRpcIdentifierArrayChanged(flimflam::kDevicesProperty,
777 device_paths);
778 Error error;
779 adaptor_->EmitStringsChanged(flimflam::kAvailableTechnologiesProperty,
780 AvailableTechnologies(&error));
781 adaptor_->EmitStringsChanged(flimflam::kEnabledTechnologiesProperty,
782 EnabledTechnologies(&error));
783}
784
mukesh agrawal4eb4d782011-12-05 17:34:37 +0000785bool Manager::HasService(const ServiceRefPtr &service) {
786 vector<ServiceRefPtr>::iterator it;
787 for (it = services_.begin(); it != services_.end(); ++it) {
Darin Petkov457728b2013-01-09 09:49:08 +0100788 if ((*it)->unique_name() == service->unique_name())
mukesh agrawal4eb4d782011-12-05 17:34:37 +0000789 return true;
790 }
791 return false;
792}
793
Chris Masone2b105542011-06-22 10:58:09 -0700794void Manager::RegisterService(const ServiceRefPtr &to_manage) {
Darin Petkov457728b2013-01-09 09:49:08 +0100795 SLOG(Manager, 2) << "Registering service " << to_manage->unique_name();
mukesh agrawald835b202011-10-07 15:26:47 -0700796
Paul Stewart75225512012-01-26 22:51:33 -0800797 MatchProfileWithService(to_manage);
Chris Masone6791a432011-07-12 13:23:19 -0700798
799 // Now add to OUR list.
Chris Masonec1e50412011-06-07 13:04:53 -0700800 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700801 for (it = services_.begin(); it != services_.end(); ++it) {
Darin Petkov457728b2013-01-09 09:49:08 +0100802 CHECK(to_manage->unique_name() != (*it)->unique_name());
Chris Masone9be4a9d2011-05-16 15:44:09 -0700803 }
Chris Masonec1e50412011-06-07 13:04:53 -0700804 services_.push_back(to_manage);
Paul Stewart22aa71b2011-09-16 12:15:11 -0700805 SortServices();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700806}
807
Chris Masone6515aab2011-10-12 16:19:09 -0700808void Manager::DeregisterService(const ServiceRefPtr &to_forget) {
Chris Masonec1e50412011-06-07 13:04:53 -0700809 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700810 for (it = services_.begin(); it != services_.end(); ++it) {
Darin Petkov457728b2013-01-09 09:49:08 +0100811 if (to_forget->unique_name() == (*it)->unique_name()) {
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800812 DCHECK(!(*it)->connection());
Paul Stewartfc9a1da2012-06-27 15:54:52 -0700813 (*it)->Unload();
Philipp Neubeck79173602012-11-13 21:10:09 +0100814 (*it)->SetProfile(NULL);
Chris Masone9be4a9d2011-05-16 15:44:09 -0700815 services_.erase(it);
Paul Stewart22aa71b2011-09-16 12:15:11 -0700816 SortServices();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700817 return;
818 }
819 }
820}
821
Paul Stewart65512e12012-03-26 18:01:08 -0700822bool Manager::UnloadService(vector<ServiceRefPtr>::iterator *service_iterator) {
823 if (!(**service_iterator)->Unload()) {
824 return false;
825 }
826
827 DCHECK(!(**service_iterator)->connection());
Philipp Neubeck79173602012-11-13 21:10:09 +0100828 (**service_iterator)->SetProfile(NULL);
Paul Stewart65512e12012-03-26 18:01:08 -0700829 *service_iterator = services_.erase(*service_iterator);
830
831 return true;
832}
833
mukesh agrawal00917ce2011-11-22 23:56:55 +0000834void Manager::UpdateService(const ServiceRefPtr &to_update) {
835 CHECK(to_update);
Darin Petkov457728b2013-01-09 09:49:08 +0100836 LOG(INFO) << "Service " << to_update->unique_name() << " updated;"
Gaurav Shahc6d6c722011-11-17 18:59:39 -0800837 << " state: " << Service::ConnectStateToString(to_update->state())
838 << " failure: "
839 << Service::ConnectFailureToString(to_update->failure());
Ben Chanfad4a0b2012-04-18 15:49:59 -0700840 SLOG(Manager, 2) << "IsConnected(): " << to_update->IsConnected();
841 SLOG(Manager, 2) << "IsConnecting(): " << to_update->IsConnecting();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800842 if (to_update->IsConnected()) {
mukesh agrawal00917ce2011-11-22 23:56:55 +0000843 to_update->MakeFavorite();
Gary Moraind93615e2012-04-27 11:50:03 -0700844 // Persists the updated favorite setting in the profile.
845 SaveServiceToProfile(to_update);
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800846 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700847 SortServices();
Paul Stewart03dba0b2011-08-22 16:32:45 -0700848}
849
Darin Petkove7c6ad32012-06-29 10:22:09 +0200850void Manager::UpdateDevice(const DeviceRefPtr &to_update) {
851 LOG(INFO) << "Device " << to_update->link_name() << " updated: "
852 << (to_update->enabled_persistent() ? "enabled" : "disabled");
853 // Saves the device to the topmost profile that accepts it. Normally, this
854 // would be the only DefaultProfile at the bottom of the stack except in
855 // autotests that push a second test-only DefaultProfile.
856 for (vector<ProfileRefPtr>::reverse_iterator rit = profiles_.rbegin();
857 rit != profiles_.rend(); ++rit) {
858 if ((*rit)->UpdateDevice(to_update)) {
859 return;
860 }
861 }
862}
863
Gary Moraind93615e2012-04-27 11:50:03 -0700864void Manager::SaveServiceToProfile(const ServiceRefPtr &to_update) {
865 if (IsServiceEphemeral(to_update)) {
866 if (profiles_.empty()) {
867 LOG(ERROR) << "Cannot assign profile to service: no profiles exist!";
868 } else {
869 MoveServiceToProfile(to_update, profiles_.back());
870 }
871 } else {
872 to_update->profile()->UpdateService(to_update);
873 }
874}
875
Paul Stewart4d5efb72012-09-17 12:24:34 -0700876bool Manager::LoadProperties(const scoped_refptr<DefaultProfile> &profile) {
877 if (!profile->LoadManagerProperties(&props_)) {
878 return false;
879 }
880 SetIgnoredDNSSearchPaths(props_.ignored_dns_search_paths, NULL);
881 return true;
882}
883
Darin Petkov3ec55342012-09-28 14:04:44 +0200884void Manager::AddTerminationAction(const string &name,
Gary Moraina9fb3252012-05-31 12:05:31 -0700885 const base::Closure &start) {
Darin Petkov3ec55342012-09-28 14:04:44 +0200886 if (termination_actions_.IsEmpty() && power_manager_.get()) {
887 power_manager_->AddSuspendDelayCallback(
888 kPowerManagerKey,
Daniel Erat0818cca2012-12-14 10:16:21 -0800889 Bind(&Manager::OnSuspendImminent, AsWeakPtr()));
890 CHECK(!suspend_delay_registered_);
891 suspend_delay_registered_ = power_manager_->RegisterSuspendDelay(
892 base::TimeDelta::FromMilliseconds(
893 kTerminationActionsTimeoutMilliseconds),
894 &suspend_delay_id_);
Darin Petkov3ec55342012-09-28 14:04:44 +0200895 }
Gary Moraina9fb3252012-05-31 12:05:31 -0700896 termination_actions_.Add(name, start);
897}
898
Darin Petkov3ec55342012-09-28 14:04:44 +0200899void Manager::TerminationActionComplete(const string &name) {
Gary Moraina9fb3252012-05-31 12:05:31 -0700900 termination_actions_.ActionComplete(name);
901}
902
Darin Petkov3ec55342012-09-28 14:04:44 +0200903void Manager::RemoveTerminationAction(const string &name) {
904 if (termination_actions_.IsEmpty()) {
905 return;
906 }
Gary Moraina9fb3252012-05-31 12:05:31 -0700907 termination_actions_.Remove(name);
Darin Petkov3ec55342012-09-28 14:04:44 +0200908 if (termination_actions_.IsEmpty() && power_manager_.get()) {
Daniel Erat0818cca2012-12-14 10:16:21 -0800909 if (suspend_delay_registered_) {
910 power_manager_->UnregisterSuspendDelay(suspend_delay_id_);
911 suspend_delay_registered_ = false;
912 suspend_delay_id_ = 0;
913 }
Darin Petkov3ec55342012-09-28 14:04:44 +0200914 power_manager_->RemoveSuspendDelayCallback(kPowerManagerKey);
915 }
Gary Moraina9fb3252012-05-31 12:05:31 -0700916}
917
918void Manager::RunTerminationActions(
Darin Petkov3ec55342012-09-28 14:04:44 +0200919 const base::Callback<void(const Error &)> &done) {
920 LOG(INFO) << "Running termination actions.";
921 termination_actions_.Run(kTerminationActionsTimeoutMilliseconds, done);
Gary Moraina9fb3252012-05-31 12:05:31 -0700922}
923
Arman Ugurayab22c162012-10-08 19:08:38 -0700924bool Manager::RunTerminationActionsAndNotifyMetrics(
925 const base::Callback<void(const Error &)> &done,
926 Metrics::TerminationActionReason reason) {
927 if (termination_actions_.IsEmpty())
928 return false;
929
930 metrics_->NotifyTerminationActionsStarted(reason);
931 RunTerminationActions(done);
932 return true;
933}
934
Darin Petkova5e07ef2012-07-09 14:27:57 +0200935int Manager::RegisterDefaultServiceCallback(const ServiceCallback &callback) {
936 default_service_callbacks_[++default_service_callback_tag_] = callback;
937 return default_service_callback_tag_;
938}
939
940void Manager::DeregisterDefaultServiceCallback(int tag) {
941 default_service_callbacks_.erase(tag);
942}
943
944void Manager::NotifyDefaultServiceChanged(const ServiceRefPtr &service) {
945 for (map<int, ServiceCallback>::const_iterator it =
946 default_service_callbacks_.begin();
947 it != default_service_callbacks_.end(); ++it) {
948 it->second.Run(service);
949 }
950 metrics_->NotifyDefaultServiceChanged(service);
Paul Stewart49739c02012-08-08 17:24:03 -0700951 EmitDefaultService();
952}
953
954void Manager::EmitDefaultService() {
955 RpcIdentifier rpc_identifier = GetDefaultServiceRpcIdentifier(NULL);
956 if (rpc_identifier != default_service_rpc_identifier_) {
957 adaptor_->EmitRpcIdentifierChanged(shill::kDefaultServiceProperty,
958 rpc_identifier);
959 default_service_rpc_identifier_ = rpc_identifier;
960 }
Darin Petkova5e07ef2012-07-09 14:27:57 +0200961}
962
Darin Petkovca621542012-07-25 14:25:56 +0200963void Manager::OnPowerStateChanged(
964 PowerManagerProxyDelegate::SuspendState power_state) {
965 if (power_state == PowerManagerProxyDelegate::kOn) {
Christopher Wiley0801d192012-09-24 11:57:15 -0700966 vector<ServiceRefPtr>::iterator sit;
967 for (sit = services_.begin(); sit != services_.end(); ++sit) {
968 (*sit)->OnAfterResume();
969 }
Darin Petkovca621542012-07-25 14:25:56 +0200970 SortServices();
mukesh agrawal784566d2012-08-08 18:32:58 -0700971 vector<DeviceRefPtr>::iterator it;
972 for (it = devices_.begin(); it != devices_.end(); ++it) {
973 (*it)->OnAfterResume();
974 }
975 } else if (power_state == PowerManagerProxyDelegate::kMem) {
976 vector<DeviceRefPtr>::iterator it;
977 for (it = devices_.begin(); it != devices_.end(); ++it) {
978 (*it)->OnBeforeSuspend();
979 }
Darin Petkovca621542012-07-25 14:25:56 +0200980 }
981}
982
Daniel Erat0818cca2012-12-14 10:16:21 -0800983void Manager::OnSuspendImminent(int suspend_id) {
Arman Ugurayab22c162012-10-08 19:08:38 -0700984 if (!RunTerminationActionsAndNotifyMetrics(
Daniel Erat0818cca2012-12-14 10:16:21 -0800985 Bind(&Manager::OnSuspendActionsComplete, AsWeakPtr(), suspend_id),
Arman Ugurayab22c162012-10-08 19:08:38 -0700986 Metrics::kTerminationActionReasonSuspend)) {
987 LOG(INFO) << "No suspend actions were run.";
Daniel Erat0818cca2012-12-14 10:16:21 -0800988 power_manager_->ReportSuspendReadiness(suspend_delay_id_, suspend_id);
Arman Ugurayab22c162012-10-08 19:08:38 -0700989 }
Darin Petkov3ec55342012-09-28 14:04:44 +0200990}
991
Daniel Erat0818cca2012-12-14 10:16:21 -0800992void Manager::OnSuspendActionsComplete(int suspend_id, const Error &error) {
Darin Petkov3ec55342012-09-28 14:04:44 +0200993 LOG(INFO) << "Finished suspend actions. Result: " << error;
Arman Ugurayab22c162012-10-08 19:08:38 -0700994 metrics_->NotifyTerminationActionsCompleted(
995 Metrics::kTerminationActionReasonSuspend, error.IsSuccess());
Daniel Erat0818cca2012-12-14 10:16:21 -0800996 power_manager_->ReportSuspendReadiness(suspend_delay_id_, suspend_id);
Darin Petkov3ec55342012-09-28 14:04:44 +0200997}
998
Paul Stewartfdd16072011-09-16 12:41:35 -0700999void Manager::FilterByTechnology(Technology::Identifier tech,
Chris Masonec1e50412011-06-07 13:04:53 -07001000 vector<DeviceRefPtr> *found) {
Chris Masone9be4a9d2011-05-16 15:44:09 -07001001 CHECK(found);
Chris Masonec1e50412011-06-07 13:04:53 -07001002 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -07001003 for (it = devices_.begin(); it != devices_.end(); ++it) {
Joshua Krollda798622012-06-05 12:30:48 -07001004 if ((*it)->technology() == tech)
Chris Masone9be4a9d2011-05-16 15:44:09 -07001005 found->push_back(*it);
1006 }
1007}
1008
Darin Petkov457728b2013-01-09 09:49:08 +01001009ServiceRefPtr Manager::FindService(const string &name) {
Chris Masonec1e50412011-06-07 13:04:53 -07001010 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -07001011 for (it = services_.begin(); it != services_.end(); ++it) {
Darin Petkov457728b2013-01-09 09:49:08 +01001012 if (name == (*it)->unique_name())
Chris Masonee0dea762011-06-09 09:06:03 -07001013 return *it;
Chris Masone9be4a9d2011-05-16 15:44:09 -07001014 }
Chris Masonee0dea762011-06-09 09:06:03 -07001015 return NULL;
Chris Masone9be4a9d2011-05-16 15:44:09 -07001016}
1017
Paul Stewart49739c02012-08-08 17:24:03 -07001018void Manager::HelpRegisterConstDerivedRpcIdentifier(
1019 const string &name,
1020 RpcIdentifier(Manager::*get)(Error *error)) {
1021 store_.RegisterDerivedRpcIdentifier(
1022 name,
1023 RpcIdentifierAccessor(
1024 new CustomAccessor<Manager, RpcIdentifier>(this, get, NULL)));
1025}
1026
mukesh agrawal2366eed2012-03-20 18:21:50 -07001027void Manager::HelpRegisterConstDerivedRpcIdentifiers(
1028 const string &name,
Jason Glasgowdf7c5532012-05-14 14:41:45 -04001029 RpcIdentifiers(Manager::*get)(Error *error)) {
mukesh agrawal2366eed2012-03-20 18:21:50 -07001030 store_.RegisterDerivedRpcIdentifiers(
1031 name,
1032 RpcIdentifiersAccessor(
1033 new CustomAccessor<Manager, RpcIdentifiers>(this, get, NULL)));
1034}
1035
mukesh agrawalffa3d042011-10-06 15:26:10 -07001036void Manager::HelpRegisterDerivedString(
1037 const string &name,
Gaurav Shah1b7a6162011-11-09 11:41:01 -08001038 string(Manager::*get)(Error *),
mukesh agrawalffa3d042011-10-06 15:26:10 -07001039 void(Manager::*set)(const string&, Error *)) {
Chris Masone27c4aa52011-07-02 13:10:14 -07001040 store_.RegisterDerivedString(
1041 name,
1042 StringAccessor(new CustomAccessor<Manager, string>(this, get, set)));
Chris Masoneb925cc82011-06-22 15:39:57 -07001043}
1044
mukesh agrawalffa3d042011-10-06 15:26:10 -07001045void Manager::HelpRegisterDerivedStrings(
1046 const string &name,
Gaurav Shah1b7a6162011-11-09 11:41:01 -08001047 Strings(Manager::*get)(Error *),
mukesh agrawalffa3d042011-10-06 15:26:10 -07001048 void(Manager::*set)(const Strings &, Error *)) {
Chris Masone27c4aa52011-07-02 13:10:14 -07001049 store_.RegisterDerivedStrings(
1050 name,
1051 StringsAccessor(new CustomAccessor<Manager, Strings>(this, get, set)));
Chris Masoneb925cc82011-06-22 15:39:57 -07001052}
1053
Paul Stewart22aa71b2011-09-16 12:15:11 -07001054void Manager::SortServices() {
Paul Stewartdfa46052012-06-26 09:44:14 -07001055 // We might be called in the middle of a series of events that
1056 // may result in multiple calls to Manager::SortServices, or within
1057 // an outer loop that may also be traversing the services_ list.
1058 // Defer this work to the event loop.
1059 if (sort_services_task_.IsCancelled()) {
1060 sort_services_task_.Reset(Bind(&Manager::SortServicesTask, AsWeakPtr()));
1061 dispatcher_->PostTask(sort_services_task_.callback());
1062 }
1063}
1064
1065void Manager::SortServicesTask() {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001066 SLOG(Manager, 4) << "In " << __func__;
Paul Stewartdfa46052012-06-26 09:44:14 -07001067 sort_services_task_.Cancel();
Thieu Lea20cbc22012-01-09 22:01:43 +00001068 ServiceRefPtr default_service;
1069
Paul Stewartc1dec4d2011-12-08 15:25:28 -08001070 if (!services_.empty()) {
Paul Stewarte2bad7c2012-03-14 08:55:33 -07001071 // Keep track of the service that is the candidate for the default
1072 // service. We have not yet tested to see if this service has a
1073 // connection.
Thieu Lea20cbc22012-01-09 22:01:43 +00001074 default_service = services_[0];
Paul Stewartc1dec4d2011-12-08 15:25:28 -08001075 }
Paul Stewart22aa71b2011-09-16 12:15:11 -07001076 sort(services_.begin(), services_.end(), ServiceSorter(technology_order_));
Paul Stewarta41e38d2011-11-11 07:47:29 -08001077
Paul Stewarta41e38d2011-11-11 07:47:29 -08001078 adaptor_->EmitRpcIdentifierArrayChanged(flimflam::kServicesProperty,
Paul Stewartbfb82552012-10-24 16:48:48 -07001079 EnumerateAvailableServices(NULL));
1080 adaptor_->EmitRpcIdentifierArrayChanged(flimflam::kServiceWatchListProperty,
1081 EnumerateWatchedServices(NULL));
Gaurav Shah435de2c2011-11-17 19:01:07 -08001082
1083 Error error;
1084 adaptor_->EmitStringsChanged(flimflam::kConnectedTechnologiesProperty,
1085 ConnectedTechnologies(&error));
1086 adaptor_->EmitStringChanged(flimflam::kDefaultTechnologyProperty,
1087 DefaultTechnology(&error));
Paul Stewartc1dec4d2011-12-08 15:25:28 -08001088
1089 if (!services_.empty()) {
Thieu Lea20cbc22012-01-09 22:01:43 +00001090 ConnectionRefPtr default_connection = default_service->connection();
Darin Petkova5e07ef2012-07-09 14:27:57 +02001091 if (default_connection &&
1092 services_[0]->connection() != default_connection) {
Paul Stewartc1dec4d2011-12-08 15:25:28 -08001093 default_connection->SetIsDefault(false);
1094 }
Darin Petkova5e07ef2012-07-09 14:27:57 +02001095 if (services_[0]->connection()) {
Paul Stewartc1dec4d2011-12-08 15:25:28 -08001096 services_[0]->connection()->SetIsDefault(true);
Thieu Lea20cbc22012-01-09 22:01:43 +00001097 default_service = services_[0];
Paul Stewarte2bad7c2012-03-14 08:55:33 -07001098 } else {
1099 default_service = NULL;
Paul Stewartc1dec4d2011-12-08 15:25:28 -08001100 }
1101 }
Darin Petkova5e07ef2012-07-09 14:27:57 +02001102 NotifyDefaultServiceChanged(default_service);
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001103 AutoConnect();
1104}
1105
Paul Stewart75225512012-01-26 22:51:33 -08001106bool Manager::MatchProfileWithService(const ServiceRefPtr &service) {
1107 vector<ProfileRefPtr>::reverse_iterator it;
1108 for (it = profiles_.rbegin(); it != profiles_.rend(); ++it) {
1109 if ((*it)->ConfigureService(service)) {
1110 break;
1111 }
1112 }
1113 if (it == profiles_.rend()) {
1114 ephemeral_profile_->AdoptService(service);
1115 return false;
1116 }
1117 return true;
1118}
1119
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001120void Manager::AutoConnect() {
Paul Stewart63864b62012-11-07 15:10:55 -08001121 if (!running_) {
1122 LOG(INFO) << "Auto-connect suppressed -- not running.";
1123 return;
1124 }
Darin Petkovca621542012-07-25 14:25:56 +02001125 if (power_manager_.get() &&
1126 power_manager_->power_state() != PowerManagerProxyDelegate::kOn &&
1127 power_manager_->power_state() != PowerManagerProxyDelegate::kUnknown) {
1128 LOG(INFO) << "Auto-connect suppressed -- power state is not 'on'.";
1129 return;
1130 }
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001131 if (services_.empty()) {
Darin Petkovca621542012-07-25 14:25:56 +02001132 LOG(INFO) << "Auto-connect suppressed -- no services.";
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001133 return;
1134 }
1135
Ben Chanfad4a0b2012-04-18 15:49:59 -07001136 if (SLOG_IS_ON(Manager, 4)) {
1137 SLOG(Manager, 4) << "Sorted service list: ";
mukesh agrawalddc378f2012-02-17 18:26:20 -08001138 for (size_t i = 0; i < services_.size(); ++i) {
1139 ServiceRefPtr service = services_[i];
1140 const char *compare_reason = NULL;
1141 if (i + 1 < services_.size()) {
1142 Service::Compare(
1143 service, services_[i+1], technology_order_, &compare_reason);
1144 } else {
mukesh agrawalbf14e942012-03-02 14:36:34 -08001145 compare_reason = "last";
mukesh agrawalddc378f2012-02-17 18:26:20 -08001146 }
Darin Petkov457728b2013-01-09 09:49:08 +01001147 SLOG(Manager, 4) << "Service " << service->unique_name()
Ben Chanfad4a0b2012-04-18 15:49:59 -07001148 << " IsConnected: " << service->IsConnected()
1149 << " IsConnecting: " << service->IsConnecting()
1150 << " IsFailed: " << service->IsFailed()
1151 << " connectable: " << service->connectable()
1152 << " auto_connect: " << service->auto_connect()
1153 << " favorite: " << service->favorite()
1154 << " priority: " << service->priority()
1155 << " security_level: " << service->security_level()
1156 << " strength: " << service->strength()
Ben Chanfad4a0b2012-04-18 15:49:59 -07001157 << " sorted: " << compare_reason;
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001158 }
1159 }
1160
Paul Stewart3d9bcf52011-12-12 15:02:22 -08001161 // Perform auto-connect.
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001162 for (vector<ServiceRefPtr>::iterator it = services_.begin();
1163 it != services_.end(); ++it) {
1164 if ((*it)->auto_connect()) {
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001165 (*it)->AutoConnect();
Paul Stewart3d9bcf52011-12-12 15:02:22 -08001166 }
1167 }
Paul Stewart22aa71b2011-09-16 12:15:11 -07001168}
1169
Gaurav Shah1b7a6162011-11-09 11:41:01 -08001170string Manager::CalculateState(Error */*error*/) {
Gary Morain028545d2012-04-07 14:55:52 -07001171 // |services_| is sorted such that connected services are first.
1172 if (!services_.empty() &&
1173 services_.front()->IsConnected()) {
1174 return flimflam::kStateOnline;
1175 }
Chris Masoneb925cc82011-06-22 15:39:57 -07001176 return flimflam::kStateOffline;
1177}
1178
Gaurav Shah1b7a6162011-11-09 11:41:01 -08001179vector<string> Manager::AvailableTechnologies(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -08001180 set<string> unique_technologies;
1181 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1182 it != devices_.end(); ++it) {
1183 unique_technologies.insert(
1184 Technology::NameFromIdentifier((*it)->technology()));
1185 }
1186 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -07001187}
1188
Gaurav Shah1b7a6162011-11-09 11:41:01 -08001189vector<string> Manager::ConnectedTechnologies(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -08001190 set<string> unique_technologies;
1191 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1192 it != devices_.end(); ++it) {
1193 if ((*it)->IsConnected())
1194 unique_technologies.insert(
1195 Technology::NameFromIdentifier((*it)->technology()));
1196 }
1197 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -07001198}
1199
Darin Petkov58f0b6d2012-06-12 12:52:30 +02001200string Manager::DefaultTechnology(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -08001201 return (!services_.empty() && services_[0]->IsConnected()) ?
Darin Petkov58f0b6d2012-06-12 12:52:30 +02001202 services_[0]->GetTechnologyString() : "";
Chris Masoneb925cc82011-06-22 15:39:57 -07001203}
1204
Eric Shienbrood9a245532012-03-07 14:20:39 -05001205vector<string> Manager::EnabledTechnologies(Error */*error*/) {
1206 set<string> unique_technologies;
1207 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1208 it != devices_.end(); ++it) {
1209 if ((*it)->enabled())
1210 unique_technologies.insert(
1211 Technology::NameFromIdentifier((*it)->technology()));
1212 }
1213 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -07001214}
1215
Paul Stewartcb3eb892012-06-07 14:24:46 -07001216RpcIdentifiers Manager::EnumerateDevices(Error */*error*/) {
1217 RpcIdentifiers device_rpc_ids;
Chris Masone3c3f6a12011-07-01 10:01:41 -07001218 for (vector<DeviceRefPtr>::const_iterator it = devices_.begin();
1219 it != devices_.end();
1220 ++it) {
1221 device_rpc_ids.push_back((*it)->GetRpcIdentifier());
1222 }
1223 return device_rpc_ids;
1224}
1225
Paul Stewartcb3eb892012-06-07 14:24:46 -07001226RpcIdentifiers Manager::EnumerateProfiles(Error */*error*/) {
1227 RpcIdentifiers profile_rpc_ids;
Paul Stewart1b253142012-01-26 14:05:52 -08001228 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
1229 it != profiles_.end();
1230 ++it) {
1231 profile_rpc_ids.push_back((*it)->GetRpcIdentifier());
1232 }
1233 return profile_rpc_ids;
1234}
1235
Gaurav Shah1b7a6162011-11-09 11:41:01 -08001236vector<string> Manager::EnumerateAvailableServices(Error */*error*/) {
Chris Masone3c3f6a12011-07-01 10:01:41 -07001237 vector<string> service_rpc_ids;
1238 for (vector<ServiceRefPtr>::const_iterator it = services_.begin();
1239 it != services_.end();
1240 ++it) {
Paul Stewartbfb82552012-10-24 16:48:48 -07001241 if ((*it)->IsVisible()) {
1242 service_rpc_ids.push_back((*it)->GetRpcIdentifier());
1243 }
Chris Masone3c3f6a12011-07-01 10:01:41 -07001244 }
1245 return service_rpc_ids;
1246}
1247
Paul Stewartbfb82552012-10-24 16:48:48 -07001248RpcIdentifiers Manager::EnumerateWatchedServices(Error */*error*/) {
1249 vector<string> service_rpc_ids;
1250 for (vector<ServiceRefPtr>::const_iterator it = services_.begin();
1251 it != services_.end();
1252 ++it) {
1253 if ((*it)->IsVisible() && (*it)->IsActive(NULL)) {
1254 service_rpc_ids.push_back((*it)->GetRpcIdentifier());
1255 }
1256 }
1257 return service_rpc_ids;
Chris Masone3c3f6a12011-07-01 10:01:41 -07001258}
1259
Paul Stewart1b253142012-01-26 14:05:52 -08001260string Manager::GetActiveProfileRpcIdentifier(Error */*error*/) {
1261 return ActiveProfile()->GetRpcIdentifier();
Chris Masone7aa5f902011-07-11 11:13:35 -07001262}
1263
Paul Stewart10e9e4e2012-04-26 19:46:28 -07001264string Manager::GetCheckPortalList(Error */*error*/) {
Jason Glasgowdf7c5532012-05-14 14:41:45 -04001265 return use_startup_portal_list_ ? startup_portal_list_ :
1266 props_.check_portal_list;
Paul Stewart10e9e4e2012-04-26 19:46:28 -07001267}
1268
1269void Manager::SetCheckPortalList(const string &portal_list, Error *error) {
1270 props_.check_portal_list = portal_list;
1271 use_startup_portal_list_ = false;
1272}
1273
Paul Stewart4d5efb72012-09-17 12:24:34 -07001274string Manager::GetIgnoredDNSSearchPaths(Error */*error*/) {
1275 return props_.ignored_dns_search_paths;
1276}
1277
1278void Manager::SetIgnoredDNSSearchPaths(const string &ignored_paths,
1279 Error */*error*/) {
1280 props_.ignored_dns_search_paths = ignored_paths;
1281 vector<string> ignored_path_list;
1282 if (!ignored_paths.empty()) {
1283 base::SplitString(ignored_paths, ',', &ignored_path_list);
1284 }
1285 resolver_->set_ignored_search_list(ignored_path_list);
1286}
1287
mukesh agrawal32399322011-09-01 10:53:43 -07001288// called via RPC (e.g., from ManagerDBusAdaptor)
Darin Petkovb65c2452012-02-23 15:17:06 +01001289ServiceRefPtr Manager::GetService(const KeyValueStore &args, Error *error) {
Paul Stewart7f5ad572012-06-04 15:18:54 -07001290 if (args.ContainsString(flimflam::kTypeProperty) &&
1291 args.GetString(flimflam::kTypeProperty) == flimflam::kTypeVPN) {
1292 // GetService on a VPN service should actually perform ConfigureService.
1293 // TODO(pstew): Remove this hack and change Chrome to use ConfigureService
1294 // instead, when we no longer need to support flimflam. crosbug.com/31523
1295 return ConfigureService(args, error);
1296 }
Paul Stewart2c575d22012-12-07 12:28:57 -08001297
1298 ServiceRefPtr service = GetServiceInner(args, error);
1299 if (service) {
1300 // Configures the service using the rest of the passed-in arguments.
1301 service->Configure(args, error);
1302 }
1303
1304 return service;
Paul Stewart7f5ad572012-06-04 15:18:54 -07001305}
1306
1307ServiceRefPtr Manager::GetServiceInner(const KeyValueStore &args,
1308 Error *error) {
Paul Stewart13ed2252012-03-21 12:52:46 -07001309 if (args.ContainsString(flimflam::kGuidProperty)) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001310 SLOG(Manager, 2) << __func__ << ": searching by GUID";
Paul Stewart13ed2252012-03-21 12:52:46 -07001311 ServiceRefPtr service =
1312 GetServiceWithGUID(args.GetString(flimflam::kGuidProperty), NULL);
1313 if (service) {
Paul Stewart13ed2252012-03-21 12:52:46 -07001314 return service;
1315 }
1316 }
1317
Darin Petkovb65c2452012-02-23 15:17:06 +01001318 if (!args.ContainsString(flimflam::kTypeProperty)) {
Paul Stewart7f61e522012-03-22 11:13:45 -07001319 Error::PopulateAndLog(error, Error::kInvalidArguments, kErrorTypeRequired);
Darin Petkovb65c2452012-02-23 15:17:06 +01001320 return NULL;
1321 }
1322
1323 string type = args.GetString(flimflam::kTypeProperty);
Darin Petkovd1cd7972012-05-22 15:26:15 +02001324 if (type == flimflam::kTypeVPN) {
1325 SLOG(Manager, 2) << __func__ << ": getting VPN Service";
1326 return vpn_provider_.GetService(args, error);
1327 }
Darin Petkovb65c2452012-02-23 15:17:06 +01001328 if (type == flimflam::kTypeWifi) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001329 SLOG(Manager, 2) << __func__ << ": getting WiFi Service";
Darin Petkovb65c2452012-02-23 15:17:06 +01001330 return GetWifiService(args, error);
1331 }
Darin Petkovd1cd7972012-05-22 15:26:15 +02001332 if (type == flimflam::kTypeWimax) {
1333 SLOG(Manager, 2) << __func__ << ": getting WiMAX Service";
1334 return wimax_provider_.GetService(args, error);
Darin Petkovb65c2452012-02-23 15:17:06 +01001335 }
mukesh agrawal06175d72012-04-23 16:46:01 -07001336 Error::PopulateAndLog(error, Error::kNotSupported,
1337 kErrorUnsupportedServiceType);
Darin Petkovb65c2452012-02-23 15:17:06 +01001338 return NULL;
1339}
1340
mukesh agrawal7a4e4002011-09-06 11:26:05 -07001341WiFiServiceRefPtr Manager::GetWifiService(const KeyValueStore &args,
1342 Error *error) {
Paul Stewarta41e38d2011-11-11 07:47:29 -08001343 vector<DeviceRefPtr> wifi_devices;
Paul Stewart22aa71b2011-09-16 12:15:11 -07001344 FilterByTechnology(Technology::kWifi, &wifi_devices);
mukesh agrawal7a4e4002011-09-06 11:26:05 -07001345 if (wifi_devices.empty()) {
mukesh agrawal06175d72012-04-23 16:46:01 -07001346 Error::PopulateAndLog(error, Error::kInvalidArguments, kErrorNoDevice);
mukesh agrawal7a4e4002011-09-06 11:26:05 -07001347 return NULL;
1348 } else {
1349 WiFi *wifi = dynamic_cast<WiFi *>(wifi_devices.front().get());
1350 CHECK(wifi);
1351 return wifi->GetService(args, error);
1352 }
1353}
1354
Paul Stewart7f61e522012-03-22 11:13:45 -07001355// called via RPC (e.g., from ManagerDBusAdaptor)
Paul Stewart7f5ad572012-06-04 15:18:54 -07001356ServiceRefPtr Manager::ConfigureService(const KeyValueStore &args,
1357 Error *error) {
Paul Stewart7f61e522012-03-22 11:13:45 -07001358 ProfileRefPtr profile = ActiveProfile();
1359 bool profile_specified = args.ContainsString(flimflam::kProfileProperty);
1360 if (profile_specified) {
1361 string profile_rpcid = args.GetString(flimflam::kProfileProperty);
1362 profile = LookupProfileByRpcIdentifier(profile_rpcid);
1363 if (!profile) {
1364 Error::PopulateAndLog(error, Error::kInvalidArguments,
1365 "Invalid profile name " + profile_rpcid);
Paul Stewart7f5ad572012-06-04 15:18:54 -07001366 return NULL;
Paul Stewart7f61e522012-03-22 11:13:45 -07001367 }
1368 }
1369
Paul Stewart7f5ad572012-06-04 15:18:54 -07001370 ServiceRefPtr service = GetServiceInner(args, error);
Paul Stewart7f61e522012-03-22 11:13:45 -07001371 if (error->IsFailure() || !service) {
1372 LOG(ERROR) << "GetService failed; returning upstream error.";
Paul Stewart7f5ad572012-06-04 15:18:54 -07001373 return NULL;
Paul Stewart7f61e522012-03-22 11:13:45 -07001374 }
1375
Paul Stewart2c575d22012-12-07 12:28:57 -08001376 // First pull in any stored configuration associated with the service.
1377 if (service->profile() == profile) {
Darin Petkov457728b2013-01-09 09:49:08 +01001378 SLOG(Manager, 2) << __func__ << ": service " << service->unique_name()
Paul Stewart2c575d22012-12-07 12:28:57 -08001379 << " is already a member of profile "
1380 << profile->GetFriendlyName()
1381 << " so a load is not necessary.";
1382 } else if (profile->LoadService(service)) {
1383 SLOG(Manager, 2) << __func__ << ": applied stored information from profile "
1384 << profile->GetFriendlyName()
1385 << " into service "
Darin Petkov457728b2013-01-09 09:49:08 +01001386 << service->unique_name();
Paul Stewart2c575d22012-12-07 12:28:57 -08001387 } else {
1388 SLOG(Manager, 2) << __func__ << ": no previous information in profile "
1389 << profile->GetFriendlyName()
1390 << " exists for service "
Darin Petkov457728b2013-01-09 09:49:08 +01001391 << service->unique_name();
Paul Stewart2c575d22012-12-07 12:28:57 -08001392 }
1393
1394 // Overlay this with the passed-in configuration parameters.
1395 service->Configure(args, error);
1396
mukesh agrawal06175d72012-04-23 16:46:01 -07001397 // Overwrite the profile data with the resulting configured service.
Paul Stewart7f61e522012-03-22 11:13:45 -07001398 if (!profile->UpdateService(service)) {
1399 Error::PopulateAndLog(error, Error::kInternalError,
1400 "Unable to save service to profile");
Paul Stewart7f5ad572012-06-04 15:18:54 -07001401 return NULL;
Paul Stewart7f61e522012-03-22 11:13:45 -07001402 }
1403
1404 if (HasService(service)) {
1405 // If the service has been registered (it may not be -- as is the case
1406 // with invisible WiFi networks), we can now transfer the service between
1407 // profiles.
Paul Stewart10ccbb32012-04-26 15:59:30 -07001408 if (IsServiceEphemeral(service) ||
Paul Stewart7f61e522012-03-22 11:13:45 -07001409 (profile_specified && service->profile() != profile)) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001410 SLOG(Manager, 2) << "Moving service to profile "
1411 << profile->GetFriendlyName();
Paul Stewart7f61e522012-03-22 11:13:45 -07001412 if (!MoveServiceToProfile(service, profile)) {
1413 Error::PopulateAndLog(error, Error::kInternalError,
1414 "Unable to move service to profile");
1415 }
1416 }
1417 }
Paul Stewart4357f4e2012-04-26 17:39:26 -07001418
1419 // Notify the service that a profile has been configured for it.
1420 service->OnProfileConfigured();
Paul Stewart7f5ad572012-06-04 15:18:54 -07001421
1422 return service;
Paul Stewart7f61e522012-03-22 11:13:45 -07001423}
1424
Gaurav Shahb790aa22012-10-23 12:51:12 -07001425map<string, GeolocationInfos> Manager::GetNetworksForGeolocation() {
1426 map<string, GeolocationInfos> networks;
1427 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1428 it != devices_.end(); ++it) {
1429 switch((*it)->technology()) {
1430 // TODO(gauravsh): crosbug.com/35736 Need a strategy for combining
1431 // geolocation objects from multiple devices of the same technolgy.
1432 // Currently, we just pick the geolocation objects from the first found
1433 // device of each supported technology type.
1434 case Technology::kWifi:
1435 if (!ContainsKey(networks, kGeoWifiAccessPointsProperty))
1436 networks[kGeoWifiAccessPointsProperty] =
1437 (*it)->GetGeolocationObjects();
1438 break;
1439 case Technology::kCellular:
1440 if (!ContainsKey(networks, kGeoCellTowersProperty))
1441 networks[kGeoCellTowersProperty] = (*it)->GetGeolocationObjects();
1442 break;
1443 default:
1444 // Ignore other technologies.
1445 break;
1446 };
1447 }
1448 return networks;
1449};
1450
Paul Stewartc681fa02012-03-02 19:40:04 -08001451void Manager::RecheckPortal(Error */*error*/) {
1452 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1453 it != devices_.end(); ++it) {
1454 if ((*it)->RequestPortalDetection()) {
1455 // Only start Portal Detection on the device with the default connection.
1456 // We will get a "true" return value when we've found that device, and
1457 // can end our loop early as a result.
1458 break;
1459 }
1460 }
1461}
1462
Paul Stewartd215af62012-04-24 23:25:50 -07001463void Manager::RecheckPortalOnService(const ServiceRefPtr &service) {
1464 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1465 it != devices_.end(); ++it) {
1466 if ((*it)->IsConnectedToService(service)) {
1467 // As opposed to RecheckPortal() above, we explicitly stop and then
1468 // restart portal detection, since the service to recheck was explicitly
1469 // specified.
1470 (*it)->RestartPortalDetection();
1471 break;
1472 }
1473 }
1474}
1475
mukesh agrawal7a4e4002011-09-06 11:26:05 -07001476// called via RPC (e.g., from ManagerDBusAdaptor)
Paul Stewart22aa71b2011-09-16 12:15:11 -07001477void Manager::RequestScan(const string &technology, Error *error) {
mukesh agrawal32399322011-09-01 10:53:43 -07001478 if (technology == flimflam::kTypeWifi || technology == "") {
1479 vector<DeviceRefPtr> wifi_devices;
Paul Stewartfdd16072011-09-16 12:41:35 -07001480 FilterByTechnology(Technology::kWifi, &wifi_devices);
mukesh agrawal32399322011-09-01 10:53:43 -07001481
1482 for (vector<DeviceRefPtr>::iterator it = wifi_devices.begin();
1483 it != wifi_devices.end();
1484 ++it) {
Darin Petkovc0865312011-09-16 15:31:20 -07001485 (*it)->Scan(error);
mukesh agrawal32399322011-09-01 10:53:43 -07001486 }
1487 } else {
1488 // TODO(quiche): support scanning for other technologies?
Paul Stewartbe005172011-11-02 18:10:29 -07001489 Error::PopulateAndLog(error, Error::kInvalidArguments,
1490 "Unrecognized technology " + technology);
mukesh agrawal32399322011-09-01 10:53:43 -07001491 }
1492}
1493
Paul Stewart22aa71b2011-09-16 12:15:11 -07001494string Manager::GetTechnologyOrder() {
1495 vector<string> technology_names;
1496 for (vector<Technology::Identifier>::iterator it = technology_order_.begin();
1497 it != technology_order_.end();
1498 ++it) {
1499 technology_names.push_back(Technology::NameFromIdentifier(*it));
1500 }
1501
1502 return JoinString(technology_names, ',');
1503}
1504
1505void Manager::SetTechnologyOrder(const string &order, Error *error) {
1506 vector<Technology::Identifier> new_order;
Ben Chanfad4a0b2012-04-18 15:49:59 -07001507 SLOG(Manager, 2) << "Setting technology order to " << order;
Paul Stewart20088d82012-02-16 06:58:55 -08001508 if (!Technology::GetTechnologyVectorFromString(order, &new_order, error)) {
1509 return;
Paul Stewart22aa71b2011-09-16 12:15:11 -07001510 }
1511
1512 technology_order_ = new_order;
1513 SortServices();
1514}
1515
Paul Stewart75897df2011-04-27 09:05:53 -07001516} // namespace shill