blob: b131388a5cb058ac87315850ed0ffadb4919a1d4 [file] [log] [blame]
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Paul Stewart75897df2011-04-27 09:05:53 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Chris Masone8fe2c7e2011-06-09 15:51:19 -07005#include "shill/manager.h"
6
Paul Stewart75897df2011-04-27 09:05:53 -07007#include <time.h>
Paul Stewart75897df2011-04-27 09:05:53 -07008#include <stdio.h>
Chris Masoneee929b72011-05-10 10:02:18 -07009
Paul Stewart22aa71b2011-09-16 12:15:11 -070010#include <algorithm>
Jason Glasgowdf7c5532012-05-14 14:41:45 -040011#include <set>
Paul Stewart75897df2011-04-27 09:05:53 -070012#include <string>
Chris Masone52cd19b2011-06-29 17:23:04 -070013#include <vector>
Paul Stewart75897df2011-04-27 09:05:53 -070014
Eric Shienbrood3e20a232012-02-16 11:35:56 -050015#include <base/bind.h>
Paul Stewarte6132022011-08-16 09:11:02 -070016#include <base/file_util.h>
Chris Masoneee929b72011-05-10 10:02:18 -070017#include <base/logging.h>
Chris Masone9be4a9d2011-05-16 15:44:09 -070018#include <base/memory/ref_counted.h>
Eric Shienbrood3e20a232012-02-16 11:35:56 -050019#include <base/stringprintf.h>
Paul Stewart22aa71b2011-09-16 12:15:11 -070020#include <base/string_util.h>
Chris Masone3bd3c8c2011-06-13 08:20:26 -070021#include <chromeos/dbus/service_constants.h>
Chris Masoneee929b72011-05-10 10:02:18 -070022
Chris Masoned0ceb8c2011-06-02 10:05:39 -070023#include "shill/adaptor_interfaces.h"
Paul Stewartc1dec4d2011-12-08 15:25:28 -080024#include "shill/connection.h"
Paul Stewart75897df2011-04-27 09:05:53 -070025#include "shill/control_interface.h"
Chris Masoned0ceb8c2011-06-02 10:05:39 -070026#include "shill/dbus_adaptor.h"
Chris Masone7aa5f902011-07-11 11:13:35 -070027#include "shill/default_profile.h"
Chris Masone9be4a9d2011-05-16 15:44:09 -070028#include "shill/device.h"
29#include "shill/device_info.h"
Chris Masone6791a432011-07-12 13:23:19 -070030#include "shill/ephemeral_profile.h"
Chris Masone8fe2c7e2011-06-09 15:51:19 -070031#include "shill/error.h"
Paul Stewart26b327e2011-10-19 11:38:09 -070032#include "shill/event_dispatcher.h"
Chris Masone9d779932011-08-25 16:33:41 -070033#include "shill/key_file_store.h"
Thieu Lea20cbc22012-01-09 22:01:43 +000034#include "shill/metrics.h"
Chris Masone7aa5f902011-07-11 11:13:35 -070035#include "shill/profile.h"
Chris Masoneb925cc82011-06-22 15:39:57 -070036#include "shill/property_accessor.h"
Gary Morainac1bdb42012-02-16 17:42:29 -080037#include "shill/proxy_factory.h"
Paul Stewarte6132022011-08-16 09:11:02 -070038#include "shill/resolver.h"
Ben Chanfad4a0b2012-04-18 15:49:59 -070039#include "shill/scope_logger.h"
Chris Masone9be4a9d2011-05-16 15:44:09 -070040#include "shill/service.h"
Thieu Lea20cbc22012-01-09 22:01:43 +000041#include "shill/service_sorter.h"
Darin Petkov33af05c2012-02-28 10:10:30 +010042#include "shill/vpn_service.h"
mukesh agrawal7a4e4002011-09-06 11:26:05 -070043#include "shill/wifi.h"
44#include "shill/wifi_service.h"
Paul Stewart75897df2011-04-27 09:05:53 -070045
Eric Shienbrood3e20a232012-02-16 11:35:56 -050046using base::Bind;
47using base::StringPrintf;
48using base::Unretained;
Gaurav Shah435de2c2011-11-17 19:01:07 -080049using std::set;
Paul Stewart75897df2011-04-27 09:05:53 -070050using std::string;
Chris Masone9be4a9d2011-05-16 15:44:09 -070051using std::vector;
Paul Stewart75897df2011-04-27 09:05:53 -070052
53namespace shill {
Paul Stewarte6132022011-08-16 09:11:02 -070054
Darin Petkovb65c2452012-02-23 15:17:06 +010055// statics
56const char Manager::kErrorNoDevice[] = "no wifi devices available";
57const char Manager::kErrorTypeRequired[] = "must specify service type";
58const char Manager::kErrorUnsupportedServiceType[] =
59 "service type is unsupported";
mukesh agrawal7a4e4002011-09-06 11:26:05 -070060
Paul Stewart75897df2011-04-27 09:05:53 -070061Manager::Manager(ControlInterface *control_interface,
Darin Petkov887f2982011-07-14 16:10:17 -070062 EventDispatcher *dispatcher,
Thieu Le3426c8f2012-01-11 17:35:11 -080063 Metrics *metrics,
Chris Masone2ae797d2011-08-23 20:41:00 -070064 GLib *glib,
65 const string &run_directory,
66 const string &storage_directory,
67 const string &user_storage_format)
mukesh agrawal8a3188d2011-12-01 20:56:44 +000068 : dispatcher_(dispatcher),
mukesh agrawal8a3188d2011-12-01 20:56:44 +000069 run_path_(FilePath(run_directory)),
70 storage_path_(FilePath(storage_directory)),
71 user_storage_format_(user_storage_format),
72 adaptor_(control_interface->CreateManagerAdaptor(this)),
Thieu Le3426c8f2012-01-11 17:35:11 -080073 device_info_(control_interface, dispatcher, metrics, this),
74 modem_info_(control_interface, dispatcher, metrics, this, glib),
Darin Petkov33af05c2012-02-28 10:10:30 +010075 vpn_provider_(control_interface, dispatcher, metrics, this),
Darin Petkovb72b62e2012-05-15 16:55:36 +020076 wimax_provider_(control_interface, dispatcher, metrics, this),
mukesh agrawal8a3188d2011-12-01 20:56:44 +000077 running_(false),
78 connect_profiles_to_rpc_(true),
79 ephemeral_profile_(new EphemeralProfile(control_interface, this)),
80 control_interface_(control_interface),
Thieu Le3426c8f2012-01-11 17:35:11 -080081 metrics_(metrics),
Paul Stewart10e9e4e2012-04-26 19:46:28 -070082 glib_(glib),
83 use_startup_portal_list_(false) {
Chris Masone7aa5f902011-07-11 11:13:35 -070084 HelpRegisterDerivedString(flimflam::kActiveProfileProperty,
Paul Stewart1b253142012-01-26 14:05:52 -080085 &Manager::GetActiveProfileRpcIdentifier,
Chris Masone7aa5f902011-07-11 11:13:35 -070086 NULL);
Paul Stewartd408fdf2012-05-07 17:15:57 -070087 store_.RegisterBool(flimflam::kArpGatewayProperty, &props_.arp_gateway);
Chris Masone27c4aa52011-07-02 13:10:14 -070088 HelpRegisterDerivedStrings(flimflam::kAvailableTechnologiesProperty,
89 &Manager::AvailableTechnologies,
90 NULL);
Paul Stewart10e9e4e2012-04-26 19:46:28 -070091 HelpRegisterDerivedString(flimflam::kCheckPortalListProperty,
92 &Manager::GetCheckPortalList,
93 &Manager::SetCheckPortalList);
Chris Masone27c4aa52011-07-02 13:10:14 -070094 HelpRegisterDerivedStrings(flimflam::kConnectedTechnologiesProperty,
95 &Manager::ConnectedTechnologies,
96 NULL);
Chris Masone88cbd5f2011-07-03 14:30:04 -070097 store_.RegisterString(flimflam::kCountryProperty, &props_.country);
Chris Masone27c4aa52011-07-02 13:10:14 -070098 HelpRegisterDerivedString(flimflam::kDefaultTechnologyProperty,
99 &Manager::DefaultTechnology,
100 NULL);
Chris Masone27c4aa52011-07-02 13:10:14 -0700101 HelpRegisterDerivedStrings(flimflam::kDevicesProperty,
102 &Manager::EnumerateDevices,
103 NULL);
Chris Masone88cbd5f2011-07-03 14:30:04 -0700104 HelpRegisterDerivedStrings(flimflam::kEnabledTechnologiesProperty,
105 &Manager::EnabledTechnologies,
106 NULL);
107 store_.RegisterBool(flimflam::kOfflineModeProperty, &props_.offline_mode);
108 store_.RegisterString(flimflam::kPortalURLProperty, &props_.portal_url);
Paul Stewartc681fa02012-03-02 19:40:04 -0800109 store_.RegisterInt32(kPortalCheckIntervalProperty,
110 &props_.portal_check_interval_seconds);
Paul Stewart1b253142012-01-26 14:05:52 -0800111 HelpRegisterDerivedStrings(flimflam::kProfilesProperty,
112 &Manager::EnumerateProfiles,
113 NULL);
Paul Stewartc681fa02012-03-02 19:40:04 -0800114 store_.RegisterString(kHostNameProperty, &props_.host_name);
Chris Masone88cbd5f2011-07-03 14:30:04 -0700115 HelpRegisterDerivedString(flimflam::kStateProperty,
116 &Manager::CalculateState,
117 NULL);
mukesh agrawal2366eed2012-03-20 18:21:50 -0700118 HelpRegisterConstDerivedRpcIdentifiers(flimflam::kServicesProperty,
119 &Manager::EnumerateAvailableServices);
Chris Masone27c4aa52011-07-02 13:10:14 -0700120 HelpRegisterDerivedStrings(flimflam::kServiceWatchListProperty,
121 &Manager::EnumerateWatchedServices,
122 NULL);
Chris Masone3c3f6a12011-07-01 10:01:41 -0700123
mukesh agrawal84de5d22012-02-17 19:29:15 -0800124 // Set default technology order "by hand", to avoid invoking side
125 // effects of SetTechnologyOrder.
126 technology_order_.push_back(
Darin Petkov2f903b32012-04-18 12:56:43 +0200127 Technology::IdentifierFromName(flimflam::kTypeVPN));
128 technology_order_.push_back(
mukesh agrawal84de5d22012-02-17 19:29:15 -0800129 Technology::IdentifierFromName(flimflam::kTypeEthernet));
130 technology_order_.push_back(
Darin Petkove08d9192012-05-21 12:21:15 +0200131 Technology::IdentifierFromName(flimflam::kTypeWimax));
132 technology_order_.push_back(
mukesh agrawal84de5d22012-02-17 19:29:15 -0800133 Technology::IdentifierFromName(flimflam::kTypeWifi));
134 technology_order_.push_back(
135 Technology::IdentifierFromName(flimflam::kTypeCellular));
136
Ben Chanfad4a0b2012-04-18 15:49:59 -0700137 SLOG(Manager, 2) << "Manager initialized.";
Paul Stewart75897df2011-04-27 09:05:53 -0700138}
139
Chris Masone6791a432011-07-12 13:23:19 -0700140Manager::~Manager() {
Chris Masone9d779932011-08-25 16:33:41 -0700141 profiles_.clear();
Chris Masone6791a432011-07-12 13:23:19 -0700142}
Paul Stewart75897df2011-04-27 09:05:53 -0700143
mukesh agrawal8f317b62011-07-15 11:53:23 -0700144void Manager::AddDeviceToBlackList(const string &device_name) {
145 device_info_.AddDeviceToBlackList(device_name);
146}
147
Paul Stewart75897df2011-04-27 09:05:53 -0700148void Manager::Start() {
Paul Stewart0af98bf2011-05-10 17:38:08 -0700149 LOG(INFO) << "Manager started.";
Paul Stewarte6132022011-08-16 09:11:02 -0700150
Gary Morainac1bdb42012-02-16 17:42:29 -0800151 power_manager_.reset(new PowerManager(ProxyFactory::GetInstance()));
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500152 // TODO(ers): weak ptr for metrics_?
153 PowerManager::PowerStateCallback cb =
154 Bind(&Metrics::NotifyPowerStateChange, Unretained(metrics_));
Thieu Leb84ba342012-03-02 15:15:19 -0800155 power_manager_->AddStateChangeCallback(Metrics::kMetricPowerManagerKey, cb);
156
Chris Masone2ae797d2011-08-23 20:41:00 -0700157 CHECK(file_util::CreateDirectory(run_path_)) << run_path_.value();
Paul Stewarte6132022011-08-16 09:11:02 -0700158 Resolver::GetInstance()->set_path(run_path_.Append("resolv.conf"));
Chris Masone2ae797d2011-08-23 20:41:00 -0700159
Gaurav Shah71354762011-11-28 19:22:49 -0800160 InitializeProfiles();
Paul Stewart75897df2011-04-27 09:05:53 -0700161 running_ = true;
Chris Masone413a3192011-05-09 17:10:05 -0700162 adaptor_->UpdateRunning();
Paul Stewart0af98bf2011-05-10 17:38:08 -0700163 device_info_.Start();
Darin Petkov887f2982011-07-14 16:10:17 -0700164 modem_info_.Start();
Darin Petkov33af05c2012-02-28 10:10:30 +0100165 vpn_provider_.Start();
Darin Petkov9893d9c2012-05-17 15:27:31 -0700166 wimax_provider_.Start();
Paul Stewart75897df2011-04-27 09:05:53 -0700167}
168
169void Manager::Stop() {
170 running_ = false;
Chris Masone9d779932011-08-25 16:33:41 -0700171 // Persist profile, device, service information to disk.
172 vector<ProfileRefPtr>::iterator it;
173 for (it = profiles_.begin(); it != profiles_.end(); ++it) {
Paul Stewartd0a3b812012-03-28 22:48:22 -0700174 // Since this happens in a loop, the current manager state is stored to
175 // all default profiles in the stack. This is acceptable because the
176 // only time multiple default profiles are loaded are during autotests.
Chris Masone6515aab2011-10-12 16:19:09 -0700177 (*it)->Save();
Chris Masone9d779932011-08-25 16:33:41 -0700178 }
Chris Masone9d779932011-08-25 16:33:41 -0700179
Thieu Le1271d682011-11-02 22:48:19 +0000180 vector<ServiceRefPtr>::iterator services_it;
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000181 Error e;
Thieu Le1271d682011-11-02 22:48:19 +0000182 for (services_it = services_.begin(); services_it != services_.end();
183 ++services_it) {
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000184 (*services_it)->Disconnect(&e);
Thieu Le1271d682011-11-02 22:48:19 +0000185 }
186
Chris Masone413a3192011-05-09 17:10:05 -0700187 adaptor_->UpdateRunning();
Darin Petkovb72b62e2012-05-15 16:55:36 +0200188 wimax_provider_.Stop();
Darin Petkov33af05c2012-02-28 10:10:30 +0100189 vpn_provider_.Stop();
Darin Petkov887f2982011-07-14 16:10:17 -0700190 modem_info_.Stop();
191 device_info_.Stop();
Thieu Leb84ba342012-03-02 15:15:19 -0800192
193 // Some unit tests do not call Manager::Start().
194 if (power_manager_.get())
195 power_manager_->RemoveStateChangeCallback(Metrics::kMetricPowerManagerKey);
Paul Stewart75897df2011-04-27 09:05:53 -0700196}
197
Gaurav Shah71354762011-11-28 19:22:49 -0800198void Manager::InitializeProfiles() {
199 DCHECK(profiles_.empty());
200 // The default profile must go first on the stack.
201 CHECK(file_util::CreateDirectory(storage_path_)) << storage_path_.value();
Paul Stewart870523b2012-01-11 17:00:42 -0800202 scoped_refptr<DefaultProfile>
203 default_profile(new DefaultProfile(control_interface_,
Gaurav Shah71354762011-11-28 19:22:49 -0800204 this,
205 storage_path_,
Paul Stewartd0a3b812012-03-28 22:48:22 -0700206 DefaultProfile::kDefaultId,
Gaurav Shah71354762011-11-28 19:22:49 -0800207 props_));
Paul Stewart870523b2012-01-11 17:00:42 -0800208 CHECK(default_profile->InitStorage(glib_, Profile::kCreateOrOpenExisting,
209 NULL));
210 CHECK(default_profile->LoadManagerProperties(&props_));
211 profiles_.push_back(default_profile.release());
Gaurav Shah71354762011-11-28 19:22:49 -0800212 Error error;
Paul Stewart19c871d2011-12-15 16:10:13 -0800213 string path;
Gaurav Shah71354762011-11-28 19:22:49 -0800214 for (vector<string>::iterator it = startup_profiles_.begin();
215 it != startup_profiles_.end(); ++it)
Paul Stewart19c871d2011-12-15 16:10:13 -0800216 PushProfile(*it, &path, &error);
Gaurav Shah71354762011-11-28 19:22:49 -0800217}
218
Paul Stewart19c871d2011-12-15 16:10:13 -0800219void Manager::CreateProfile(const string &name, string *path, Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700220 SLOG(Manager, 2) << __func__ << " " << name;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700221 Profile::Identifier ident;
222 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700223 Error::PopulateAndLog(error, Error::kInvalidArguments,
224 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700225 return;
226 }
Paul Stewartd0a3b812012-03-28 22:48:22 -0700227
228 ProfileRefPtr profile;
229 if (ident.user.empty()) {
230 profile = new DefaultProfile(control_interface_,
231 this,
232 storage_path_,
233 ident.identifier,
234 props_);
235 } else {
236 profile = new Profile(control_interface_,
237 this,
238 ident,
239 user_storage_format_,
Gary Morainb672d352012-04-25 09:19:06 -0700240 true);
Paul Stewartd0a3b812012-03-28 22:48:22 -0700241 }
242
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700243 if (!profile->InitStorage(glib_, Profile::kCreateNew, error)) {
Paul Stewart19c871d2011-12-15 16:10:13 -0800244 // |error| will have been populated by InitStorage().
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700245 return;
246 }
247
248 // Save profile data out, and then let the scoped pointer fall out of scope.
249 if (!profile->Save()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700250 Error::PopulateAndLog(error, Error::kInternalError,
251 "Profile name " + name + " could not be saved");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700252 return;
253 }
Paul Stewart19c871d2011-12-15 16:10:13 -0800254
255 *path = profile->GetRpcIdentifier();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700256}
257
Paul Stewart19c871d2011-12-15 16:10:13 -0800258void Manager::PushProfile(const string &name, string *path, Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700259 SLOG(Manager, 2) << __func__ << " " << name;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700260 Profile::Identifier ident;
261 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700262 Error::PopulateAndLog(error, Error::kInvalidArguments,
263 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700264 return;
265 }
266
267 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
268 it != profiles_.end();
269 ++it) {
270 if ((*it)->MatchesIdentifier(ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700271 Error::PopulateAndLog(error, Error::kAlreadyExists,
272 "Profile name " + name + " is already on stack");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700273 return;
274 }
275 }
276
Paul Stewartd0a3b812012-03-28 22:48:22 -0700277 ProfileRefPtr profile;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700278 if (ident.user.empty()) {
Paul Stewartd0a3b812012-03-28 22:48:22 -0700279 // Allow a machine-wide-profile to be pushed on the stack only if the
280 // profile stack is empty, or if the topmost profile on the stack is
281 // also a machine-wide (non-user) profile.
282 if (!profiles_.empty() && !profiles_.back()->GetUser().empty()) {
283 Error::PopulateAndLog(error, Error::kInvalidArguments,
284 "Cannot load non-default global profile " + name +
285 " on top of a user profile");
286 return;
287 }
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700288
Paul Stewartd0a3b812012-03-28 22:48:22 -0700289 scoped_refptr<DefaultProfile>
290 default_profile(new DefaultProfile(control_interface_,
291 this,
292 storage_path_,
293 ident.identifier,
294 props_));
295 if (!default_profile->InitStorage(glib_, Profile::kOpenExisting, error)) {
296 // |error| will have been populated by InitStorage().
297 return;
298 }
299
300 if (!default_profile->LoadManagerProperties(&props_)) {
301 Error::PopulateAndLog(error, Error::kInvalidArguments,
302 "Could not load Manager properties from profile " +
303 name);
304 return;
305 }
306 profile = default_profile;
307 } else {
308 profile = new Profile(control_interface_,
309 this,
310 ident,
311 user_storage_format_,
312 connect_profiles_to_rpc_);
313 if (!profile->InitStorage(glib_, Profile::kOpenExisting, error)) {
314 // |error| will have been populated by InitStorage().
315 return;
316 }
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700317 }
318
Paul Stewarta849a3d2011-11-03 05:54:09 -0700319 profiles_.push_back(profile);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700320
321 // Offer each registered Service the opportunity to join this new Profile.
Paul Stewarta41e38d2011-11-11 07:47:29 -0800322 for (vector<ServiceRefPtr>::iterator it = services_.begin();
323 it != services_.end(); ++it) {
Paul Stewartbba6a5b2011-11-02 18:45:59 -0700324 profile->ConfigureService(*it);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700325 }
326
Paul Stewarta41e38d2011-11-11 07:47:29 -0800327 // Shop the Profile contents around to Devices which can create
328 // non-visible services.
329 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
330 it != devices_.end(); ++it) {
331 profile->ConfigureDevice(*it);
332 }
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800333
Paul Stewart66815332012-04-09 18:09:36 -0700334 // Offer the Profile contents to the VPNProvider which will create
335 // new VPN services if necessary.
336 vpn_provider_.CreateServicesFromProfile(profile);
337
Paul Stewart19c871d2011-12-15 16:10:13 -0800338 *path = profile->GetRpcIdentifier();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800339 SortServices();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700340}
341
342void Manager::PopProfileInternal() {
343 CHECK(!profiles_.empty());
344 ProfileRefPtr active_profile = profiles_.back();
345 profiles_.pop_back();
Paul Stewart75225512012-01-26 22:51:33 -0800346 vector<ServiceRefPtr>::iterator it;
Paul Stewart65512e12012-03-26 18:01:08 -0700347 for (it = services_.begin(); it != services_.end();) {
348 if ((*it)->profile().get() != active_profile.get() ||
349 MatchProfileWithService(*it) ||
350 !UnloadService(&it)) {
351 LOG(ERROR) << "Skipping unload of service";
352 ++it;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700353 }
354 }
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800355 SortServices();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700356}
357
Paul Stewarta41e38d2011-11-11 07:47:29 -0800358void Manager::PopProfile(const string &name, Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700359 SLOG(Manager, 2) << __func__ << " " << name;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700360 Profile::Identifier ident;
361 if (profiles_.empty()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700362 Error::PopulateAndLog(error, Error::kNotFound, "Profile stack is empty");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700363 return;
364 }
365 ProfileRefPtr active_profile = profiles_.back();
366 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700367 Error::PopulateAndLog(error, Error::kInvalidArguments,
368 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700369 return;
370 }
371 if (!active_profile->MatchesIdentifier(ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700372 Error::PopulateAndLog(error, Error::kNotSupported,
373 name + " is not the active profile");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700374 return;
375 }
376 PopProfileInternal();
377}
378
379void Manager::PopAnyProfile(Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700380 SLOG(Manager, 2) << __func__;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700381 Profile::Identifier ident;
382 if (profiles_.empty()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700383 Error::PopulateAndLog(error, Error::kNotFound, "Profile stack is empty");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700384 return;
385 }
386 PopProfileInternal();
387}
388
Paul Stewarte73d05c2012-03-29 16:26:05 -0700389void Manager::RemoveProfile(const string &name, Error *error) {
390 Profile::Identifier ident;
391 if (!Profile::ParseIdentifier(name, &ident)) {
392 Error::PopulateAndLog(error, Error::kInvalidArguments,
393 "Invalid profile name " + name);
394 return;
395 }
396
397 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
398 it != profiles_.end();
399 ++it) {
400 if ((*it)->MatchesIdentifier(ident)) {
401 Error::PopulateAndLog(error, Error::kInvalidArguments,
402 "Cannot remove profile name " + name +
403 " since it is on stack");
404 return;
405 }
406 }
407
408 ProfileRefPtr profile;
409 if (ident.user.empty()) {
410 profile = new DefaultProfile(control_interface_,
411 this,
412 storage_path_,
413 ident.identifier,
414 props_);
415 } else {
416 profile = new Profile(control_interface_,
417 this,
418 ident,
419 user_storage_format_,
420 false);
421 }
422
423
424 // |error| will have been populated if RemoveStorage fails.
425 profile->RemoveStorage(glib_, error);
426
427 return;
428}
429
Paul Stewart75225512012-01-26 22:51:33 -0800430bool Manager::HandleProfileEntryDeletion(const ProfileRefPtr &profile,
431 const std::string &entry_name) {
432 bool moved_services = false;
433 for (vector<ServiceRefPtr>::iterator it = services_.begin();
Paul Stewart65512e12012-03-26 18:01:08 -0700434 it != services_.end();) {
Paul Stewart75225512012-01-26 22:51:33 -0800435 if ((*it)->profile().get() == profile.get() &&
436 (*it)->GetStorageIdentifier() == entry_name) {
437 profile->AbandonService(*it);
Paul Stewart65512e12012-03-26 18:01:08 -0700438 if (MatchProfileWithService(*it) ||
439 !UnloadService(&it)) {
440 ++it;
Paul Stewart75225512012-01-26 22:51:33 -0800441 }
442 moved_services = true;
Paul Stewart65512e12012-03-26 18:01:08 -0700443 } else {
444 ++it;
Paul Stewart75225512012-01-26 22:51:33 -0800445 }
446 }
447 return moved_services;
448}
449
Paul Stewart0756db92012-01-27 08:34:47 -0800450ServiceRefPtr Manager::GetServiceWithStorageIdentifier(
451 const ProfileRefPtr &profile, const std::string &entry_name, Error *error) {
452 for (vector<ServiceRefPtr>::iterator it = services_.begin();
453 it != services_.end(); ++it) {
454 if ((*it)->profile().get() == profile.get() &&
455 (*it)->GetStorageIdentifier() == entry_name) {
456 return *it;
457 }
458 }
459
460 Error::PopulateAndLog(error, Error::kNotFound,
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500461 StringPrintf("Entry %s is not registered in the manager",
462 entry_name.c_str()));
Paul Stewart0756db92012-01-27 08:34:47 -0800463 return NULL;
464}
465
Paul Stewart13ed2252012-03-21 12:52:46 -0700466ServiceRefPtr Manager::GetServiceWithGUID(
467 const std::string &guid, Error *error) {
468 for (vector<ServiceRefPtr>::iterator it = services_.begin();
469 it != services_.end(); ++it) {
470 if ((*it)->guid() == guid) {
471 return *it;
472 }
473 }
474
475 Error::PopulateAndLog(error, Error::kNotFound,
476 StringPrintf("Service wth GUID %s is not registered in the manager",
477 guid.c_str()));
478 return NULL;
479}
480
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700481ServiceRefPtr Manager::GetDefaultService() const {
482 if (services_.empty() || !services_[0]->connection().get()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700483 SLOG(Manager, 2) << "In " << __func__ << ": No default connection exists.";
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700484 return NULL;
485 }
486 return services_[0];
487}
488
Paul Stewart20088d82012-02-16 06:58:55 -0800489bool Manager::IsPortalDetectionEnabled(Technology::Identifier tech) {
490 Error error;
491 vector<Technology::Identifier> portal_technologies;
Paul Stewart10e9e4e2012-04-26 19:46:28 -0700492 return Technology::GetTechnologyVectorFromString(GetCheckPortalList(NULL),
Paul Stewart20088d82012-02-16 06:58:55 -0800493 &portal_technologies,
494 &error) &&
495 std::find(portal_technologies.begin(), portal_technologies.end(),
496 tech) != portal_technologies.end();
497}
498
Paul Stewart10e9e4e2012-04-26 19:46:28 -0700499void Manager::SetStartupPortalList(const string &portal_list) {
500 startup_portal_list_ = portal_list;
501 use_startup_portal_list_ = true;
502}
503
Paul Stewart10ccbb32012-04-26 15:59:30 -0700504bool Manager::IsServiceEphemeral(const ServiceConstRefPtr &service) const {
505 return service->profile() == ephemeral_profile_;
506}
507
Paul Stewart1b253142012-01-26 14:05:52 -0800508const ProfileRefPtr &Manager::ActiveProfile() const {
Eric Shienbroodc74cf9c2012-03-02 15:00:35 -0500509 DCHECK_NE(profiles_.size(), 0U);
Chris Masone7aa5f902011-07-11 11:13:35 -0700510 return profiles_.back();
511}
512
Paul Stewart1b253142012-01-26 14:05:52 -0800513bool Manager::IsActiveProfile(const ProfileRefPtr &profile) const {
514 return (profiles_.size() > 0 &&
515 ActiveProfile().get() == profile.get());
516}
517
Eric Shienbrood9a245532012-03-07 14:20:39 -0500518void Manager::SaveActiveProfile() {
519 if (!profiles_.empty()) {
520 ActiveProfile()->Save();
521 }
522}
523
Chris Masone6515aab2011-10-12 16:19:09 -0700524bool Manager::MoveServiceToProfile(const ServiceRefPtr &to_move,
525 const ProfileRefPtr &destination) {
526 const ProfileRefPtr from = to_move->profile();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700527 SLOG(Manager, 2) << "Moving service "
528 << to_move->UniqueName()
529 << " to profile "
530 << destination->GetFriendlyName()
531 << " from "
532 << from->GetFriendlyName();
Chris Masone6515aab2011-10-12 16:19:09 -0700533 return destination->AdoptService(to_move) &&
534 from->AbandonService(to_move);
Chris Masone6791a432011-07-12 13:23:19 -0700535}
536
Paul Stewart7f61e522012-03-22 11:13:45 -0700537ProfileRefPtr Manager::LookupProfileByRpcIdentifier(
538 const string &profile_rpcid) {
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800539 for (vector<ProfileRefPtr>::iterator it = profiles_.begin();
540 it != profiles_.end();
541 ++it) {
542 if (profile_rpcid == (*it)->GetRpcIdentifier()) {
Paul Stewart7f61e522012-03-22 11:13:45 -0700543 return *it;
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800544 }
545 }
Paul Stewart7f61e522012-03-22 11:13:45 -0700546 return NULL;
547}
548
549void Manager::SetProfileForService(const ServiceRefPtr &to_set,
550 const string &profile_rpcid,
551 Error *error) {
552 ProfileRefPtr profile = LookupProfileByRpcIdentifier(profile_rpcid);
553 if (!profile) {
554 Error::PopulateAndLog(error, Error::kInvalidArguments,
555 StringPrintf("Unknown Profile %s requested for "
556 "Service", profile_rpcid.c_str()));
557 return;
558 }
559
560 if (to_set->profile().get() == profile.get()) {
561 Error::PopulateAndLog(error, Error::kInvalidArguments,
562 "Service is already connected to this profile");
563 } else if (!MoveServiceToProfile(to_set, profile)) {
564 Error::PopulateAndLog(error, Error::kInternalError,
565 "Unable to move service to profile");
566 }
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800567}
568
Eric Shienbrood9a245532012-03-07 14:20:39 -0500569void Manager::EnableTechnology(const std::string &technology_name,
570 Error *error,
571 const ResultCallback &callback) {
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400572 CHECK(error != NULL);
573 DCHECK(error->IsOngoing());
Eric Shienbrood9a245532012-03-07 14:20:39 -0500574 Technology::Identifier id = Technology::IdentifierFromName(technology_name);
575 if (id == Technology::kUnknown) {
576 error->Populate(Error::kInvalidArguments, "Unknown technology");
577 return;
578 }
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400579 bool deferred = false;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500580 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
581 it != devices_.end(); ++it) {
582 DeviceRefPtr device = *it;
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400583 if (device->TechnologyIs(id) && !device->enabled()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500584 device->SetEnabledPersistent(true, error, callback);
585 // Continue with other devices even if one fails
586 // TODO(ers): Decide whether an error should be returned
587 // for the overall EnableTechnology operation if some
588 // devices succeed and some fail.
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400589 if (error->IsOngoing())
590 deferred = true;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500591 }
592 }
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400593 // If no device has deferred work, then clear the error to
594 // communicate to the caller that all work is done.
595 if (!deferred)
596 error->Reset();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500597}
598
599void Manager::DisableTechnology(const std::string &technology_name,
600 Error *error,
601 const ResultCallback &callback) {
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400602 CHECK(error != NULL);
603 DCHECK(error->IsOngoing());
Eric Shienbrood9a245532012-03-07 14:20:39 -0500604 Technology::Identifier id = Technology::IdentifierFromName(technology_name);
605 if (id == Technology::kUnknown) {
606 error->Populate(Error::kInvalidArguments, "Unknown technology");
607 return;
608 }
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400609 bool deferred = false;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500610 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
611 it != devices_.end(); ++it) {
612 DeviceRefPtr device = *it;
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400613 if (device->TechnologyIs(id) && device->enabled()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500614 device->SetEnabledPersistent(false, error, callback);
615 // Continue with other devices even if one fails
616 // TODO(ers): Decide whether an error should be returned
617 // for the overall DisableTechnology operation if some
618 // devices succeed and some fail.
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400619 if (error->IsOngoing())
620 deferred = true;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500621 }
622 }
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400623 // If no device has deferred work, then clear the error to
624 // communicate to the caller that all work is done.
625 if (!deferred)
626 error->Reset();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500627}
628
629void Manager::UpdateEnabledTechnologies() {
630 Error error;
631 adaptor_->EmitStringsChanged(flimflam::kEnabledTechnologiesProperty,
632 EnabledTechnologies(&error));
633}
634
Chris Masone2b105542011-06-22 10:58:09 -0700635void Manager::RegisterDevice(const DeviceRefPtr &to_manage) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700636 SLOG(Manager, 2) << __func__ << "(" << to_manage->FriendlyName() << ")";
Chris Masonec1e50412011-06-07 13:04:53 -0700637 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700638 for (it = devices_.begin(); it != devices_.end(); ++it) {
Chris Masonec1e50412011-06-07 13:04:53 -0700639 if (to_manage.get() == it->get())
Chris Masone9be4a9d2011-05-16 15:44:09 -0700640 return;
641 }
Chris Masonec1e50412011-06-07 13:04:53 -0700642 devices_.push_back(to_manage);
Paul Stewartf1ce5d22011-05-19 13:10:20 -0700643
Paul Stewarta41e38d2011-11-11 07:47:29 -0800644 // We are applying device properties from the DefaultProfile, and adding
645 // the union of hidden services in all loaded profiles to the device.
Chris Masone6515aab2011-10-12 16:19:09 -0700646 for (vector<ProfileRefPtr>::iterator it = profiles_.begin();
647 it != profiles_.end();
648 ++it) {
Paul Stewarta41e38d2011-11-11 07:47:29 -0800649 // Load device configuration, if any exists, as well as hidden services.
650 (*it)->ConfigureDevice(to_manage);
651
652 // Currently the only profile for which "Save" is implemented is the
653 // DefaultProfile. It iterates over all Devices and stores their state.
654 // We perform the Save now in case the device we have just registered
655 // is new and needs to be added to the stored DefaultProfile.
Chris Masone6515aab2011-10-12 16:19:09 -0700656 (*it)->Save();
657 }
Paul Stewarta41e38d2011-11-11 07:47:29 -0800658
659 // In normal usage, running_ will always be true when we are here, however
660 // unit tests sometimes do things in otherwise invalid states.
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400661 if (running_ && (to_manage->enabled_persistent() ||
662 to_manage->IsUnderlyingDeviceEnabled()))
Eric Shienbrood9a245532012-03-07 14:20:39 -0500663 to_manage->SetEnabled(true);
Gaurav Shah435de2c2011-11-17 19:01:07 -0800664
Eric Shienbrood8839a892012-03-29 10:33:48 -0400665 EmitDeviceProperties();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700666}
667
mukesh agrawal5029c6c2011-08-25 11:12:40 -0700668void Manager::DeregisterDevice(const DeviceRefPtr &to_forget) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700669 SLOG(Manager, 2) << __func__ << "(" << to_forget->FriendlyName() << ")";
Chris Masonec1e50412011-06-07 13:04:53 -0700670 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700671 for (it = devices_.begin(); it != devices_.end(); ++it) {
Chris Masonec1e50412011-06-07 13:04:53 -0700672 if (to_forget.get() == it->get()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700673 SLOG(Manager, 2) << "Deregistered device: " << to_forget->UniqueName();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500674 to_forget->SetEnabled(false);
Chris Masone9be4a9d2011-05-16 15:44:09 -0700675 devices_.erase(it);
Eric Shienbrood8839a892012-03-29 10:33:48 -0400676 EmitDeviceProperties();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700677 return;
678 }
679 }
Ben Chanfad4a0b2012-04-18 15:49:59 -0700680 SLOG(Manager, 2) << __func__ << " unknown device: "
681 << to_forget->UniqueName();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700682}
683
Eric Shienbrood8839a892012-03-29 10:33:48 -0400684void Manager::EmitDeviceProperties() {
685 vector<DeviceRefPtr>::iterator it;
686 vector<string> device_paths;
687 for (it = devices_.begin(); it != devices_.end(); ++it) {
688 device_paths.push_back((*it)->GetRpcIdentifier());
689 }
690 adaptor_->EmitRpcIdentifierArrayChanged(flimflam::kDevicesProperty,
691 device_paths);
692 Error error;
693 adaptor_->EmitStringsChanged(flimflam::kAvailableTechnologiesProperty,
694 AvailableTechnologies(&error));
695 adaptor_->EmitStringsChanged(flimflam::kEnabledTechnologiesProperty,
696 EnabledTechnologies(&error));
697}
698
mukesh agrawal4eb4d782011-12-05 17:34:37 +0000699bool Manager::HasService(const ServiceRefPtr &service) {
700 vector<ServiceRefPtr>::iterator it;
701 for (it = services_.begin(); it != services_.end(); ++it) {
702 if ((*it)->UniqueName() == service->UniqueName())
703 return true;
704 }
705 return false;
706}
707
Chris Masone2b105542011-06-22 10:58:09 -0700708void Manager::RegisterService(const ServiceRefPtr &to_manage) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700709 SLOG(Manager, 2) << "In " << __func__ << "(): Registering service "
710 << to_manage->UniqueName();
mukesh agrawald835b202011-10-07 15:26:47 -0700711
Paul Stewart75225512012-01-26 22:51:33 -0800712 MatchProfileWithService(to_manage);
Chris Masone6791a432011-07-12 13:23:19 -0700713
714 // Now add to OUR list.
Chris Masonec1e50412011-06-07 13:04:53 -0700715 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700716 for (it = services_.begin(); it != services_.end(); ++it) {
mukesh agrawald835b202011-10-07 15:26:47 -0700717 CHECK(to_manage->UniqueName() != (*it)->UniqueName());
Chris Masone9be4a9d2011-05-16 15:44:09 -0700718 }
Chris Masonec1e50412011-06-07 13:04:53 -0700719 services_.push_back(to_manage);
Paul Stewart22aa71b2011-09-16 12:15:11 -0700720 SortServices();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700721}
722
Chris Masone6515aab2011-10-12 16:19:09 -0700723void Manager::DeregisterService(const ServiceRefPtr &to_forget) {
Chris Masonec1e50412011-06-07 13:04:53 -0700724 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700725 for (it = services_.begin(); it != services_.end(); ++it) {
Chris Masone6791a432011-07-12 13:23:19 -0700726 if (to_forget->UniqueName() == (*it)->UniqueName()) {
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800727 DCHECK(!(*it)->connection());
Chris Masone9be4a9d2011-05-16 15:44:09 -0700728 services_.erase(it);
Paul Stewart22aa71b2011-09-16 12:15:11 -0700729 SortServices();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700730 return;
731 }
732 }
733}
734
Paul Stewart65512e12012-03-26 18:01:08 -0700735bool Manager::UnloadService(vector<ServiceRefPtr>::iterator *service_iterator) {
736 if (!(**service_iterator)->Unload()) {
737 return false;
738 }
739
740 DCHECK(!(**service_iterator)->connection());
741 *service_iterator = services_.erase(*service_iterator);
742
743 return true;
744}
745
mukesh agrawal00917ce2011-11-22 23:56:55 +0000746void Manager::UpdateService(const ServiceRefPtr &to_update) {
747 CHECK(to_update);
Paul Stewart03dba0b2011-08-22 16:32:45 -0700748 LOG(INFO) << "Service " << to_update->UniqueName() << " updated;"
Gaurav Shahc6d6c722011-11-17 18:59:39 -0800749 << " state: " << Service::ConnectStateToString(to_update->state())
750 << " failure: "
751 << Service::ConnectFailureToString(to_update->failure());
Ben Chanfad4a0b2012-04-18 15:49:59 -0700752 SLOG(Manager, 2) << "IsConnected(): " << to_update->IsConnected();
753 SLOG(Manager, 2) << "IsConnecting(): " << to_update->IsConnecting();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800754 if (to_update->IsConnected()) {
mukesh agrawal00917ce2011-11-22 23:56:55 +0000755 to_update->MakeFavorite();
Gary Moraind93615e2012-04-27 11:50:03 -0700756 // Persists the updated favorite setting in the profile.
757 SaveServiceToProfile(to_update);
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800758 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700759 SortServices();
Paul Stewart03dba0b2011-08-22 16:32:45 -0700760}
761
Gary Moraind93615e2012-04-27 11:50:03 -0700762void Manager::SaveServiceToProfile(const ServiceRefPtr &to_update) {
763 if (IsServiceEphemeral(to_update)) {
764 if (profiles_.empty()) {
765 LOG(ERROR) << "Cannot assign profile to service: no profiles exist!";
766 } else {
767 MoveServiceToProfile(to_update, profiles_.back());
768 }
769 } else {
770 to_update->profile()->UpdateService(to_update);
771 }
772}
773
Paul Stewartfdd16072011-09-16 12:41:35 -0700774void Manager::FilterByTechnology(Technology::Identifier tech,
Chris Masonec1e50412011-06-07 13:04:53 -0700775 vector<DeviceRefPtr> *found) {
Chris Masone9be4a9d2011-05-16 15:44:09 -0700776 CHECK(found);
Chris Masonec1e50412011-06-07 13:04:53 -0700777 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700778 for (it = devices_.begin(); it != devices_.end(); ++it) {
779 if ((*it)->TechnologyIs(tech))
780 found->push_back(*it);
781 }
782}
783
Paul Stewart22aa71b2011-09-16 12:15:11 -0700784ServiceRefPtr Manager::FindService(const string& name) {
Chris Masonec1e50412011-06-07 13:04:53 -0700785 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700786 for (it = services_.begin(); it != services_.end(); ++it) {
Chris Masone6791a432011-07-12 13:23:19 -0700787 if (name == (*it)->UniqueName())
Chris Masonee0dea762011-06-09 09:06:03 -0700788 return *it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700789 }
Chris Masonee0dea762011-06-09 09:06:03 -0700790 return NULL;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700791}
792
mukesh agrawal2366eed2012-03-20 18:21:50 -0700793void Manager::HelpRegisterConstDerivedRpcIdentifiers(
794 const string &name,
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400795 RpcIdentifiers(Manager::*get)(Error *error)) {
mukesh agrawal2366eed2012-03-20 18:21:50 -0700796 store_.RegisterDerivedRpcIdentifiers(
797 name,
798 RpcIdentifiersAccessor(
799 new CustomAccessor<Manager, RpcIdentifiers>(this, get, NULL)));
800}
801
mukesh agrawalffa3d042011-10-06 15:26:10 -0700802void Manager::HelpRegisterDerivedString(
803 const string &name,
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800804 string(Manager::*get)(Error *),
mukesh agrawalffa3d042011-10-06 15:26:10 -0700805 void(Manager::*set)(const string&, Error *)) {
Chris Masone27c4aa52011-07-02 13:10:14 -0700806 store_.RegisterDerivedString(
807 name,
808 StringAccessor(new CustomAccessor<Manager, string>(this, get, set)));
Chris Masoneb925cc82011-06-22 15:39:57 -0700809}
810
mukesh agrawalffa3d042011-10-06 15:26:10 -0700811void Manager::HelpRegisterDerivedStrings(
812 const string &name,
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800813 Strings(Manager::*get)(Error *),
mukesh agrawalffa3d042011-10-06 15:26:10 -0700814 void(Manager::*set)(const Strings &, Error *)) {
Chris Masone27c4aa52011-07-02 13:10:14 -0700815 store_.RegisterDerivedStrings(
816 name,
817 StringsAccessor(new CustomAccessor<Manager, Strings>(this, get, set)));
Chris Masoneb925cc82011-06-22 15:39:57 -0700818}
819
Paul Stewart22aa71b2011-09-16 12:15:11 -0700820void Manager::SortServices() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700821 SLOG(Manager, 4) << "In " << __func__;
Thieu Lea20cbc22012-01-09 22:01:43 +0000822 ServiceRefPtr default_service;
823
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800824 if (!services_.empty()) {
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700825 // Keep track of the service that is the candidate for the default
826 // service. We have not yet tested to see if this service has a
827 // connection.
Thieu Lea20cbc22012-01-09 22:01:43 +0000828 default_service = services_[0];
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800829 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700830 sort(services_.begin(), services_.end(), ServiceSorter(technology_order_));
Paul Stewarta41e38d2011-11-11 07:47:29 -0800831
832 vector<string> service_paths;
833 vector<ServiceRefPtr>::iterator it;
834 for (it = services_.begin(); it != services_.end(); ++it) {
835 if ((*it)->IsVisible()) {
836 service_paths.push_back((*it)->GetRpcIdentifier());
837 }
838 }
839 adaptor_->EmitRpcIdentifierArrayChanged(flimflam::kServicesProperty,
840 service_paths);
Gaurav Shah435de2c2011-11-17 19:01:07 -0800841
842 Error error;
843 adaptor_->EmitStringsChanged(flimflam::kConnectedTechnologiesProperty,
844 ConnectedTechnologies(&error));
845 adaptor_->EmitStringChanged(flimflam::kDefaultTechnologyProperty,
846 DefaultTechnology(&error));
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800847
848 if (!services_.empty()) {
Thieu Lea20cbc22012-01-09 22:01:43 +0000849 ConnectionRefPtr default_connection = default_service->connection();
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800850 if (default_connection.get() &&
851 (services_[0]->connection().get() != default_connection.get())) {
852 default_connection->SetIsDefault(false);
853 }
854 if (services_[0]->connection().get()) {
855 services_[0]->connection()->SetIsDefault(true);
Thieu Lea20cbc22012-01-09 22:01:43 +0000856 default_service = services_[0];
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700857 } else {
858 default_service = NULL;
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800859 }
860 }
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700861 metrics_->NotifyDefaultServiceChanged(default_service);
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800862
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000863 AutoConnect();
864}
865
Paul Stewart75225512012-01-26 22:51:33 -0800866bool Manager::MatchProfileWithService(const ServiceRefPtr &service) {
867 vector<ProfileRefPtr>::reverse_iterator it;
868 for (it = profiles_.rbegin(); it != profiles_.rend(); ++it) {
869 if ((*it)->ConfigureService(service)) {
870 break;
871 }
872 }
873 if (it == profiles_.rend()) {
874 ephemeral_profile_->AdoptService(service);
875 return false;
876 }
877 return true;
878}
879
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000880void Manager::AutoConnect() {
881 // We might be called in the middle of another request (e.g., as a
882 // consequence of Service::SetState calling UpdateService). To avoid
883 // re-entrancy issues in dbus-c++, defer to the event loop.
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500884 dispatcher_->PostTask(Bind(&Manager::AutoConnectTask, AsWeakPtr()));
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000885}
886
887void Manager::AutoConnectTask() {
888 if (services_.empty()) {
889 LOG(INFO) << "No services.";
890 return;
891 }
892
Ben Chanfad4a0b2012-04-18 15:49:59 -0700893 if (SLOG_IS_ON(Manager, 4)) {
894 SLOG(Manager, 4) << "Sorted service list: ";
mukesh agrawalddc378f2012-02-17 18:26:20 -0800895 for (size_t i = 0; i < services_.size(); ++i) {
896 ServiceRefPtr service = services_[i];
897 const char *compare_reason = NULL;
898 if (i + 1 < services_.size()) {
899 Service::Compare(
900 service, services_[i+1], technology_order_, &compare_reason);
901 } else {
mukesh agrawalbf14e942012-03-02 14:36:34 -0800902 compare_reason = "last";
mukesh agrawalddc378f2012-02-17 18:26:20 -0800903 }
Ben Chanfad4a0b2012-04-18 15:49:59 -0700904 SLOG(Manager, 4) << "Service " << service->friendly_name()
905 << " IsConnected: " << service->IsConnected()
906 << " IsConnecting: " << service->IsConnecting()
907 << " IsFailed: " << service->IsFailed()
908 << " connectable: " << service->connectable()
909 << " auto_connect: " << service->auto_connect()
910 << " favorite: " << service->favorite()
911 << " priority: " << service->priority()
912 << " security_level: " << service->security_level()
913 << " strength: " << service->strength()
914 << " UniqueName: " << service->UniqueName()
915 << " sorted: " << compare_reason;
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000916 }
917 }
918
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800919 // Perform auto-connect.
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000920 for (vector<ServiceRefPtr>::iterator it = services_.begin();
921 it != services_.end(); ++it) {
922 if ((*it)->auto_connect()) {
mukesh agrawal592516d2012-01-12 14:01:00 -0800923 LOG(INFO) << "Requesting autoconnect to service "
924 << (*it)->friendly_name() << ".";
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000925 (*it)->AutoConnect();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800926 }
927 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700928}
929
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800930string Manager::CalculateState(Error */*error*/) {
Gary Morain028545d2012-04-07 14:55:52 -0700931 // |services_| is sorted such that connected services are first.
932 if (!services_.empty() &&
933 services_.front()->IsConnected()) {
934 return flimflam::kStateOnline;
935 }
Chris Masoneb925cc82011-06-22 15:39:57 -0700936 return flimflam::kStateOffline;
937}
938
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800939vector<string> Manager::AvailableTechnologies(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -0800940 set<string> unique_technologies;
941 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
942 it != devices_.end(); ++it) {
943 unique_technologies.insert(
944 Technology::NameFromIdentifier((*it)->technology()));
945 }
946 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -0700947}
948
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800949vector<string> Manager::ConnectedTechnologies(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -0800950 set<string> unique_technologies;
951 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
952 it != devices_.end(); ++it) {
953 if ((*it)->IsConnected())
954 unique_technologies.insert(
955 Technology::NameFromIdentifier((*it)->technology()));
956 }
957 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -0700958}
959
Gaurav Shah435de2c2011-11-17 19:01:07 -0800960string Manager::DefaultTechnology(Error *error) {
961 return (!services_.empty() && services_[0]->IsConnected()) ?
962 services_[0]->GetTechnologyString(error) : "";
Chris Masoneb925cc82011-06-22 15:39:57 -0700963}
964
Eric Shienbrood9a245532012-03-07 14:20:39 -0500965vector<string> Manager::EnabledTechnologies(Error */*error*/) {
966 set<string> unique_technologies;
967 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
968 it != devices_.end(); ++it) {
969 if ((*it)->enabled())
970 unique_technologies.insert(
971 Technology::NameFromIdentifier((*it)->technology()));
972 }
973 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -0700974}
975
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800976vector<string> Manager::EnumerateDevices(Error */*error*/) {
Chris Masone3c3f6a12011-07-01 10:01:41 -0700977 vector<string> device_rpc_ids;
978 for (vector<DeviceRefPtr>::const_iterator it = devices_.begin();
979 it != devices_.end();
980 ++it) {
981 device_rpc_ids.push_back((*it)->GetRpcIdentifier());
982 }
983 return device_rpc_ids;
984}
985
Paul Stewart1b253142012-01-26 14:05:52 -0800986vector<string> Manager::EnumerateProfiles(Error */*error*/) {
987 vector<string> profile_rpc_ids;
988 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
989 it != profiles_.end();
990 ++it) {
991 profile_rpc_ids.push_back((*it)->GetRpcIdentifier());
992 }
993 return profile_rpc_ids;
994}
995
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800996vector<string> Manager::EnumerateAvailableServices(Error */*error*/) {
Chris Masone3c3f6a12011-07-01 10:01:41 -0700997 vector<string> service_rpc_ids;
998 for (vector<ServiceRefPtr>::const_iterator it = services_.begin();
999 it != services_.end();
1000 ++it) {
1001 service_rpc_ids.push_back((*it)->GetRpcIdentifier());
1002 }
1003 return service_rpc_ids;
1004}
1005
Gaurav Shah1b7a6162011-11-09 11:41:01 -08001006vector<string> Manager::EnumerateWatchedServices(Error *error) {
Chris Masone6791a432011-07-12 13:23:19 -07001007 // TODO(cmasone): Filter this list for services in appropriate states.
Gaurav Shah1b7a6162011-11-09 11:41:01 -08001008 return EnumerateAvailableServices(error);
Chris Masone3c3f6a12011-07-01 10:01:41 -07001009}
1010
Paul Stewart1b253142012-01-26 14:05:52 -08001011string Manager::GetActiveProfileRpcIdentifier(Error */*error*/) {
1012 return ActiveProfile()->GetRpcIdentifier();
Chris Masone7aa5f902011-07-11 11:13:35 -07001013}
1014
Paul Stewart10e9e4e2012-04-26 19:46:28 -07001015string Manager::GetCheckPortalList(Error */*error*/) {
Jason Glasgowdf7c5532012-05-14 14:41:45 -04001016 return use_startup_portal_list_ ? startup_portal_list_ :
1017 props_.check_portal_list;
Paul Stewart10e9e4e2012-04-26 19:46:28 -07001018}
1019
1020void Manager::SetCheckPortalList(const string &portal_list, Error *error) {
1021 props_.check_portal_list = portal_list;
1022 use_startup_portal_list_ = false;
1023}
1024
mukesh agrawal32399322011-09-01 10:53:43 -07001025// called via RPC (e.g., from ManagerDBusAdaptor)
Darin Petkovb65c2452012-02-23 15:17:06 +01001026ServiceRefPtr Manager::GetService(const KeyValueStore &args, Error *error) {
Paul Stewart13ed2252012-03-21 12:52:46 -07001027 if (args.ContainsString(flimflam::kGuidProperty)) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001028 SLOG(Manager, 2) << __func__ << ": searching by GUID";
Paul Stewart13ed2252012-03-21 12:52:46 -07001029 ServiceRefPtr service =
1030 GetServiceWithGUID(args.GetString(flimflam::kGuidProperty), NULL);
1031 if (service) {
Paul Stewartcb59fed2012-03-21 21:14:46 -07001032 service->Configure(args, error);
Paul Stewart13ed2252012-03-21 12:52:46 -07001033 return service;
1034 }
1035 }
1036
Darin Petkovb65c2452012-02-23 15:17:06 +01001037 if (!args.ContainsString(flimflam::kTypeProperty)) {
Paul Stewart7f61e522012-03-22 11:13:45 -07001038 Error::PopulateAndLog(error, Error::kInvalidArguments, kErrorTypeRequired);
Darin Petkovb65c2452012-02-23 15:17:06 +01001039 return NULL;
1040 }
1041
1042 string type = args.GetString(flimflam::kTypeProperty);
1043 if (type == flimflam::kTypeWifi) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001044 SLOG(Manager, 2) << __func__ << ": getting WiFi Service";
Darin Petkovb65c2452012-02-23 15:17:06 +01001045 return GetWifiService(args, error);
1046 }
1047 if (type == flimflam::kTypeVPN) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001048 SLOG(Manager, 2) << __func__ << ": getting VPN Service";
Darin Petkov33af05c2012-02-28 10:10:30 +01001049 return vpn_provider_.GetService(args, error);
Darin Petkovb65c2452012-02-23 15:17:06 +01001050 }
mukesh agrawal06175d72012-04-23 16:46:01 -07001051 Error::PopulateAndLog(error, Error::kNotSupported,
1052 kErrorUnsupportedServiceType);
Darin Petkovb65c2452012-02-23 15:17:06 +01001053 return NULL;
1054}
1055
mukesh agrawal7a4e4002011-09-06 11:26:05 -07001056WiFiServiceRefPtr Manager::GetWifiService(const KeyValueStore &args,
1057 Error *error) {
Paul Stewarta41e38d2011-11-11 07:47:29 -08001058 vector<DeviceRefPtr> wifi_devices;
Paul Stewart22aa71b2011-09-16 12:15:11 -07001059 FilterByTechnology(Technology::kWifi, &wifi_devices);
mukesh agrawal7a4e4002011-09-06 11:26:05 -07001060 if (wifi_devices.empty()) {
mukesh agrawal06175d72012-04-23 16:46:01 -07001061 Error::PopulateAndLog(error, Error::kInvalidArguments, kErrorNoDevice);
mukesh agrawal7a4e4002011-09-06 11:26:05 -07001062 return NULL;
1063 } else {
1064 WiFi *wifi = dynamic_cast<WiFi *>(wifi_devices.front().get());
1065 CHECK(wifi);
1066 return wifi->GetService(args, error);
1067 }
1068}
1069
Paul Stewart7f61e522012-03-22 11:13:45 -07001070// called via RPC (e.g., from ManagerDBusAdaptor)
1071void Manager::ConfigureService(const KeyValueStore &args, Error *error) {
1072 ProfileRefPtr profile = ActiveProfile();
1073 bool profile_specified = args.ContainsString(flimflam::kProfileProperty);
1074 if (profile_specified) {
1075 string profile_rpcid = args.GetString(flimflam::kProfileProperty);
1076 profile = LookupProfileByRpcIdentifier(profile_rpcid);
1077 if (!profile) {
1078 Error::PopulateAndLog(error, Error::kInvalidArguments,
1079 "Invalid profile name " + profile_rpcid);
1080 return;
1081 }
1082 }
1083
1084 ServiceRefPtr service = GetService(args, error);
1085 if (error->IsFailure() || !service) {
1086 LOG(ERROR) << "GetService failed; returning upstream error.";
1087 return;
1088 }
1089
mukesh agrawal06175d72012-04-23 16:46:01 -07001090 // Overwrite the profile data with the resulting configured service.
Paul Stewart7f61e522012-03-22 11:13:45 -07001091 if (!profile->UpdateService(service)) {
1092 Error::PopulateAndLog(error, Error::kInternalError,
1093 "Unable to save service to profile");
1094 return;
1095 }
1096
1097 if (HasService(service)) {
1098 // If the service has been registered (it may not be -- as is the case
1099 // with invisible WiFi networks), we can now transfer the service between
1100 // profiles.
Paul Stewart10ccbb32012-04-26 15:59:30 -07001101 if (IsServiceEphemeral(service) ||
Paul Stewart7f61e522012-03-22 11:13:45 -07001102 (profile_specified && service->profile() != profile)) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001103 SLOG(Manager, 2) << "Moving service to profile "
1104 << profile->GetFriendlyName();
Paul Stewart7f61e522012-03-22 11:13:45 -07001105 if (!MoveServiceToProfile(service, profile)) {
1106 Error::PopulateAndLog(error, Error::kInternalError,
1107 "Unable to move service to profile");
1108 }
1109 }
1110 }
Paul Stewart4357f4e2012-04-26 17:39:26 -07001111
1112 // Notify the service that a profile has been configured for it.
1113 service->OnProfileConfigured();
Paul Stewart7f61e522012-03-22 11:13:45 -07001114}
1115
Paul Stewartc681fa02012-03-02 19:40:04 -08001116void Manager::RecheckPortal(Error */*error*/) {
1117 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1118 it != devices_.end(); ++it) {
1119 if ((*it)->RequestPortalDetection()) {
1120 // Only start Portal Detection on the device with the default connection.
1121 // We will get a "true" return value when we've found that device, and
1122 // can end our loop early as a result.
1123 break;
1124 }
1125 }
1126}
1127
Paul Stewartd215af62012-04-24 23:25:50 -07001128void Manager::RecheckPortalOnService(const ServiceRefPtr &service) {
1129 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1130 it != devices_.end(); ++it) {
1131 if ((*it)->IsConnectedToService(service)) {
1132 // As opposed to RecheckPortal() above, we explicitly stop and then
1133 // restart portal detection, since the service to recheck was explicitly
1134 // specified.
1135 (*it)->RestartPortalDetection();
1136 break;
1137 }
1138 }
1139}
1140
mukesh agrawal7a4e4002011-09-06 11:26:05 -07001141// called via RPC (e.g., from ManagerDBusAdaptor)
Paul Stewart22aa71b2011-09-16 12:15:11 -07001142void Manager::RequestScan(const string &technology, Error *error) {
mukesh agrawal32399322011-09-01 10:53:43 -07001143 if (technology == flimflam::kTypeWifi || technology == "") {
1144 vector<DeviceRefPtr> wifi_devices;
Paul Stewartfdd16072011-09-16 12:41:35 -07001145 FilterByTechnology(Technology::kWifi, &wifi_devices);
mukesh agrawal32399322011-09-01 10:53:43 -07001146
1147 for (vector<DeviceRefPtr>::iterator it = wifi_devices.begin();
1148 it != wifi_devices.end();
1149 ++it) {
Darin Petkovc0865312011-09-16 15:31:20 -07001150 (*it)->Scan(error);
mukesh agrawal32399322011-09-01 10:53:43 -07001151 }
1152 } else {
1153 // TODO(quiche): support scanning for other technologies?
Paul Stewartbe005172011-11-02 18:10:29 -07001154 Error::PopulateAndLog(error, Error::kInvalidArguments,
1155 "Unrecognized technology " + technology);
mukesh agrawal32399322011-09-01 10:53:43 -07001156 }
1157}
1158
Paul Stewart22aa71b2011-09-16 12:15:11 -07001159string Manager::GetTechnologyOrder() {
1160 vector<string> technology_names;
1161 for (vector<Technology::Identifier>::iterator it = technology_order_.begin();
1162 it != technology_order_.end();
1163 ++it) {
1164 technology_names.push_back(Technology::NameFromIdentifier(*it));
1165 }
1166
1167 return JoinString(technology_names, ',');
1168}
1169
1170void Manager::SetTechnologyOrder(const string &order, Error *error) {
1171 vector<Technology::Identifier> new_order;
Ben Chanfad4a0b2012-04-18 15:49:59 -07001172 SLOG(Manager, 2) << "Setting technology order to " << order;
Paul Stewart20088d82012-02-16 06:58:55 -08001173 if (!Technology::GetTechnologyVectorFromString(order, &new_order, error)) {
1174 return;
Paul Stewart22aa71b2011-09-16 12:15:11 -07001175 }
1176
1177 technology_order_ = new_order;
1178 SortServices();
1179}
1180
Paul Stewart75897df2011-04-27 09:05:53 -07001181} // namespace shill