blob: cc54ddedc9ba99fee7595b7d0d597fe71c5f7644 [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),
94 default_service_callback_tag_(0) {
Chris Masone7aa5f902011-07-11 11:13:35 -070095 HelpRegisterDerivedString(flimflam::kActiveProfileProperty,
Paul Stewart1b253142012-01-26 14:05:52 -080096 &Manager::GetActiveProfileRpcIdentifier,
Chris Masone7aa5f902011-07-11 11:13:35 -070097 NULL);
Paul Stewartd408fdf2012-05-07 17:15:57 -070098 store_.RegisterBool(flimflam::kArpGatewayProperty, &props_.arp_gateway);
Chris Masone27c4aa52011-07-02 13:10:14 -070099 HelpRegisterDerivedStrings(flimflam::kAvailableTechnologiesProperty,
100 &Manager::AvailableTechnologies,
101 NULL);
Paul Stewart10e9e4e2012-04-26 19:46:28 -0700102 HelpRegisterDerivedString(flimflam::kCheckPortalListProperty,
103 &Manager::GetCheckPortalList,
104 &Manager::SetCheckPortalList);
Chris Masone27c4aa52011-07-02 13:10:14 -0700105 HelpRegisterDerivedStrings(flimflam::kConnectedTechnologiesProperty,
106 &Manager::ConnectedTechnologies,
107 NULL);
Chris Masone88cbd5f2011-07-03 14:30:04 -0700108 store_.RegisterString(flimflam::kCountryProperty, &props_.country);
Chris Masone27c4aa52011-07-02 13:10:14 -0700109 HelpRegisterDerivedString(flimflam::kDefaultTechnologyProperty,
110 &Manager::DefaultTechnology,
111 NULL);
Paul Stewart49739c02012-08-08 17:24:03 -0700112 HelpRegisterConstDerivedRpcIdentifier(
113 shill::kDefaultServiceProperty,
114 &Manager::GetDefaultServiceRpcIdentifier);
Paul Stewartcb3eb892012-06-07 14:24:46 -0700115 HelpRegisterConstDerivedRpcIdentifiers(flimflam::kDevicesProperty,
116 &Manager::EnumerateDevices);
Chris Masone88cbd5f2011-07-03 14:30:04 -0700117 HelpRegisterDerivedStrings(flimflam::kEnabledTechnologiesProperty,
118 &Manager::EnabledTechnologies,
119 NULL);
Paul Stewart4d5efb72012-09-17 12:24:34 -0700120 HelpRegisterDerivedString(shill::kIgnoredDNSSearchPathsProperty,
121 &Manager::GetIgnoredDNSSearchPaths,
122 &Manager::SetIgnoredDNSSearchPaths);
Paul Stewart036dba02012-08-07 12:34:41 -0700123 store_.RegisterString(shill::kLinkMonitorTechnologiesProperty,
124 &props_.link_monitor_technologies);
Chris Masone88cbd5f2011-07-03 14:30:04 -0700125 store_.RegisterBool(flimflam::kOfflineModeProperty, &props_.offline_mode);
126 store_.RegisterString(flimflam::kPortalURLProperty, &props_.portal_url);
Paul Stewartc681fa02012-03-02 19:40:04 -0800127 store_.RegisterInt32(kPortalCheckIntervalProperty,
128 &props_.portal_check_interval_seconds);
Paul Stewartcb3eb892012-06-07 14:24:46 -0700129 HelpRegisterConstDerivedRpcIdentifiers(flimflam::kProfilesProperty,
130 &Manager::EnumerateProfiles);
Paul Stewartc681fa02012-03-02 19:40:04 -0800131 store_.RegisterString(kHostNameProperty, &props_.host_name);
Chris Masone88cbd5f2011-07-03 14:30:04 -0700132 HelpRegisterDerivedString(flimflam::kStateProperty,
133 &Manager::CalculateState,
134 NULL);
mukesh agrawal2366eed2012-03-20 18:21:50 -0700135 HelpRegisterConstDerivedRpcIdentifiers(flimflam::kServicesProperty,
136 &Manager::EnumerateAvailableServices);
Paul Stewartcb3eb892012-06-07 14:24:46 -0700137 HelpRegisterConstDerivedRpcIdentifiers(flimflam::kServiceWatchListProperty,
138 &Manager::EnumerateWatchedServices);
Paul Stewartbf667612012-06-29 14:49:54 -0700139 store_.RegisterString(shill::kShortDNSTimeoutTechnologiesProperty,
140 &props_.short_dns_timeout_technologies);
Chris Masone3c3f6a12011-07-01 10:01:41 -0700141
mukesh agrawal84de5d22012-02-17 19:29:15 -0800142 // Set default technology order "by hand", to avoid invoking side
143 // effects of SetTechnologyOrder.
144 technology_order_.push_back(
Darin Petkov2f903b32012-04-18 12:56:43 +0200145 Technology::IdentifierFromName(flimflam::kTypeVPN));
146 technology_order_.push_back(
mukesh agrawal84de5d22012-02-17 19:29:15 -0800147 Technology::IdentifierFromName(flimflam::kTypeEthernet));
148 technology_order_.push_back(
149 Technology::IdentifierFromName(flimflam::kTypeWifi));
150 technology_order_.push_back(
Ben Chan3cafe382012-11-13 07:51:10 -0800151 Technology::IdentifierFromName(flimflam::kTypeWimax));
152 technology_order_.push_back(
mukesh agrawal84de5d22012-02-17 19:29:15 -0800153 Technology::IdentifierFromName(flimflam::kTypeCellular));
154
Ben Chanfad4a0b2012-04-18 15:49:59 -0700155 SLOG(Manager, 2) << "Manager initialized.";
Paul Stewart75897df2011-04-27 09:05:53 -0700156}
157
Darin Petkove7c6ad32012-06-29 10:22:09 +0200158Manager::~Manager() {}
Paul Stewart75897df2011-04-27 09:05:53 -0700159
mukesh agrawal8f317b62011-07-15 11:53:23 -0700160void Manager::AddDeviceToBlackList(const string &device_name) {
161 device_info_.AddDeviceToBlackList(device_name);
162}
163
Paul Stewart75897df2011-04-27 09:05:53 -0700164void Manager::Start() {
Paul Stewart0af98bf2011-05-10 17:38:08 -0700165 LOG(INFO) << "Manager started.";
Paul Stewarte6132022011-08-16 09:11:02 -0700166
Darin Petkov002c58e2012-06-19 02:56:05 +0200167 dbus_manager_.reset(new DBusManager());
168 dbus_manager_->Start();
169
Darin Petkov3ec55342012-09-28 14:04:44 +0200170 power_manager_.reset(
171 new PowerManager(dispatcher_, ProxyFactory::GetInstance()));
Darin Petkovca621542012-07-25 14:25:56 +0200172 power_manager_->AddStateChangeCallback(
Darin Petkov3ec55342012-09-28 14:04:44 +0200173 kPowerManagerKey,
Darin Petkovca621542012-07-25 14:25:56 +0200174 Bind(&Manager::OnPowerStateChanged, AsWeakPtr()));
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500175 // TODO(ers): weak ptr for metrics_?
176 PowerManager::PowerStateCallback cb =
177 Bind(&Metrics::NotifyPowerStateChange, Unretained(metrics_));
Thieu Leb84ba342012-03-02 15:15:19 -0800178 power_manager_->AddStateChangeCallback(Metrics::kMetricPowerManagerKey, cb);
179
Chris Masone2ae797d2011-08-23 20:41:00 -0700180 CHECK(file_util::CreateDirectory(run_path_)) << run_path_.value();
Paul Stewart4d5efb72012-09-17 12:24:34 -0700181 resolver_->set_path(run_path_.Append("resolv.conf"));
Chris Masone2ae797d2011-08-23 20:41:00 -0700182
Gaurav Shah71354762011-11-28 19:22:49 -0800183 InitializeProfiles();
Paul Stewart75897df2011-04-27 09:05:53 -0700184 running_ = true;
Chris Masone413a3192011-05-09 17:10:05 -0700185 adaptor_->UpdateRunning();
Paul Stewart0af98bf2011-05-10 17:38:08 -0700186 device_info_.Start();
Darin Petkov887f2982011-07-14 16:10:17 -0700187 modem_info_.Start();
Darin Petkov33af05c2012-02-28 10:10:30 +0100188 vpn_provider_.Start();
Darin Petkov9893d9c2012-05-17 15:27:31 -0700189 wimax_provider_.Start();
Paul Stewart75897df2011-04-27 09:05:53 -0700190}
191
192void Manager::Stop() {
193 running_ = false;
Paul Stewart212d60f2012-07-12 10:59:13 -0700194 // Persist device information to disk;
195 vector<DeviceRefPtr>::iterator devices_it;
196 for (devices_it = devices_.begin(); devices_it != devices_.end();
197 ++devices_it) {
198 UpdateDevice(*devices_it);
199 }
200
201 // Persist profile, service information to disk.
202 vector<ProfileRefPtr>::iterator profiles_it;
203 for (profiles_it = profiles_.begin(); profiles_it != profiles_.end();
204 ++profiles_it) {
Paul Stewartd0a3b812012-03-28 22:48:22 -0700205 // Since this happens in a loop, the current manager state is stored to
206 // all default profiles in the stack. This is acceptable because the
207 // only time multiple default profiles are loaded are during autotests.
Paul Stewart212d60f2012-07-12 10:59:13 -0700208 (*profiles_it)->Save();
Chris Masone9d779932011-08-25 16:33:41 -0700209 }
Chris Masone9d779932011-08-25 16:33:41 -0700210
Thieu Le1271d682011-11-02 22:48:19 +0000211 vector<ServiceRefPtr>::iterator services_it;
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000212 Error e;
Thieu Le1271d682011-11-02 22:48:19 +0000213 for (services_it = services_.begin(); services_it != services_.end();
214 ++services_it) {
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000215 (*services_it)->Disconnect(&e);
Thieu Le1271d682011-11-02 22:48:19 +0000216 }
217
Chris Masone413a3192011-05-09 17:10:05 -0700218 adaptor_->UpdateRunning();
Darin Petkovb72b62e2012-05-15 16:55:36 +0200219 wimax_provider_.Stop();
Darin Petkov33af05c2012-02-28 10:10:30 +0100220 vpn_provider_.Stop();
Darin Petkov887f2982011-07-14 16:10:17 -0700221 modem_info_.Stop();
222 device_info_.Stop();
Paul Stewartdfa46052012-06-26 09:44:14 -0700223 sort_services_task_.Cancel();
Darin Petkovca621542012-07-25 14:25:56 +0200224 power_manager_.reset();
Darin Petkov002c58e2012-06-19 02:56:05 +0200225 dbus_manager_.reset();
Paul Stewart75897df2011-04-27 09:05:53 -0700226}
227
Gaurav Shah71354762011-11-28 19:22:49 -0800228void Manager::InitializeProfiles() {
229 DCHECK(profiles_.empty());
230 // The default profile must go first on the stack.
231 CHECK(file_util::CreateDirectory(storage_path_)) << storage_path_.value();
Paul Stewart870523b2012-01-11 17:00:42 -0800232 scoped_refptr<DefaultProfile>
233 default_profile(new DefaultProfile(control_interface_,
Gaurav Shah71354762011-11-28 19:22:49 -0800234 this,
235 storage_path_,
Paul Stewartd0a3b812012-03-28 22:48:22 -0700236 DefaultProfile::kDefaultId,
Gaurav Shah71354762011-11-28 19:22:49 -0800237 props_));
Paul Stewart870523b2012-01-11 17:00:42 -0800238 CHECK(default_profile->InitStorage(glib_, Profile::kCreateOrOpenExisting,
239 NULL));
Paul Stewart4d5efb72012-09-17 12:24:34 -0700240 CHECK(LoadProperties(default_profile));
Paul Stewart870523b2012-01-11 17:00:42 -0800241 profiles_.push_back(default_profile.release());
Gaurav Shah71354762011-11-28 19:22:49 -0800242 Error error;
Paul Stewart19c871d2011-12-15 16:10:13 -0800243 string path;
Gaurav Shah71354762011-11-28 19:22:49 -0800244 for (vector<string>::iterator it = startup_profiles_.begin();
245 it != startup_profiles_.end(); ++it)
Paul Stewart19c871d2011-12-15 16:10:13 -0800246 PushProfile(*it, &path, &error);
Gaurav Shah71354762011-11-28 19:22:49 -0800247}
248
Paul Stewart19c871d2011-12-15 16:10:13 -0800249void Manager::CreateProfile(const string &name, string *path, Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700250 SLOG(Manager, 2) << __func__ << " " << name;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700251 Profile::Identifier ident;
252 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700253 Error::PopulateAndLog(error, Error::kInvalidArguments,
254 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700255 return;
256 }
Paul Stewartd0a3b812012-03-28 22:48:22 -0700257
Paul Stewartfc9a1da2012-06-27 15:54:52 -0700258 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
259 it != profiles_.end();
260 ++it) {
261 if ((*it)->MatchesIdentifier(ident)) {
262 Error::PopulateAndLog(error, Error::kAlreadyExists,
263 "Profile name " + name + " is already on stack");
264 *path = (*it)->GetRpcIdentifier();
265 return;
266 }
267 }
268
Paul Stewartd0a3b812012-03-28 22:48:22 -0700269 ProfileRefPtr profile;
270 if (ident.user.empty()) {
271 profile = new DefaultProfile(control_interface_,
272 this,
273 storage_path_,
274 ident.identifier,
275 props_);
276 } else {
277 profile = new Profile(control_interface_,
278 this,
279 ident,
280 user_storage_format_,
Gary Morainb672d352012-04-25 09:19:06 -0700281 true);
Paul Stewartd0a3b812012-03-28 22:48:22 -0700282 }
283
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700284 if (!profile->InitStorage(glib_, Profile::kCreateNew, error)) {
Paul Stewart19c871d2011-12-15 16:10:13 -0800285 // |error| will have been populated by InitStorage().
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700286 return;
287 }
288
289 // Save profile data out, and then let the scoped pointer fall out of scope.
290 if (!profile->Save()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700291 Error::PopulateAndLog(error, Error::kInternalError,
292 "Profile name " + name + " could not be saved");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700293 return;
294 }
Paul Stewart19c871d2011-12-15 16:10:13 -0800295
296 *path = profile->GetRpcIdentifier();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700297}
298
Paul Stewart19c871d2011-12-15 16:10:13 -0800299void Manager::PushProfile(const string &name, string *path, Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700300 SLOG(Manager, 2) << __func__ << " " << name;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700301 Profile::Identifier ident;
302 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700303 Error::PopulateAndLog(error, Error::kInvalidArguments,
304 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700305 return;
306 }
307
308 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
309 it != profiles_.end();
310 ++it) {
311 if ((*it)->MatchesIdentifier(ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700312 Error::PopulateAndLog(error, Error::kAlreadyExists,
313 "Profile name " + name + " is already on stack");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700314 return;
315 }
316 }
317
Paul Stewartd0a3b812012-03-28 22:48:22 -0700318 ProfileRefPtr profile;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700319 if (ident.user.empty()) {
Paul Stewartd0a3b812012-03-28 22:48:22 -0700320 // Allow a machine-wide-profile to be pushed on the stack only if the
321 // profile stack is empty, or if the topmost profile on the stack is
322 // also a machine-wide (non-user) profile.
323 if (!profiles_.empty() && !profiles_.back()->GetUser().empty()) {
324 Error::PopulateAndLog(error, Error::kInvalidArguments,
325 "Cannot load non-default global profile " + name +
326 " on top of a user profile");
327 return;
328 }
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700329
Paul Stewartd0a3b812012-03-28 22:48:22 -0700330 scoped_refptr<DefaultProfile>
331 default_profile(new DefaultProfile(control_interface_,
332 this,
333 storage_path_,
334 ident.identifier,
335 props_));
336 if (!default_profile->InitStorage(glib_, Profile::kOpenExisting, error)) {
337 // |error| will have been populated by InitStorage().
338 return;
339 }
340
Paul Stewart4d5efb72012-09-17 12:24:34 -0700341 if (!LoadProperties(default_profile)) {
Paul Stewartd0a3b812012-03-28 22:48:22 -0700342 Error::PopulateAndLog(error, Error::kInvalidArguments,
343 "Could not load Manager properties from profile " +
344 name);
345 return;
346 }
347 profile = default_profile;
348 } else {
349 profile = new Profile(control_interface_,
350 this,
351 ident,
352 user_storage_format_,
353 connect_profiles_to_rpc_);
354 if (!profile->InitStorage(glib_, Profile::kOpenExisting, error)) {
355 // |error| will have been populated by InitStorage().
356 return;
357 }
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700358 }
359
Paul Stewarta849a3d2011-11-03 05:54:09 -0700360 profiles_.push_back(profile);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700361
362 // Offer each registered Service the opportunity to join this new Profile.
Paul Stewarta41e38d2011-11-11 07:47:29 -0800363 for (vector<ServiceRefPtr>::iterator it = services_.begin();
364 it != services_.end(); ++it) {
Paul Stewartbba6a5b2011-11-02 18:45:59 -0700365 profile->ConfigureService(*it);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700366 }
367
Paul Stewarta41e38d2011-11-11 07:47:29 -0800368 // Shop the Profile contents around to Devices which can create
369 // non-visible services.
370 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
371 it != devices_.end(); ++it) {
372 profile->ConfigureDevice(*it);
373 }
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800374
Darin Petkovc63dcf02012-05-24 11:51:43 +0200375 // Offer the Profile contents to the service/device providers which will
376 // create new services if necessary.
Paul Stewart66815332012-04-09 18:09:36 -0700377 vpn_provider_.CreateServicesFromProfile(profile);
Darin Petkovc63dcf02012-05-24 11:51:43 +0200378 wimax_provider_.CreateServicesFromProfile(profile);
Paul Stewart66815332012-04-09 18:09:36 -0700379
Paul Stewart19c871d2011-12-15 16:10:13 -0800380 *path = profile->GetRpcIdentifier();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800381 SortServices();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700382}
383
384void Manager::PopProfileInternal() {
385 CHECK(!profiles_.empty());
386 ProfileRefPtr active_profile = profiles_.back();
387 profiles_.pop_back();
Paul Stewart75225512012-01-26 22:51:33 -0800388 vector<ServiceRefPtr>::iterator it;
Paul Stewart65512e12012-03-26 18:01:08 -0700389 for (it = services_.begin(); it != services_.end();) {
390 if ((*it)->profile().get() != active_profile.get() ||
391 MatchProfileWithService(*it) ||
392 !UnloadService(&it)) {
393 LOG(ERROR) << "Skipping unload of service";
394 ++it;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700395 }
396 }
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800397 SortServices();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700398}
399
Paul Stewarta41e38d2011-11-11 07:47:29 -0800400void Manager::PopProfile(const string &name, Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700401 SLOG(Manager, 2) << __func__ << " " << name;
Christopher Wiley3e7635e2012-08-15 09:46:17 -0700402 // This signal is sent when a user logs out of a session. Regardless of
403 // whether we find their profile to remove, lets clear the network related
404 // logs.
405 MemoryLog::GetInstance()->Clear();
406 LOG(INFO) << "Cleared the memory log on logout event.";
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700407 Profile::Identifier ident;
408 if (profiles_.empty()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700409 Error::PopulateAndLog(error, Error::kNotFound, "Profile stack is empty");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700410 return;
411 }
412 ProfileRefPtr active_profile = profiles_.back();
413 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700414 Error::PopulateAndLog(error, Error::kInvalidArguments,
415 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700416 return;
417 }
418 if (!active_profile->MatchesIdentifier(ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700419 Error::PopulateAndLog(error, Error::kNotSupported,
420 name + " is not the active profile");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700421 return;
422 }
423 PopProfileInternal();
424}
425
426void Manager::PopAnyProfile(Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700427 SLOG(Manager, 2) << __func__;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700428 Profile::Identifier ident;
429 if (profiles_.empty()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700430 Error::PopulateAndLog(error, Error::kNotFound, "Profile stack is empty");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700431 return;
432 }
433 PopProfileInternal();
434}
435
Paul Stewarte73d05c2012-03-29 16:26:05 -0700436void Manager::RemoveProfile(const string &name, Error *error) {
437 Profile::Identifier ident;
438 if (!Profile::ParseIdentifier(name, &ident)) {
439 Error::PopulateAndLog(error, Error::kInvalidArguments,
440 "Invalid profile name " + name);
441 return;
442 }
443
444 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
445 it != profiles_.end();
446 ++it) {
447 if ((*it)->MatchesIdentifier(ident)) {
448 Error::PopulateAndLog(error, Error::kInvalidArguments,
449 "Cannot remove profile name " + name +
450 " since it is on stack");
451 return;
452 }
453 }
454
455 ProfileRefPtr profile;
456 if (ident.user.empty()) {
457 profile = new DefaultProfile(control_interface_,
458 this,
459 storage_path_,
460 ident.identifier,
461 props_);
462 } else {
463 profile = new Profile(control_interface_,
464 this,
465 ident,
466 user_storage_format_,
467 false);
468 }
469
470
471 // |error| will have been populated if RemoveStorage fails.
472 profile->RemoveStorage(glib_, error);
473
474 return;
475}
476
Paul Stewart75225512012-01-26 22:51:33 -0800477bool Manager::HandleProfileEntryDeletion(const ProfileRefPtr &profile,
478 const std::string &entry_name) {
479 bool moved_services = false;
480 for (vector<ServiceRefPtr>::iterator it = services_.begin();
Paul Stewart65512e12012-03-26 18:01:08 -0700481 it != services_.end();) {
Paul Stewart75225512012-01-26 22:51:33 -0800482 if ((*it)->profile().get() == profile.get() &&
483 (*it)->GetStorageIdentifier() == entry_name) {
484 profile->AbandonService(*it);
Paul Stewart65512e12012-03-26 18:01:08 -0700485 if (MatchProfileWithService(*it) ||
486 !UnloadService(&it)) {
487 ++it;
Paul Stewart75225512012-01-26 22:51:33 -0800488 }
489 moved_services = true;
Paul Stewart65512e12012-03-26 18:01:08 -0700490 } else {
491 ++it;
Paul Stewart75225512012-01-26 22:51:33 -0800492 }
493 }
494 return moved_services;
495}
496
Paul Stewart0756db92012-01-27 08:34:47 -0800497ServiceRefPtr Manager::GetServiceWithStorageIdentifier(
498 const ProfileRefPtr &profile, const std::string &entry_name, Error *error) {
499 for (vector<ServiceRefPtr>::iterator it = services_.begin();
500 it != services_.end(); ++it) {
501 if ((*it)->profile().get() == profile.get() &&
502 (*it)->GetStorageIdentifier() == entry_name) {
503 return *it;
504 }
505 }
506
Paul Stewart76a89cb2012-09-14 06:06:48 -0700507 string error_string(
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500508 StringPrintf("Entry %s is not registered in the manager",
509 entry_name.c_str()));
Paul Stewart76a89cb2012-09-14 06:06:48 -0700510 if (error) {
511 error->Populate(Error::kNotFound, error_string);
512 }
513 SLOG(Manager, 2) << error_string;
Paul Stewart0756db92012-01-27 08:34:47 -0800514 return NULL;
515}
516
Paul Stewart13ed2252012-03-21 12:52:46 -0700517ServiceRefPtr Manager::GetServiceWithGUID(
518 const std::string &guid, Error *error) {
519 for (vector<ServiceRefPtr>::iterator it = services_.begin();
520 it != services_.end(); ++it) {
521 if ((*it)->guid() == guid) {
522 return *it;
523 }
524 }
525
Paul Stewart76a89cb2012-09-14 06:06:48 -0700526 string error_string(
Paul Stewart13ed2252012-03-21 12:52:46 -0700527 StringPrintf("Service wth GUID %s is not registered in the manager",
528 guid.c_str()));
Paul Stewart76a89cb2012-09-14 06:06:48 -0700529 if (error) {
530 error->Populate(Error::kNotFound, error_string);
531 }
532 SLOG(Manager, 2) << error_string;
Paul Stewart13ed2252012-03-21 12:52:46 -0700533 return NULL;
534}
535
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700536ServiceRefPtr Manager::GetDefaultService() const {
537 if (services_.empty() || !services_[0]->connection().get()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700538 SLOG(Manager, 2) << "In " << __func__ << ": No default connection exists.";
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700539 return NULL;
540 }
541 return services_[0];
542}
543
Paul Stewart49739c02012-08-08 17:24:03 -0700544RpcIdentifier Manager::GetDefaultServiceRpcIdentifier(Error */*error*/) {
545 ServiceRefPtr default_service = GetDefaultService();
546 return default_service ? default_service->GetRpcIdentifier() : "/";
547}
548
Paul Stewart036dba02012-08-07 12:34:41 -0700549bool Manager::IsTechnologyInList(const string &technology_list,
550 Technology::Identifier tech) const {
Paul Stewart20088d82012-02-16 06:58:55 -0800551 Error error;
Paul Stewart036dba02012-08-07 12:34:41 -0700552 vector<Technology::Identifier> technologies;
553 return Technology::GetTechnologyVectorFromString(technology_list,
554 &technologies,
Paul Stewart20088d82012-02-16 06:58:55 -0800555 &error) &&
Paul Stewart036dba02012-08-07 12:34:41 -0700556 std::find(technologies.begin(), technologies.end(), tech) !=
557 technologies.end();
558}
559
560bool Manager::IsPortalDetectionEnabled(Technology::Identifier tech) {
561 return IsTechnologyInList(GetCheckPortalList(NULL), tech);
Paul Stewart20088d82012-02-16 06:58:55 -0800562}
563
Paul Stewart10e9e4e2012-04-26 19:46:28 -0700564void Manager::SetStartupPortalList(const string &portal_list) {
565 startup_portal_list_ = portal_list;
566 use_startup_portal_list_ = true;
567}
568
Paul Stewart10ccbb32012-04-26 15:59:30 -0700569bool Manager::IsServiceEphemeral(const ServiceConstRefPtr &service) const {
570 return service->profile() == ephemeral_profile_;
571}
572
Paul Stewartbf667612012-06-29 14:49:54 -0700573bool Manager::IsTechnologyShortDNSTimeoutEnabled(
Paul Stewart036dba02012-08-07 12:34:41 -0700574 Technology::Identifier technology) const {
575 return IsTechnologyInList(props_.short_dns_timeout_technologies, technology);
576}
577
578bool Manager::IsTechnologyLinkMonitorEnabled(
579 Technology::Identifier technology) const {
580 return IsTechnologyInList(props_.link_monitor_technologies, technology);
Paul Stewartbf667612012-06-29 14:49:54 -0700581}
582
Paul Stewart1b253142012-01-26 14:05:52 -0800583const ProfileRefPtr &Manager::ActiveProfile() const {
Eric Shienbroodc74cf9c2012-03-02 15:00:35 -0500584 DCHECK_NE(profiles_.size(), 0U);
Chris Masone7aa5f902011-07-11 11:13:35 -0700585 return profiles_.back();
586}
587
Paul Stewart1b253142012-01-26 14:05:52 -0800588bool Manager::IsActiveProfile(const ProfileRefPtr &profile) const {
589 return (profiles_.size() > 0 &&
590 ActiveProfile().get() == profile.get());
591}
592
Chris Masone6515aab2011-10-12 16:19:09 -0700593bool Manager::MoveServiceToProfile(const ServiceRefPtr &to_move,
594 const ProfileRefPtr &destination) {
595 const ProfileRefPtr from = to_move->profile();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700596 SLOG(Manager, 2) << "Moving service "
597 << to_move->UniqueName()
598 << " to profile "
599 << destination->GetFriendlyName()
600 << " from "
601 << from->GetFriendlyName();
Chris Masone6515aab2011-10-12 16:19:09 -0700602 return destination->AdoptService(to_move) &&
603 from->AbandonService(to_move);
Chris Masone6791a432011-07-12 13:23:19 -0700604}
605
Paul Stewart7f61e522012-03-22 11:13:45 -0700606ProfileRefPtr Manager::LookupProfileByRpcIdentifier(
607 const string &profile_rpcid) {
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800608 for (vector<ProfileRefPtr>::iterator it = profiles_.begin();
609 it != profiles_.end();
610 ++it) {
611 if (profile_rpcid == (*it)->GetRpcIdentifier()) {
Paul Stewart7f61e522012-03-22 11:13:45 -0700612 return *it;
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800613 }
614 }
Paul Stewart7f61e522012-03-22 11:13:45 -0700615 return NULL;
616}
617
618void Manager::SetProfileForService(const ServiceRefPtr &to_set,
619 const string &profile_rpcid,
620 Error *error) {
621 ProfileRefPtr profile = LookupProfileByRpcIdentifier(profile_rpcid);
622 if (!profile) {
623 Error::PopulateAndLog(error, Error::kInvalidArguments,
624 StringPrintf("Unknown Profile %s requested for "
625 "Service", profile_rpcid.c_str()));
626 return;
627 }
628
Paul Stewart649f3a42012-04-24 23:22:16 -0700629 if (!to_set->profile()) {
630 // We are being asked to set the profile property of a service that
631 // has never been registered. Now is a good time to register it.
632 RegisterService(to_set);
633 }
634
Paul Stewart7f61e522012-03-22 11:13:45 -0700635 if (to_set->profile().get() == profile.get()) {
636 Error::PopulateAndLog(error, Error::kInvalidArguments,
637 "Service is already connected to this profile");
638 } else if (!MoveServiceToProfile(to_set, profile)) {
639 Error::PopulateAndLog(error, Error::kInternalError,
640 "Unable to move service to profile");
641 }
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800642}
643
Eric Shienbrood9a245532012-03-07 14:20:39 -0500644void Manager::EnableTechnology(const std::string &technology_name,
645 Error *error,
646 const ResultCallback &callback) {
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400647 CHECK(error != NULL);
648 DCHECK(error->IsOngoing());
Eric Shienbrood9a245532012-03-07 14:20:39 -0500649 Technology::Identifier id = Technology::IdentifierFromName(technology_name);
650 if (id == Technology::kUnknown) {
651 error->Populate(Error::kInvalidArguments, "Unknown technology");
652 return;
653 }
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400654 bool deferred = false;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500655 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
656 it != devices_.end(); ++it) {
657 DeviceRefPtr device = *it;
Joshua Krollda798622012-06-05 12:30:48 -0700658 if (device->technology() == id && !device->enabled()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500659 device->SetEnabledPersistent(true, error, callback);
660 // Continue with other devices even if one fails
661 // TODO(ers): Decide whether an error should be returned
662 // for the overall EnableTechnology operation if some
663 // devices succeed and some fail.
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400664 if (error->IsOngoing())
665 deferred = true;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500666 }
667 }
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400668 // If no device has deferred work, then clear the error to
669 // communicate to the caller that all work is done.
670 if (!deferred)
671 error->Reset();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500672}
673
674void Manager::DisableTechnology(const std::string &technology_name,
675 Error *error,
676 const ResultCallback &callback) {
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400677 CHECK(error != NULL);
678 DCHECK(error->IsOngoing());
Eric Shienbrood9a245532012-03-07 14:20:39 -0500679 Technology::Identifier id = Technology::IdentifierFromName(technology_name);
680 if (id == Technology::kUnknown) {
681 error->Populate(Error::kInvalidArguments, "Unknown technology");
682 return;
683 }
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400684 bool deferred = false;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500685 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
686 it != devices_.end(); ++it) {
687 DeviceRefPtr device = *it;
Joshua Krollda798622012-06-05 12:30:48 -0700688 if (device->technology() == id && device->enabled()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500689 device->SetEnabledPersistent(false, error, callback);
690 // Continue with other devices even if one fails
691 // TODO(ers): Decide whether an error should be returned
692 // for the overall DisableTechnology operation if some
693 // devices succeed and some fail.
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400694 if (error->IsOngoing())
695 deferred = true;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500696 }
697 }
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400698 // If no device has deferred work, then clear the error to
699 // communicate to the caller that all work is done.
700 if (!deferred)
701 error->Reset();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500702}
703
704void Manager::UpdateEnabledTechnologies() {
705 Error error;
706 adaptor_->EmitStringsChanged(flimflam::kEnabledTechnologiesProperty,
707 EnabledTechnologies(&error));
708}
709
Chris Masone2b105542011-06-22 10:58:09 -0700710void Manager::RegisterDevice(const DeviceRefPtr &to_manage) {
Darin Petkove7c6ad32012-06-29 10:22:09 +0200711 LOG(INFO) << "Device " << to_manage->FriendlyName() << " registered.";
712 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
713 it != devices_.end(); ++it) {
Chris Masonec1e50412011-06-07 13:04:53 -0700714 if (to_manage.get() == it->get())
Chris Masone9be4a9d2011-05-16 15:44:09 -0700715 return;
716 }
Chris Masonec1e50412011-06-07 13:04:53 -0700717 devices_.push_back(to_manage);
Paul Stewartf1ce5d22011-05-19 13:10:20 -0700718
Paul Stewart87a4ae82012-10-26 15:49:32 -0700719 LoadDeviceFromProfiles(to_manage);
Paul Stewarta41e38d2011-11-11 07:47:29 -0800720
Darin Petkove7c6ad32012-06-29 10:22:09 +0200721 // If |to_manage| is new, it needs to be persisted.
722 UpdateDevice(to_manage);
723
Paul Stewarta41e38d2011-11-11 07:47:29 -0800724 // In normal usage, running_ will always be true when we are here, however
725 // unit tests sometimes do things in otherwise invalid states.
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400726 if (running_ && (to_manage->enabled_persistent() ||
727 to_manage->IsUnderlyingDeviceEnabled()))
Eric Shienbrood9a245532012-03-07 14:20:39 -0500728 to_manage->SetEnabled(true);
Gaurav Shah435de2c2011-11-17 19:01:07 -0800729
Eric Shienbrood8839a892012-03-29 10:33:48 -0400730 EmitDeviceProperties();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700731}
732
mukesh agrawal5029c6c2011-08-25 11:12:40 -0700733void Manager::DeregisterDevice(const DeviceRefPtr &to_forget) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700734 SLOG(Manager, 2) << __func__ << "(" << to_forget->FriendlyName() << ")";
Chris Masonec1e50412011-06-07 13:04:53 -0700735 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700736 for (it = devices_.begin(); it != devices_.end(); ++it) {
Chris Masonec1e50412011-06-07 13:04:53 -0700737 if (to_forget.get() == it->get()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700738 SLOG(Manager, 2) << "Deregistered device: " << to_forget->UniqueName();
Paul Stewart212d60f2012-07-12 10:59:13 -0700739 UpdateDevice(to_forget);
Eric Shienbrood9a245532012-03-07 14:20:39 -0500740 to_forget->SetEnabled(false);
Chris Masone9be4a9d2011-05-16 15:44:09 -0700741 devices_.erase(it);
Eric Shienbrood8839a892012-03-29 10:33:48 -0400742 EmitDeviceProperties();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700743 return;
744 }
745 }
Ben Chanfad4a0b2012-04-18 15:49:59 -0700746 SLOG(Manager, 2) << __func__ << " unknown device: "
747 << to_forget->UniqueName();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700748}
749
Paul Stewart87a4ae82012-10-26 15:49:32 -0700750void Manager::LoadDeviceFromProfiles(const DeviceRefPtr &device) {
751 // We are applying device properties from the DefaultProfile, and adding the
752 // union of hidden services in all loaded profiles to the device.
753 for (vector<ProfileRefPtr>::iterator it = profiles_.begin();
754 it != profiles_.end(); ++it) {
755 // Load device configuration, if any exists, as well as hidden services.
756 (*it)->ConfigureDevice(device);
757 }
758}
759
Eric Shienbrood8839a892012-03-29 10:33:48 -0400760void Manager::EmitDeviceProperties() {
761 vector<DeviceRefPtr>::iterator it;
762 vector<string> device_paths;
763 for (it = devices_.begin(); it != devices_.end(); ++it) {
764 device_paths.push_back((*it)->GetRpcIdentifier());
765 }
766 adaptor_->EmitRpcIdentifierArrayChanged(flimflam::kDevicesProperty,
767 device_paths);
768 Error error;
769 adaptor_->EmitStringsChanged(flimflam::kAvailableTechnologiesProperty,
770 AvailableTechnologies(&error));
771 adaptor_->EmitStringsChanged(flimflam::kEnabledTechnologiesProperty,
772 EnabledTechnologies(&error));
773}
774
mukesh agrawal4eb4d782011-12-05 17:34:37 +0000775bool Manager::HasService(const ServiceRefPtr &service) {
776 vector<ServiceRefPtr>::iterator it;
777 for (it = services_.begin(); it != services_.end(); ++it) {
778 if ((*it)->UniqueName() == service->UniqueName())
779 return true;
780 }
781 return false;
782}
783
Chris Masone2b105542011-06-22 10:58:09 -0700784void Manager::RegisterService(const ServiceRefPtr &to_manage) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700785 SLOG(Manager, 2) << "In " << __func__ << "(): Registering service "
786 << to_manage->UniqueName();
mukesh agrawald835b202011-10-07 15:26:47 -0700787
Paul Stewart75225512012-01-26 22:51:33 -0800788 MatchProfileWithService(to_manage);
Chris Masone6791a432011-07-12 13:23:19 -0700789
790 // Now add to OUR list.
Chris Masonec1e50412011-06-07 13:04:53 -0700791 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700792 for (it = services_.begin(); it != services_.end(); ++it) {
mukesh agrawald835b202011-10-07 15:26:47 -0700793 CHECK(to_manage->UniqueName() != (*it)->UniqueName());
Chris Masone9be4a9d2011-05-16 15:44:09 -0700794 }
Chris Masonec1e50412011-06-07 13:04:53 -0700795 services_.push_back(to_manage);
Paul Stewart22aa71b2011-09-16 12:15:11 -0700796 SortServices();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700797}
798
Chris Masone6515aab2011-10-12 16:19:09 -0700799void Manager::DeregisterService(const ServiceRefPtr &to_forget) {
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) {
Chris Masone6791a432011-07-12 13:23:19 -0700802 if (to_forget->UniqueName() == (*it)->UniqueName()) {
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800803 DCHECK(!(*it)->connection());
Paul Stewartfc9a1da2012-06-27 15:54:52 -0700804 (*it)->Unload();
805 (*it)->set_profile(NULL);
Chris Masone9be4a9d2011-05-16 15:44:09 -0700806 services_.erase(it);
Paul Stewart22aa71b2011-09-16 12:15:11 -0700807 SortServices();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700808 return;
809 }
810 }
811}
812
Paul Stewart65512e12012-03-26 18:01:08 -0700813bool Manager::UnloadService(vector<ServiceRefPtr>::iterator *service_iterator) {
814 if (!(**service_iterator)->Unload()) {
815 return false;
816 }
817
818 DCHECK(!(**service_iterator)->connection());
Paul Stewartfc9a1da2012-06-27 15:54:52 -0700819 (**service_iterator)->set_profile(NULL);
Paul Stewart65512e12012-03-26 18:01:08 -0700820 *service_iterator = services_.erase(*service_iterator);
821
822 return true;
823}
824
mukesh agrawal00917ce2011-11-22 23:56:55 +0000825void Manager::UpdateService(const ServiceRefPtr &to_update) {
826 CHECK(to_update);
Paul Stewart03dba0b2011-08-22 16:32:45 -0700827 LOG(INFO) << "Service " << to_update->UniqueName() << " updated;"
Gaurav Shahc6d6c722011-11-17 18:59:39 -0800828 << " state: " << Service::ConnectStateToString(to_update->state())
829 << " failure: "
830 << Service::ConnectFailureToString(to_update->failure());
Ben Chanfad4a0b2012-04-18 15:49:59 -0700831 SLOG(Manager, 2) << "IsConnected(): " << to_update->IsConnected();
832 SLOG(Manager, 2) << "IsConnecting(): " << to_update->IsConnecting();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800833 if (to_update->IsConnected()) {
mukesh agrawal00917ce2011-11-22 23:56:55 +0000834 to_update->MakeFavorite();
Gary Moraind93615e2012-04-27 11:50:03 -0700835 // Persists the updated favorite setting in the profile.
836 SaveServiceToProfile(to_update);
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800837 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700838 SortServices();
Paul Stewart03dba0b2011-08-22 16:32:45 -0700839}
840
Darin Petkove7c6ad32012-06-29 10:22:09 +0200841void Manager::UpdateDevice(const DeviceRefPtr &to_update) {
842 LOG(INFO) << "Device " << to_update->link_name() << " updated: "
843 << (to_update->enabled_persistent() ? "enabled" : "disabled");
844 // Saves the device to the topmost profile that accepts it. Normally, this
845 // would be the only DefaultProfile at the bottom of the stack except in
846 // autotests that push a second test-only DefaultProfile.
847 for (vector<ProfileRefPtr>::reverse_iterator rit = profiles_.rbegin();
848 rit != profiles_.rend(); ++rit) {
849 if ((*rit)->UpdateDevice(to_update)) {
850 return;
851 }
852 }
853}
854
Gary Moraind93615e2012-04-27 11:50:03 -0700855void Manager::SaveServiceToProfile(const ServiceRefPtr &to_update) {
856 if (IsServiceEphemeral(to_update)) {
857 if (profiles_.empty()) {
858 LOG(ERROR) << "Cannot assign profile to service: no profiles exist!";
859 } else {
860 MoveServiceToProfile(to_update, profiles_.back());
861 }
862 } else {
863 to_update->profile()->UpdateService(to_update);
864 }
865}
866
Paul Stewart4d5efb72012-09-17 12:24:34 -0700867bool Manager::LoadProperties(const scoped_refptr<DefaultProfile> &profile) {
868 if (!profile->LoadManagerProperties(&props_)) {
869 return false;
870 }
871 SetIgnoredDNSSearchPaths(props_.ignored_dns_search_paths, NULL);
872 return true;
873}
874
Darin Petkov3ec55342012-09-28 14:04:44 +0200875void Manager::AddTerminationAction(const string &name,
Gary Moraina9fb3252012-05-31 12:05:31 -0700876 const base::Closure &start) {
Darin Petkov3ec55342012-09-28 14:04:44 +0200877 if (termination_actions_.IsEmpty() && power_manager_.get()) {
878 power_manager_->AddSuspendDelayCallback(
879 kPowerManagerKey,
880 Bind(&Manager::OnSuspendDelay, AsWeakPtr()));
881 power_manager_->RegisterSuspendDelay(
882 kTerminationActionsTimeoutMilliseconds);
883 }
Gary Moraina9fb3252012-05-31 12:05:31 -0700884 termination_actions_.Add(name, start);
885}
886
Darin Petkov3ec55342012-09-28 14:04:44 +0200887void Manager::TerminationActionComplete(const string &name) {
Gary Moraina9fb3252012-05-31 12:05:31 -0700888 termination_actions_.ActionComplete(name);
889}
890
Darin Petkov3ec55342012-09-28 14:04:44 +0200891void Manager::RemoveTerminationAction(const string &name) {
892 if (termination_actions_.IsEmpty()) {
893 return;
894 }
Gary Moraina9fb3252012-05-31 12:05:31 -0700895 termination_actions_.Remove(name);
Darin Petkov3ec55342012-09-28 14:04:44 +0200896 if (termination_actions_.IsEmpty() && power_manager_.get()) {
897 power_manager_->UnregisterSuspendDelay();
898 power_manager_->RemoveSuspendDelayCallback(kPowerManagerKey);
899 }
Gary Moraina9fb3252012-05-31 12:05:31 -0700900}
901
902void Manager::RunTerminationActions(
Darin Petkov3ec55342012-09-28 14:04:44 +0200903 const base::Callback<void(const Error &)> &done) {
904 LOG(INFO) << "Running termination actions.";
905 termination_actions_.Run(kTerminationActionsTimeoutMilliseconds, done);
Gary Moraina9fb3252012-05-31 12:05:31 -0700906}
907
Arman Ugurayab22c162012-10-08 19:08:38 -0700908bool Manager::RunTerminationActionsAndNotifyMetrics(
909 const base::Callback<void(const Error &)> &done,
910 Metrics::TerminationActionReason reason) {
911 if (termination_actions_.IsEmpty())
912 return false;
913
914 metrics_->NotifyTerminationActionsStarted(reason);
915 RunTerminationActions(done);
916 return true;
917}
918
Darin Petkova5e07ef2012-07-09 14:27:57 +0200919int Manager::RegisterDefaultServiceCallback(const ServiceCallback &callback) {
920 default_service_callbacks_[++default_service_callback_tag_] = callback;
921 return default_service_callback_tag_;
922}
923
924void Manager::DeregisterDefaultServiceCallback(int tag) {
925 default_service_callbacks_.erase(tag);
926}
927
928void Manager::NotifyDefaultServiceChanged(const ServiceRefPtr &service) {
929 for (map<int, ServiceCallback>::const_iterator it =
930 default_service_callbacks_.begin();
931 it != default_service_callbacks_.end(); ++it) {
932 it->second.Run(service);
933 }
934 metrics_->NotifyDefaultServiceChanged(service);
Paul Stewart49739c02012-08-08 17:24:03 -0700935 EmitDefaultService();
936}
937
938void Manager::EmitDefaultService() {
939 RpcIdentifier rpc_identifier = GetDefaultServiceRpcIdentifier(NULL);
940 if (rpc_identifier != default_service_rpc_identifier_) {
941 adaptor_->EmitRpcIdentifierChanged(shill::kDefaultServiceProperty,
942 rpc_identifier);
943 default_service_rpc_identifier_ = rpc_identifier;
944 }
Darin Petkova5e07ef2012-07-09 14:27:57 +0200945}
946
Darin Petkovca621542012-07-25 14:25:56 +0200947void Manager::OnPowerStateChanged(
948 PowerManagerProxyDelegate::SuspendState power_state) {
949 if (power_state == PowerManagerProxyDelegate::kOn) {
Christopher Wiley0801d192012-09-24 11:57:15 -0700950 vector<ServiceRefPtr>::iterator sit;
951 for (sit = services_.begin(); sit != services_.end(); ++sit) {
952 (*sit)->OnAfterResume();
953 }
Darin Petkovca621542012-07-25 14:25:56 +0200954 SortServices();
mukesh agrawal784566d2012-08-08 18:32:58 -0700955 vector<DeviceRefPtr>::iterator it;
956 for (it = devices_.begin(); it != devices_.end(); ++it) {
957 (*it)->OnAfterResume();
958 }
959 } else if (power_state == PowerManagerProxyDelegate::kMem) {
960 vector<DeviceRefPtr>::iterator it;
961 for (it = devices_.begin(); it != devices_.end(); ++it) {
962 (*it)->OnBeforeSuspend();
963 }
Darin Petkovca621542012-07-25 14:25:56 +0200964 }
965}
966
Darin Petkov3ec55342012-09-28 14:04:44 +0200967void Manager::OnSuspendDelay(uint32 sequence_number) {
Arman Ugurayab22c162012-10-08 19:08:38 -0700968 if (!RunTerminationActionsAndNotifyMetrics(
969 Bind(&Manager::OnSuspendActionsComplete, AsWeakPtr(), sequence_number),
970 Metrics::kTerminationActionReasonSuspend)) {
971 LOG(INFO) << "No suspend actions were run.";
972 power_manager_->SuspendReady(sequence_number);
973 }
Darin Petkov3ec55342012-09-28 14:04:44 +0200974}
975
976void Manager::OnSuspendActionsComplete(uint32 sequence_number,
977 const Error &error) {
978 LOG(INFO) << "Finished suspend actions. Result: " << error;
Arman Ugurayab22c162012-10-08 19:08:38 -0700979 metrics_->NotifyTerminationActionsCompleted(
980 Metrics::kTerminationActionReasonSuspend, error.IsSuccess());
Darin Petkov3ec55342012-09-28 14:04:44 +0200981 power_manager_->SuspendReady(sequence_number);
982}
983
Paul Stewartfdd16072011-09-16 12:41:35 -0700984void Manager::FilterByTechnology(Technology::Identifier tech,
Chris Masonec1e50412011-06-07 13:04:53 -0700985 vector<DeviceRefPtr> *found) {
Chris Masone9be4a9d2011-05-16 15:44:09 -0700986 CHECK(found);
Chris Masonec1e50412011-06-07 13:04:53 -0700987 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700988 for (it = devices_.begin(); it != devices_.end(); ++it) {
Joshua Krollda798622012-06-05 12:30:48 -0700989 if ((*it)->technology() == tech)
Chris Masone9be4a9d2011-05-16 15:44:09 -0700990 found->push_back(*it);
991 }
992}
993
Paul Stewart22aa71b2011-09-16 12:15:11 -0700994ServiceRefPtr Manager::FindService(const string& name) {
Chris Masonec1e50412011-06-07 13:04:53 -0700995 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700996 for (it = services_.begin(); it != services_.end(); ++it) {
Chris Masone6791a432011-07-12 13:23:19 -0700997 if (name == (*it)->UniqueName())
Chris Masonee0dea762011-06-09 09:06:03 -0700998 return *it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700999 }
Chris Masonee0dea762011-06-09 09:06:03 -07001000 return NULL;
Chris Masone9be4a9d2011-05-16 15:44:09 -07001001}
1002
Paul Stewart49739c02012-08-08 17:24:03 -07001003void Manager::HelpRegisterConstDerivedRpcIdentifier(
1004 const string &name,
1005 RpcIdentifier(Manager::*get)(Error *error)) {
1006 store_.RegisterDerivedRpcIdentifier(
1007 name,
1008 RpcIdentifierAccessor(
1009 new CustomAccessor<Manager, RpcIdentifier>(this, get, NULL)));
1010}
1011
mukesh agrawal2366eed2012-03-20 18:21:50 -07001012void Manager::HelpRegisterConstDerivedRpcIdentifiers(
1013 const string &name,
Jason Glasgowdf7c5532012-05-14 14:41:45 -04001014 RpcIdentifiers(Manager::*get)(Error *error)) {
mukesh agrawal2366eed2012-03-20 18:21:50 -07001015 store_.RegisterDerivedRpcIdentifiers(
1016 name,
1017 RpcIdentifiersAccessor(
1018 new CustomAccessor<Manager, RpcIdentifiers>(this, get, NULL)));
1019}
1020
mukesh agrawalffa3d042011-10-06 15:26:10 -07001021void Manager::HelpRegisterDerivedString(
1022 const string &name,
Gaurav Shah1b7a6162011-11-09 11:41:01 -08001023 string(Manager::*get)(Error *),
mukesh agrawalffa3d042011-10-06 15:26:10 -07001024 void(Manager::*set)(const string&, Error *)) {
Chris Masone27c4aa52011-07-02 13:10:14 -07001025 store_.RegisterDerivedString(
1026 name,
1027 StringAccessor(new CustomAccessor<Manager, string>(this, get, set)));
Chris Masoneb925cc82011-06-22 15:39:57 -07001028}
1029
mukesh agrawalffa3d042011-10-06 15:26:10 -07001030void Manager::HelpRegisterDerivedStrings(
1031 const string &name,
Gaurav Shah1b7a6162011-11-09 11:41:01 -08001032 Strings(Manager::*get)(Error *),
mukesh agrawalffa3d042011-10-06 15:26:10 -07001033 void(Manager::*set)(const Strings &, Error *)) {
Chris Masone27c4aa52011-07-02 13:10:14 -07001034 store_.RegisterDerivedStrings(
1035 name,
1036 StringsAccessor(new CustomAccessor<Manager, Strings>(this, get, set)));
Chris Masoneb925cc82011-06-22 15:39:57 -07001037}
1038
Paul Stewart22aa71b2011-09-16 12:15:11 -07001039void Manager::SortServices() {
Paul Stewartdfa46052012-06-26 09:44:14 -07001040 // We might be called in the middle of a series of events that
1041 // may result in multiple calls to Manager::SortServices, or within
1042 // an outer loop that may also be traversing the services_ list.
1043 // Defer this work to the event loop.
1044 if (sort_services_task_.IsCancelled()) {
1045 sort_services_task_.Reset(Bind(&Manager::SortServicesTask, AsWeakPtr()));
1046 dispatcher_->PostTask(sort_services_task_.callback());
1047 }
1048}
1049
1050void Manager::SortServicesTask() {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001051 SLOG(Manager, 4) << "In " << __func__;
Paul Stewartdfa46052012-06-26 09:44:14 -07001052 sort_services_task_.Cancel();
Thieu Lea20cbc22012-01-09 22:01:43 +00001053 ServiceRefPtr default_service;
1054
Paul Stewartc1dec4d2011-12-08 15:25:28 -08001055 if (!services_.empty()) {
Paul Stewarte2bad7c2012-03-14 08:55:33 -07001056 // Keep track of the service that is the candidate for the default
1057 // service. We have not yet tested to see if this service has a
1058 // connection.
Thieu Lea20cbc22012-01-09 22:01:43 +00001059 default_service = services_[0];
Paul Stewartc1dec4d2011-12-08 15:25:28 -08001060 }
Paul Stewart22aa71b2011-09-16 12:15:11 -07001061 sort(services_.begin(), services_.end(), ServiceSorter(technology_order_));
Paul Stewarta41e38d2011-11-11 07:47:29 -08001062
Paul Stewarta41e38d2011-11-11 07:47:29 -08001063 adaptor_->EmitRpcIdentifierArrayChanged(flimflam::kServicesProperty,
Paul Stewartbfb82552012-10-24 16:48:48 -07001064 EnumerateAvailableServices(NULL));
1065 adaptor_->EmitRpcIdentifierArrayChanged(flimflam::kServiceWatchListProperty,
1066 EnumerateWatchedServices(NULL));
Gaurav Shah435de2c2011-11-17 19:01:07 -08001067
1068 Error error;
1069 adaptor_->EmitStringsChanged(flimflam::kConnectedTechnologiesProperty,
1070 ConnectedTechnologies(&error));
1071 adaptor_->EmitStringChanged(flimflam::kDefaultTechnologyProperty,
1072 DefaultTechnology(&error));
Paul Stewartc1dec4d2011-12-08 15:25:28 -08001073
1074 if (!services_.empty()) {
Thieu Lea20cbc22012-01-09 22:01:43 +00001075 ConnectionRefPtr default_connection = default_service->connection();
Darin Petkova5e07ef2012-07-09 14:27:57 +02001076 if (default_connection &&
1077 services_[0]->connection() != default_connection) {
Paul Stewartc1dec4d2011-12-08 15:25:28 -08001078 default_connection->SetIsDefault(false);
1079 }
Darin Petkova5e07ef2012-07-09 14:27:57 +02001080 if (services_[0]->connection()) {
Paul Stewartc1dec4d2011-12-08 15:25:28 -08001081 services_[0]->connection()->SetIsDefault(true);
Thieu Lea20cbc22012-01-09 22:01:43 +00001082 default_service = services_[0];
Paul Stewarte2bad7c2012-03-14 08:55:33 -07001083 } else {
1084 default_service = NULL;
Paul Stewartc1dec4d2011-12-08 15:25:28 -08001085 }
1086 }
Darin Petkova5e07ef2012-07-09 14:27:57 +02001087 NotifyDefaultServiceChanged(default_service);
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001088 AutoConnect();
1089}
1090
Paul Stewart75225512012-01-26 22:51:33 -08001091bool Manager::MatchProfileWithService(const ServiceRefPtr &service) {
1092 vector<ProfileRefPtr>::reverse_iterator it;
1093 for (it = profiles_.rbegin(); it != profiles_.rend(); ++it) {
1094 if ((*it)->ConfigureService(service)) {
1095 break;
1096 }
1097 }
1098 if (it == profiles_.rend()) {
1099 ephemeral_profile_->AdoptService(service);
1100 return false;
1101 }
1102 return true;
1103}
1104
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001105void Manager::AutoConnect() {
Paul Stewart63864b62012-11-07 15:10:55 -08001106 if (!running_) {
1107 LOG(INFO) << "Auto-connect suppressed -- not running.";
1108 return;
1109 }
Darin Petkovca621542012-07-25 14:25:56 +02001110 if (power_manager_.get() &&
1111 power_manager_->power_state() != PowerManagerProxyDelegate::kOn &&
1112 power_manager_->power_state() != PowerManagerProxyDelegate::kUnknown) {
1113 LOG(INFO) << "Auto-connect suppressed -- power state is not 'on'.";
1114 return;
1115 }
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001116 if (services_.empty()) {
Darin Petkovca621542012-07-25 14:25:56 +02001117 LOG(INFO) << "Auto-connect suppressed -- no services.";
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001118 return;
1119 }
1120
Ben Chanfad4a0b2012-04-18 15:49:59 -07001121 if (SLOG_IS_ON(Manager, 4)) {
1122 SLOG(Manager, 4) << "Sorted service list: ";
mukesh agrawalddc378f2012-02-17 18:26:20 -08001123 for (size_t i = 0; i < services_.size(); ++i) {
1124 ServiceRefPtr service = services_[i];
1125 const char *compare_reason = NULL;
1126 if (i + 1 < services_.size()) {
1127 Service::Compare(
1128 service, services_[i+1], technology_order_, &compare_reason);
1129 } else {
mukesh agrawalbf14e942012-03-02 14:36:34 -08001130 compare_reason = "last";
mukesh agrawalddc378f2012-02-17 18:26:20 -08001131 }
Ben Chanfad4a0b2012-04-18 15:49:59 -07001132 SLOG(Manager, 4) << "Service " << service->friendly_name()
1133 << " IsConnected: " << service->IsConnected()
1134 << " IsConnecting: " << service->IsConnecting()
1135 << " IsFailed: " << service->IsFailed()
1136 << " connectable: " << service->connectable()
1137 << " auto_connect: " << service->auto_connect()
1138 << " favorite: " << service->favorite()
1139 << " priority: " << service->priority()
1140 << " security_level: " << service->security_level()
1141 << " strength: " << service->strength()
1142 << " UniqueName: " << service->UniqueName()
1143 << " sorted: " << compare_reason;
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001144 }
1145 }
1146
Paul Stewart3d9bcf52011-12-12 15:02:22 -08001147 // Perform auto-connect.
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001148 for (vector<ServiceRefPtr>::iterator it = services_.begin();
1149 it != services_.end(); ++it) {
1150 if ((*it)->auto_connect()) {
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001151 (*it)->AutoConnect();
Paul Stewart3d9bcf52011-12-12 15:02:22 -08001152 }
1153 }
Paul Stewart22aa71b2011-09-16 12:15:11 -07001154}
1155
Gaurav Shah1b7a6162011-11-09 11:41:01 -08001156string Manager::CalculateState(Error */*error*/) {
Gary Morain028545d2012-04-07 14:55:52 -07001157 // |services_| is sorted such that connected services are first.
1158 if (!services_.empty() &&
1159 services_.front()->IsConnected()) {
1160 return flimflam::kStateOnline;
1161 }
Chris Masoneb925cc82011-06-22 15:39:57 -07001162 return flimflam::kStateOffline;
1163}
1164
Gaurav Shah1b7a6162011-11-09 11:41:01 -08001165vector<string> Manager::AvailableTechnologies(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -08001166 set<string> unique_technologies;
1167 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1168 it != devices_.end(); ++it) {
1169 unique_technologies.insert(
1170 Technology::NameFromIdentifier((*it)->technology()));
1171 }
1172 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -07001173}
1174
Gaurav Shah1b7a6162011-11-09 11:41:01 -08001175vector<string> Manager::ConnectedTechnologies(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -08001176 set<string> unique_technologies;
1177 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1178 it != devices_.end(); ++it) {
1179 if ((*it)->IsConnected())
1180 unique_technologies.insert(
1181 Technology::NameFromIdentifier((*it)->technology()));
1182 }
1183 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -07001184}
1185
Darin Petkov58f0b6d2012-06-12 12:52:30 +02001186string Manager::DefaultTechnology(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -08001187 return (!services_.empty() && services_[0]->IsConnected()) ?
Darin Petkov58f0b6d2012-06-12 12:52:30 +02001188 services_[0]->GetTechnologyString() : "";
Chris Masoneb925cc82011-06-22 15:39:57 -07001189}
1190
Eric Shienbrood9a245532012-03-07 14:20:39 -05001191vector<string> Manager::EnabledTechnologies(Error */*error*/) {
1192 set<string> unique_technologies;
1193 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1194 it != devices_.end(); ++it) {
1195 if ((*it)->enabled())
1196 unique_technologies.insert(
1197 Technology::NameFromIdentifier((*it)->technology()));
1198 }
1199 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -07001200}
1201
Paul Stewartcb3eb892012-06-07 14:24:46 -07001202RpcIdentifiers Manager::EnumerateDevices(Error */*error*/) {
1203 RpcIdentifiers device_rpc_ids;
Chris Masone3c3f6a12011-07-01 10:01:41 -07001204 for (vector<DeviceRefPtr>::const_iterator it = devices_.begin();
1205 it != devices_.end();
1206 ++it) {
1207 device_rpc_ids.push_back((*it)->GetRpcIdentifier());
1208 }
1209 return device_rpc_ids;
1210}
1211
Paul Stewartcb3eb892012-06-07 14:24:46 -07001212RpcIdentifiers Manager::EnumerateProfiles(Error */*error*/) {
1213 RpcIdentifiers profile_rpc_ids;
Paul Stewart1b253142012-01-26 14:05:52 -08001214 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
1215 it != profiles_.end();
1216 ++it) {
1217 profile_rpc_ids.push_back((*it)->GetRpcIdentifier());
1218 }
1219 return profile_rpc_ids;
1220}
1221
Gaurav Shah1b7a6162011-11-09 11:41:01 -08001222vector<string> Manager::EnumerateAvailableServices(Error */*error*/) {
Chris Masone3c3f6a12011-07-01 10:01:41 -07001223 vector<string> service_rpc_ids;
1224 for (vector<ServiceRefPtr>::const_iterator it = services_.begin();
1225 it != services_.end();
1226 ++it) {
Paul Stewartbfb82552012-10-24 16:48:48 -07001227 if ((*it)->IsVisible()) {
1228 service_rpc_ids.push_back((*it)->GetRpcIdentifier());
1229 }
Chris Masone3c3f6a12011-07-01 10:01:41 -07001230 }
1231 return service_rpc_ids;
1232}
1233
Paul Stewartbfb82552012-10-24 16:48:48 -07001234RpcIdentifiers Manager::EnumerateWatchedServices(Error */*error*/) {
1235 vector<string> service_rpc_ids;
1236 for (vector<ServiceRefPtr>::const_iterator it = services_.begin();
1237 it != services_.end();
1238 ++it) {
1239 if ((*it)->IsVisible() && (*it)->IsActive(NULL)) {
1240 service_rpc_ids.push_back((*it)->GetRpcIdentifier());
1241 }
1242 }
1243 return service_rpc_ids;
Chris Masone3c3f6a12011-07-01 10:01:41 -07001244}
1245
Paul Stewart1b253142012-01-26 14:05:52 -08001246string Manager::GetActiveProfileRpcIdentifier(Error */*error*/) {
1247 return ActiveProfile()->GetRpcIdentifier();
Chris Masone7aa5f902011-07-11 11:13:35 -07001248}
1249
Paul Stewart10e9e4e2012-04-26 19:46:28 -07001250string Manager::GetCheckPortalList(Error */*error*/) {
Jason Glasgowdf7c5532012-05-14 14:41:45 -04001251 return use_startup_portal_list_ ? startup_portal_list_ :
1252 props_.check_portal_list;
Paul Stewart10e9e4e2012-04-26 19:46:28 -07001253}
1254
1255void Manager::SetCheckPortalList(const string &portal_list, Error *error) {
1256 props_.check_portal_list = portal_list;
1257 use_startup_portal_list_ = false;
1258}
1259
Paul Stewart4d5efb72012-09-17 12:24:34 -07001260string Manager::GetIgnoredDNSSearchPaths(Error */*error*/) {
1261 return props_.ignored_dns_search_paths;
1262}
1263
1264void Manager::SetIgnoredDNSSearchPaths(const string &ignored_paths,
1265 Error */*error*/) {
1266 props_.ignored_dns_search_paths = ignored_paths;
1267 vector<string> ignored_path_list;
1268 if (!ignored_paths.empty()) {
1269 base::SplitString(ignored_paths, ',', &ignored_path_list);
1270 }
1271 resolver_->set_ignored_search_list(ignored_path_list);
1272}
1273
mukesh agrawal32399322011-09-01 10:53:43 -07001274// called via RPC (e.g., from ManagerDBusAdaptor)
Darin Petkovb65c2452012-02-23 15:17:06 +01001275ServiceRefPtr Manager::GetService(const KeyValueStore &args, Error *error) {
Paul Stewart7f5ad572012-06-04 15:18:54 -07001276 if (args.ContainsString(flimflam::kTypeProperty) &&
1277 args.GetString(flimflam::kTypeProperty) == flimflam::kTypeVPN) {
1278 // GetService on a VPN service should actually perform ConfigureService.
1279 // TODO(pstew): Remove this hack and change Chrome to use ConfigureService
1280 // instead, when we no longer need to support flimflam. crosbug.com/31523
1281 return ConfigureService(args, error);
1282 }
1283 return GetServiceInner(args, error);
1284}
1285
1286ServiceRefPtr Manager::GetServiceInner(const KeyValueStore &args,
1287 Error *error) {
Paul Stewart13ed2252012-03-21 12:52:46 -07001288 if (args.ContainsString(flimflam::kGuidProperty)) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001289 SLOG(Manager, 2) << __func__ << ": searching by GUID";
Paul Stewart13ed2252012-03-21 12:52:46 -07001290 ServiceRefPtr service =
1291 GetServiceWithGUID(args.GetString(flimflam::kGuidProperty), NULL);
1292 if (service) {
Paul Stewartcb59fed2012-03-21 21:14:46 -07001293 service->Configure(args, error);
Paul Stewart13ed2252012-03-21 12:52:46 -07001294 return service;
1295 }
1296 }
1297
Darin Petkovb65c2452012-02-23 15:17:06 +01001298 if (!args.ContainsString(flimflam::kTypeProperty)) {
Paul Stewart7f61e522012-03-22 11:13:45 -07001299 Error::PopulateAndLog(error, Error::kInvalidArguments, kErrorTypeRequired);
Darin Petkovb65c2452012-02-23 15:17:06 +01001300 return NULL;
1301 }
1302
1303 string type = args.GetString(flimflam::kTypeProperty);
Darin Petkovd1cd7972012-05-22 15:26:15 +02001304 if (type == flimflam::kTypeVPN) {
1305 SLOG(Manager, 2) << __func__ << ": getting VPN Service";
1306 return vpn_provider_.GetService(args, error);
1307 }
Darin Petkovb65c2452012-02-23 15:17:06 +01001308 if (type == flimflam::kTypeWifi) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001309 SLOG(Manager, 2) << __func__ << ": getting WiFi Service";
Darin Petkovb65c2452012-02-23 15:17:06 +01001310 return GetWifiService(args, error);
1311 }
Darin Petkovd1cd7972012-05-22 15:26:15 +02001312 if (type == flimflam::kTypeWimax) {
1313 SLOG(Manager, 2) << __func__ << ": getting WiMAX Service";
1314 return wimax_provider_.GetService(args, error);
Darin Petkovb65c2452012-02-23 15:17:06 +01001315 }
mukesh agrawal06175d72012-04-23 16:46:01 -07001316 Error::PopulateAndLog(error, Error::kNotSupported,
1317 kErrorUnsupportedServiceType);
Darin Petkovb65c2452012-02-23 15:17:06 +01001318 return NULL;
1319}
1320
mukesh agrawal7a4e4002011-09-06 11:26:05 -07001321WiFiServiceRefPtr Manager::GetWifiService(const KeyValueStore &args,
1322 Error *error) {
Paul Stewarta41e38d2011-11-11 07:47:29 -08001323 vector<DeviceRefPtr> wifi_devices;
Paul Stewart22aa71b2011-09-16 12:15:11 -07001324 FilterByTechnology(Technology::kWifi, &wifi_devices);
mukesh agrawal7a4e4002011-09-06 11:26:05 -07001325 if (wifi_devices.empty()) {
mukesh agrawal06175d72012-04-23 16:46:01 -07001326 Error::PopulateAndLog(error, Error::kInvalidArguments, kErrorNoDevice);
mukesh agrawal7a4e4002011-09-06 11:26:05 -07001327 return NULL;
1328 } else {
1329 WiFi *wifi = dynamic_cast<WiFi *>(wifi_devices.front().get());
1330 CHECK(wifi);
1331 return wifi->GetService(args, error);
1332 }
1333}
1334
Paul Stewart7f61e522012-03-22 11:13:45 -07001335// called via RPC (e.g., from ManagerDBusAdaptor)
Paul Stewart7f5ad572012-06-04 15:18:54 -07001336ServiceRefPtr Manager::ConfigureService(const KeyValueStore &args,
1337 Error *error) {
Paul Stewart7f61e522012-03-22 11:13:45 -07001338 ProfileRefPtr profile = ActiveProfile();
1339 bool profile_specified = args.ContainsString(flimflam::kProfileProperty);
1340 if (profile_specified) {
1341 string profile_rpcid = args.GetString(flimflam::kProfileProperty);
1342 profile = LookupProfileByRpcIdentifier(profile_rpcid);
1343 if (!profile) {
1344 Error::PopulateAndLog(error, Error::kInvalidArguments,
1345 "Invalid profile name " + profile_rpcid);
Paul Stewart7f5ad572012-06-04 15:18:54 -07001346 return NULL;
Paul Stewart7f61e522012-03-22 11:13:45 -07001347 }
1348 }
1349
Paul Stewart7f5ad572012-06-04 15:18:54 -07001350 ServiceRefPtr service = GetServiceInner(args, error);
Paul Stewart7f61e522012-03-22 11:13:45 -07001351 if (error->IsFailure() || !service) {
1352 LOG(ERROR) << "GetService failed; returning upstream error.";
Paul Stewart7f5ad572012-06-04 15:18:54 -07001353 return NULL;
Paul Stewart7f61e522012-03-22 11:13:45 -07001354 }
1355
mukesh agrawal06175d72012-04-23 16:46:01 -07001356 // Overwrite the profile data with the resulting configured service.
Paul Stewart7f61e522012-03-22 11:13:45 -07001357 if (!profile->UpdateService(service)) {
1358 Error::PopulateAndLog(error, Error::kInternalError,
1359 "Unable to save service to profile");
Paul Stewart7f5ad572012-06-04 15:18:54 -07001360 return NULL;
Paul Stewart7f61e522012-03-22 11:13:45 -07001361 }
1362
1363 if (HasService(service)) {
1364 // If the service has been registered (it may not be -- as is the case
1365 // with invisible WiFi networks), we can now transfer the service between
1366 // profiles.
Paul Stewart10ccbb32012-04-26 15:59:30 -07001367 if (IsServiceEphemeral(service) ||
Paul Stewart7f61e522012-03-22 11:13:45 -07001368 (profile_specified && service->profile() != profile)) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001369 SLOG(Manager, 2) << "Moving service to profile "
1370 << profile->GetFriendlyName();
Paul Stewart7f61e522012-03-22 11:13:45 -07001371 if (!MoveServiceToProfile(service, profile)) {
1372 Error::PopulateAndLog(error, Error::kInternalError,
1373 "Unable to move service to profile");
1374 }
1375 }
1376 }
Paul Stewart4357f4e2012-04-26 17:39:26 -07001377
1378 // Notify the service that a profile has been configured for it.
1379 service->OnProfileConfigured();
Paul Stewart7f5ad572012-06-04 15:18:54 -07001380
1381 return service;
Paul Stewart7f61e522012-03-22 11:13:45 -07001382}
1383
Gaurav Shahb790aa22012-10-23 12:51:12 -07001384map<string, GeolocationInfos> Manager::GetNetworksForGeolocation() {
1385 map<string, GeolocationInfos> networks;
1386 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1387 it != devices_.end(); ++it) {
1388 switch((*it)->technology()) {
1389 // TODO(gauravsh): crosbug.com/35736 Need a strategy for combining
1390 // geolocation objects from multiple devices of the same technolgy.
1391 // Currently, we just pick the geolocation objects from the first found
1392 // device of each supported technology type.
1393 case Technology::kWifi:
1394 if (!ContainsKey(networks, kGeoWifiAccessPointsProperty))
1395 networks[kGeoWifiAccessPointsProperty] =
1396 (*it)->GetGeolocationObjects();
1397 break;
1398 case Technology::kCellular:
1399 if (!ContainsKey(networks, kGeoCellTowersProperty))
1400 networks[kGeoCellTowersProperty] = (*it)->GetGeolocationObjects();
1401 break;
1402 default:
1403 // Ignore other technologies.
1404 break;
1405 };
1406 }
1407 return networks;
1408};
1409
Paul Stewartc681fa02012-03-02 19:40:04 -08001410void Manager::RecheckPortal(Error */*error*/) {
1411 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1412 it != devices_.end(); ++it) {
1413 if ((*it)->RequestPortalDetection()) {
1414 // Only start Portal Detection on the device with the default connection.
1415 // We will get a "true" return value when we've found that device, and
1416 // can end our loop early as a result.
1417 break;
1418 }
1419 }
1420}
1421
Paul Stewartd215af62012-04-24 23:25:50 -07001422void Manager::RecheckPortalOnService(const ServiceRefPtr &service) {
1423 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1424 it != devices_.end(); ++it) {
1425 if ((*it)->IsConnectedToService(service)) {
1426 // As opposed to RecheckPortal() above, we explicitly stop and then
1427 // restart portal detection, since the service to recheck was explicitly
1428 // specified.
1429 (*it)->RestartPortalDetection();
1430 break;
1431 }
1432 }
1433}
1434
mukesh agrawal7a4e4002011-09-06 11:26:05 -07001435// called via RPC (e.g., from ManagerDBusAdaptor)
Paul Stewart22aa71b2011-09-16 12:15:11 -07001436void Manager::RequestScan(const string &technology, Error *error) {
mukesh agrawal32399322011-09-01 10:53:43 -07001437 if (technology == flimflam::kTypeWifi || technology == "") {
1438 vector<DeviceRefPtr> wifi_devices;
Paul Stewartfdd16072011-09-16 12:41:35 -07001439 FilterByTechnology(Technology::kWifi, &wifi_devices);
mukesh agrawal32399322011-09-01 10:53:43 -07001440
1441 for (vector<DeviceRefPtr>::iterator it = wifi_devices.begin();
1442 it != wifi_devices.end();
1443 ++it) {
Darin Petkovc0865312011-09-16 15:31:20 -07001444 (*it)->Scan(error);
mukesh agrawal32399322011-09-01 10:53:43 -07001445 }
1446 } else {
1447 // TODO(quiche): support scanning for other technologies?
Paul Stewartbe005172011-11-02 18:10:29 -07001448 Error::PopulateAndLog(error, Error::kInvalidArguments,
1449 "Unrecognized technology " + technology);
mukesh agrawal32399322011-09-01 10:53:43 -07001450 }
1451}
1452
Paul Stewart22aa71b2011-09-16 12:15:11 -07001453string Manager::GetTechnologyOrder() {
1454 vector<string> technology_names;
1455 for (vector<Technology::Identifier>::iterator it = technology_order_.begin();
1456 it != technology_order_.end();
1457 ++it) {
1458 technology_names.push_back(Technology::NameFromIdentifier(*it));
1459 }
1460
1461 return JoinString(technology_names, ',');
1462}
1463
1464void Manager::SetTechnologyOrder(const string &order, Error *error) {
1465 vector<Technology::Identifier> new_order;
Ben Chanfad4a0b2012-04-18 15:49:59 -07001466 SLOG(Manager, 2) << "Setting technology order to " << order;
Paul Stewart20088d82012-02-16 06:58:55 -08001467 if (!Technology::GetTechnologyVectorFromString(order, &new_order, error)) {
1468 return;
Paul Stewart22aa71b2011-09-16 12:15:11 -07001469 }
1470
1471 technology_order_ = new_order;
1472 SortServices();
1473}
1474
Paul Stewart75897df2011-04-27 09:05:53 -07001475} // namespace shill