blob: 5a9f04dea404b1361c6c8840f71b599aaca0535d [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>
Paul Stewart75897df2011-04-27 09:05:53 -070011#include <string>
Chris Masone52cd19b2011-06-29 17:23:04 -070012#include <vector>
Paul Stewart75897df2011-04-27 09:05:53 -070013
Eric Shienbrood3e20a232012-02-16 11:35:56 -050014#include <base/bind.h>
Paul Stewarte6132022011-08-16 09:11:02 -070015#include <base/file_util.h>
Chris Masoneee929b72011-05-10 10:02:18 -070016#include <base/logging.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 Stewart22aa71b2011-09-16 12:15:11 -070019#include <base/string_util.h>
Chris Masone3bd3c8c2011-06-13 08:20:26 -070020#include <chromeos/dbus/service_constants.h>
Chris Masoneee929b72011-05-10 10:02:18 -070021
Chris Masoned0ceb8c2011-06-02 10:05:39 -070022#include "shill/adaptor_interfaces.h"
Paul Stewartc1dec4d2011-12-08 15:25:28 -080023#include "shill/connection.h"
Paul Stewart75897df2011-04-27 09:05:53 -070024#include "shill/control_interface.h"
Chris Masoned0ceb8c2011-06-02 10:05:39 -070025#include "shill/dbus_adaptor.h"
Chris Masone7aa5f902011-07-11 11:13:35 -070026#include "shill/default_profile.h"
Chris Masone9be4a9d2011-05-16 15:44:09 -070027#include "shill/device.h"
28#include "shill/device_info.h"
Chris Masone6791a432011-07-12 13:23:19 -070029#include "shill/ephemeral_profile.h"
Chris Masone8fe2c7e2011-06-09 15:51:19 -070030#include "shill/error.h"
Paul Stewart26b327e2011-10-19 11:38:09 -070031#include "shill/event_dispatcher.h"
Chris Masone9d779932011-08-25 16:33:41 -070032#include "shill/key_file_store.h"
Thieu Lea20cbc22012-01-09 22:01:43 +000033#include "shill/metrics.h"
Chris Masone7aa5f902011-07-11 11:13:35 -070034#include "shill/profile.h"
Chris Masoneb925cc82011-06-22 15:39:57 -070035#include "shill/property_accessor.h"
Gary Morainac1bdb42012-02-16 17:42:29 -080036#include "shill/proxy_factory.h"
Paul Stewarte6132022011-08-16 09:11:02 -070037#include "shill/resolver.h"
Ben Chanfad4a0b2012-04-18 15:49:59 -070038#include "shill/scope_logger.h"
Chris Masone9be4a9d2011-05-16 15:44:09 -070039#include "shill/service.h"
Thieu Lea20cbc22012-01-09 22:01:43 +000040#include "shill/service_sorter.h"
Darin Petkov33af05c2012-02-28 10:10:30 +010041#include "shill/vpn_service.h"
mukesh agrawal7a4e4002011-09-06 11:26:05 -070042#include "shill/wifi.h"
43#include "shill/wifi_service.h"
Paul Stewart75897df2011-04-27 09:05:53 -070044
Eric Shienbrood3e20a232012-02-16 11:35:56 -050045using base::Bind;
46using base::StringPrintf;
47using base::Unretained;
Gaurav Shah435de2c2011-11-17 19:01:07 -080048using std::set;
Paul Stewart75897df2011-04-27 09:05:53 -070049using std::string;
Chris Masone9be4a9d2011-05-16 15:44:09 -070050using std::vector;
Paul Stewart75897df2011-04-27 09:05:53 -070051
52namespace shill {
Paul Stewarte6132022011-08-16 09:11:02 -070053
Darin Petkovb65c2452012-02-23 15:17:06 +010054// statics
55const char Manager::kErrorNoDevice[] = "no wifi devices available";
56const char Manager::kErrorTypeRequired[] = "must specify service type";
57const char Manager::kErrorUnsupportedServiceType[] =
58 "service type is unsupported";
mukesh agrawal7a4e4002011-09-06 11:26:05 -070059
Paul Stewart75897df2011-04-27 09:05:53 -070060Manager::Manager(ControlInterface *control_interface,
Darin Petkov887f2982011-07-14 16:10:17 -070061 EventDispatcher *dispatcher,
Thieu Le3426c8f2012-01-11 17:35:11 -080062 Metrics *metrics,
Chris Masone2ae797d2011-08-23 20:41:00 -070063 GLib *glib,
64 const string &run_directory,
65 const string &storage_directory,
66 const string &user_storage_format)
mukesh agrawal8a3188d2011-12-01 20:56:44 +000067 : dispatcher_(dispatcher),
mukesh agrawal8a3188d2011-12-01 20:56:44 +000068 run_path_(FilePath(run_directory)),
69 storage_path_(FilePath(storage_directory)),
70 user_storage_format_(user_storage_format),
71 adaptor_(control_interface->CreateManagerAdaptor(this)),
Thieu Le3426c8f2012-01-11 17:35:11 -080072 device_info_(control_interface, dispatcher, metrics, this),
73 modem_info_(control_interface, dispatcher, metrics, this, glib),
Darin Petkov33af05c2012-02-28 10:10:30 +010074 vpn_provider_(control_interface, dispatcher, metrics, this),
mukesh agrawal8a3188d2011-12-01 20:56:44 +000075 running_(false),
76 connect_profiles_to_rpc_(true),
77 ephemeral_profile_(new EphemeralProfile(control_interface, this)),
78 control_interface_(control_interface),
Thieu Le3426c8f2012-01-11 17:35:11 -080079 metrics_(metrics),
Paul Stewart10e9e4e2012-04-26 19:46:28 -070080 glib_(glib),
81 use_startup_portal_list_(false) {
Chris Masone7aa5f902011-07-11 11:13:35 -070082 HelpRegisterDerivedString(flimflam::kActiveProfileProperty,
Paul Stewart1b253142012-01-26 14:05:52 -080083 &Manager::GetActiveProfileRpcIdentifier,
Chris Masone7aa5f902011-07-11 11:13:35 -070084 NULL);
Chris Masone27c4aa52011-07-02 13:10:14 -070085 HelpRegisterDerivedStrings(flimflam::kAvailableTechnologiesProperty,
86 &Manager::AvailableTechnologies,
87 NULL);
Paul Stewart10e9e4e2012-04-26 19:46:28 -070088 HelpRegisterDerivedString(flimflam::kCheckPortalListProperty,
89 &Manager::GetCheckPortalList,
90 &Manager::SetCheckPortalList);
Chris Masone27c4aa52011-07-02 13:10:14 -070091 HelpRegisterDerivedStrings(flimflam::kConnectedTechnologiesProperty,
92 &Manager::ConnectedTechnologies,
93 NULL);
Chris Masone88cbd5f2011-07-03 14:30:04 -070094 store_.RegisterString(flimflam::kCountryProperty, &props_.country);
Chris Masone27c4aa52011-07-02 13:10:14 -070095 HelpRegisterDerivedString(flimflam::kDefaultTechnologyProperty,
96 &Manager::DefaultTechnology,
97 NULL);
Chris Masone27c4aa52011-07-02 13:10:14 -070098 HelpRegisterDerivedStrings(flimflam::kDevicesProperty,
99 &Manager::EnumerateDevices,
100 NULL);
Chris Masone88cbd5f2011-07-03 14:30:04 -0700101 HelpRegisterDerivedStrings(flimflam::kEnabledTechnologiesProperty,
102 &Manager::EnabledTechnologies,
103 NULL);
104 store_.RegisterBool(flimflam::kOfflineModeProperty, &props_.offline_mode);
105 store_.RegisterString(flimflam::kPortalURLProperty, &props_.portal_url);
Paul Stewartc681fa02012-03-02 19:40:04 -0800106 store_.RegisterInt32(kPortalCheckIntervalProperty,
107 &props_.portal_check_interval_seconds);
Paul Stewart1b253142012-01-26 14:05:52 -0800108 HelpRegisterDerivedStrings(flimflam::kProfilesProperty,
109 &Manager::EnumerateProfiles,
110 NULL);
Paul Stewartc681fa02012-03-02 19:40:04 -0800111 store_.RegisterString(kHostNameProperty, &props_.host_name);
Chris Masone88cbd5f2011-07-03 14:30:04 -0700112 HelpRegisterDerivedString(flimflam::kStateProperty,
113 &Manager::CalculateState,
114 NULL);
mukesh agrawal2366eed2012-03-20 18:21:50 -0700115 HelpRegisterConstDerivedRpcIdentifiers(flimflam::kServicesProperty,
116 &Manager::EnumerateAvailableServices);
Chris Masone27c4aa52011-07-02 13:10:14 -0700117 HelpRegisterDerivedStrings(flimflam::kServiceWatchListProperty,
118 &Manager::EnumerateWatchedServices,
119 NULL);
Chris Masone3c3f6a12011-07-01 10:01:41 -0700120
mukesh agrawal84de5d22012-02-17 19:29:15 -0800121 // Set default technology order "by hand", to avoid invoking side
122 // effects of SetTechnologyOrder.
123 technology_order_.push_back(
Darin Petkov2f903b32012-04-18 12:56:43 +0200124 Technology::IdentifierFromName(flimflam::kTypeVPN));
125 technology_order_.push_back(
mukesh agrawal84de5d22012-02-17 19:29:15 -0800126 Technology::IdentifierFromName(flimflam::kTypeEthernet));
127 technology_order_.push_back(
128 Technology::IdentifierFromName(flimflam::kTypeWifi));
129 technology_order_.push_back(
130 Technology::IdentifierFromName(flimflam::kTypeCellular));
131
Ben Chanfad4a0b2012-04-18 15:49:59 -0700132 SLOG(Manager, 2) << "Manager initialized.";
Paul Stewart75897df2011-04-27 09:05:53 -0700133}
134
Chris Masone6791a432011-07-12 13:23:19 -0700135Manager::~Manager() {
Chris Masone9d779932011-08-25 16:33:41 -0700136 profiles_.clear();
Chris Masone6791a432011-07-12 13:23:19 -0700137}
Paul Stewart75897df2011-04-27 09:05:53 -0700138
mukesh agrawal8f317b62011-07-15 11:53:23 -0700139void Manager::AddDeviceToBlackList(const string &device_name) {
140 device_info_.AddDeviceToBlackList(device_name);
141}
142
Paul Stewart75897df2011-04-27 09:05:53 -0700143void Manager::Start() {
Paul Stewart0af98bf2011-05-10 17:38:08 -0700144 LOG(INFO) << "Manager started.";
Paul Stewarte6132022011-08-16 09:11:02 -0700145
Gary Morainac1bdb42012-02-16 17:42:29 -0800146 power_manager_.reset(new PowerManager(ProxyFactory::GetInstance()));
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500147 // TODO(ers): weak ptr for metrics_?
148 PowerManager::PowerStateCallback cb =
149 Bind(&Metrics::NotifyPowerStateChange, Unretained(metrics_));
Thieu Leb84ba342012-03-02 15:15:19 -0800150 power_manager_->AddStateChangeCallback(Metrics::kMetricPowerManagerKey, cb);
151
Chris Masone2ae797d2011-08-23 20:41:00 -0700152 CHECK(file_util::CreateDirectory(run_path_)) << run_path_.value();
Paul Stewarte6132022011-08-16 09:11:02 -0700153 Resolver::GetInstance()->set_path(run_path_.Append("resolv.conf"));
Chris Masone2ae797d2011-08-23 20:41:00 -0700154
Gaurav Shah71354762011-11-28 19:22:49 -0800155 InitializeProfiles();
Paul Stewart75897df2011-04-27 09:05:53 -0700156 running_ = true;
Chris Masone413a3192011-05-09 17:10:05 -0700157 adaptor_->UpdateRunning();
Paul Stewart0af98bf2011-05-10 17:38:08 -0700158 device_info_.Start();
Darin Petkov887f2982011-07-14 16:10:17 -0700159 modem_info_.Start();
Darin Petkov33af05c2012-02-28 10:10:30 +0100160 vpn_provider_.Start();
Paul Stewart75897df2011-04-27 09:05:53 -0700161}
162
163void Manager::Stop() {
164 running_ = false;
Chris Masone9d779932011-08-25 16:33:41 -0700165 // Persist profile, device, service information to disk.
166 vector<ProfileRefPtr>::iterator it;
167 for (it = profiles_.begin(); it != profiles_.end(); ++it) {
Paul Stewartd0a3b812012-03-28 22:48:22 -0700168 // Since this happens in a loop, the current manager state is stored to
169 // all default profiles in the stack. This is acceptable because the
170 // only time multiple default profiles are loaded are during autotests.
Chris Masone6515aab2011-10-12 16:19:09 -0700171 (*it)->Save();
Chris Masone9d779932011-08-25 16:33:41 -0700172 }
Chris Masone9d779932011-08-25 16:33:41 -0700173
Thieu Le1271d682011-11-02 22:48:19 +0000174 vector<ServiceRefPtr>::iterator services_it;
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000175 Error e;
Thieu Le1271d682011-11-02 22:48:19 +0000176 for (services_it = services_.begin(); services_it != services_.end();
177 ++services_it) {
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000178 (*services_it)->Disconnect(&e);
Thieu Le1271d682011-11-02 22:48:19 +0000179 }
180
Chris Masone413a3192011-05-09 17:10:05 -0700181 adaptor_->UpdateRunning();
Darin Petkov33af05c2012-02-28 10:10:30 +0100182 vpn_provider_.Stop();
Darin Petkov887f2982011-07-14 16:10:17 -0700183 modem_info_.Stop();
184 device_info_.Stop();
Thieu Leb84ba342012-03-02 15:15:19 -0800185
186 // Some unit tests do not call Manager::Start().
187 if (power_manager_.get())
188 power_manager_->RemoveStateChangeCallback(Metrics::kMetricPowerManagerKey);
Paul Stewart75897df2011-04-27 09:05:53 -0700189}
190
Gaurav Shah71354762011-11-28 19:22:49 -0800191void Manager::InitializeProfiles() {
192 DCHECK(profiles_.empty());
193 // The default profile must go first on the stack.
194 CHECK(file_util::CreateDirectory(storage_path_)) << storage_path_.value();
Paul Stewart870523b2012-01-11 17:00:42 -0800195 scoped_refptr<DefaultProfile>
196 default_profile(new DefaultProfile(control_interface_,
Gaurav Shah71354762011-11-28 19:22:49 -0800197 this,
198 storage_path_,
Paul Stewartd0a3b812012-03-28 22:48:22 -0700199 DefaultProfile::kDefaultId,
Gaurav Shah71354762011-11-28 19:22:49 -0800200 props_));
Paul Stewart870523b2012-01-11 17:00:42 -0800201 CHECK(default_profile->InitStorage(glib_, Profile::kCreateOrOpenExisting,
202 NULL));
203 CHECK(default_profile->LoadManagerProperties(&props_));
204 profiles_.push_back(default_profile.release());
Gaurav Shah71354762011-11-28 19:22:49 -0800205 Error error;
Paul Stewart19c871d2011-12-15 16:10:13 -0800206 string path;
Gaurav Shah71354762011-11-28 19:22:49 -0800207 for (vector<string>::iterator it = startup_profiles_.begin();
208 it != startup_profiles_.end(); ++it)
Paul Stewart19c871d2011-12-15 16:10:13 -0800209 PushProfile(*it, &path, &error);
Gaurav Shah71354762011-11-28 19:22:49 -0800210}
211
Paul Stewart19c871d2011-12-15 16:10:13 -0800212void Manager::CreateProfile(const string &name, string *path, Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700213 SLOG(Manager, 2) << __func__ << " " << name;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700214 Profile::Identifier ident;
215 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700216 Error::PopulateAndLog(error, Error::kInvalidArguments,
217 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700218 return;
219 }
Paul Stewartd0a3b812012-03-28 22:48:22 -0700220
221 ProfileRefPtr profile;
222 if (ident.user.empty()) {
223 profile = new DefaultProfile(control_interface_,
224 this,
225 storage_path_,
226 ident.identifier,
227 props_);
228 } else {
229 profile = new Profile(control_interface_,
230 this,
231 ident,
232 user_storage_format_,
Gary Morainb672d352012-04-25 09:19:06 -0700233 true);
Paul Stewartd0a3b812012-03-28 22:48:22 -0700234 }
235
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700236 if (!profile->InitStorage(glib_, Profile::kCreateNew, error)) {
Paul Stewart19c871d2011-12-15 16:10:13 -0800237 // |error| will have been populated by InitStorage().
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700238 return;
239 }
240
241 // Save profile data out, and then let the scoped pointer fall out of scope.
242 if (!profile->Save()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700243 Error::PopulateAndLog(error, Error::kInternalError,
244 "Profile name " + name + " could not be saved");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700245 return;
246 }
Paul Stewart19c871d2011-12-15 16:10:13 -0800247
248 *path = profile->GetRpcIdentifier();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700249}
250
Paul Stewart19c871d2011-12-15 16:10:13 -0800251void Manager::PushProfile(const string &name, string *path, Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700252 SLOG(Manager, 2) << __func__ << " " << name;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700253 Profile::Identifier ident;
254 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700255 Error::PopulateAndLog(error, Error::kInvalidArguments,
256 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700257 return;
258 }
259
260 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
261 it != profiles_.end();
262 ++it) {
263 if ((*it)->MatchesIdentifier(ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700264 Error::PopulateAndLog(error, Error::kAlreadyExists,
265 "Profile name " + name + " is already on stack");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700266 return;
267 }
268 }
269
Paul Stewartd0a3b812012-03-28 22:48:22 -0700270 ProfileRefPtr profile;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700271 if (ident.user.empty()) {
Paul Stewartd0a3b812012-03-28 22:48:22 -0700272 // Allow a machine-wide-profile to be pushed on the stack only if the
273 // profile stack is empty, or if the topmost profile on the stack is
274 // also a machine-wide (non-user) profile.
275 if (!profiles_.empty() && !profiles_.back()->GetUser().empty()) {
276 Error::PopulateAndLog(error, Error::kInvalidArguments,
277 "Cannot load non-default global profile " + name +
278 " on top of a user profile");
279 return;
280 }
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700281
Paul Stewartd0a3b812012-03-28 22:48:22 -0700282 scoped_refptr<DefaultProfile>
283 default_profile(new DefaultProfile(control_interface_,
284 this,
285 storage_path_,
286 ident.identifier,
287 props_));
288 if (!default_profile->InitStorage(glib_, Profile::kOpenExisting, error)) {
289 // |error| will have been populated by InitStorage().
290 return;
291 }
292
293 if (!default_profile->LoadManagerProperties(&props_)) {
294 Error::PopulateAndLog(error, Error::kInvalidArguments,
295 "Could not load Manager properties from profile " +
296 name);
297 return;
298 }
299 profile = default_profile;
300 } else {
301 profile = new Profile(control_interface_,
302 this,
303 ident,
304 user_storage_format_,
305 connect_profiles_to_rpc_);
306 if (!profile->InitStorage(glib_, Profile::kOpenExisting, error)) {
307 // |error| will have been populated by InitStorage().
308 return;
309 }
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700310 }
311
Paul Stewarta849a3d2011-11-03 05:54:09 -0700312 profiles_.push_back(profile);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700313
314 // Offer each registered Service the opportunity to join this new Profile.
Paul Stewarta41e38d2011-11-11 07:47:29 -0800315 for (vector<ServiceRefPtr>::iterator it = services_.begin();
316 it != services_.end(); ++it) {
Paul Stewartbba6a5b2011-11-02 18:45:59 -0700317 profile->ConfigureService(*it);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700318 }
319
Paul Stewarta41e38d2011-11-11 07:47:29 -0800320 // Shop the Profile contents around to Devices which can create
321 // non-visible services.
322 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
323 it != devices_.end(); ++it) {
324 profile->ConfigureDevice(*it);
325 }
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800326
Paul Stewart66815332012-04-09 18:09:36 -0700327 // Offer the Profile contents to the VPNProvider which will create
328 // new VPN services if necessary.
329 vpn_provider_.CreateServicesFromProfile(profile);
330
Paul Stewart19c871d2011-12-15 16:10:13 -0800331 *path = profile->GetRpcIdentifier();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800332 SortServices();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700333}
334
335void Manager::PopProfileInternal() {
336 CHECK(!profiles_.empty());
337 ProfileRefPtr active_profile = profiles_.back();
338 profiles_.pop_back();
Paul Stewart75225512012-01-26 22:51:33 -0800339 vector<ServiceRefPtr>::iterator it;
Paul Stewart65512e12012-03-26 18:01:08 -0700340 for (it = services_.begin(); it != services_.end();) {
341 if ((*it)->profile().get() != active_profile.get() ||
342 MatchProfileWithService(*it) ||
343 !UnloadService(&it)) {
344 LOG(ERROR) << "Skipping unload of service";
345 ++it;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700346 }
347 }
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800348 SortServices();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700349}
350
Paul Stewarta41e38d2011-11-11 07:47:29 -0800351void Manager::PopProfile(const string &name, Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700352 SLOG(Manager, 2) << __func__ << " " << name;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700353 Profile::Identifier ident;
354 if (profiles_.empty()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700355 Error::PopulateAndLog(error, Error::kNotFound, "Profile stack is empty");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700356 return;
357 }
358 ProfileRefPtr active_profile = profiles_.back();
359 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700360 Error::PopulateAndLog(error, Error::kInvalidArguments,
361 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700362 return;
363 }
364 if (!active_profile->MatchesIdentifier(ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700365 Error::PopulateAndLog(error, Error::kNotSupported,
366 name + " is not the active profile");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700367 return;
368 }
369 PopProfileInternal();
370}
371
372void Manager::PopAnyProfile(Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700373 SLOG(Manager, 2) << __func__;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700374 Profile::Identifier ident;
375 if (profiles_.empty()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700376 Error::PopulateAndLog(error, Error::kNotFound, "Profile stack is empty");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700377 return;
378 }
379 PopProfileInternal();
380}
381
Paul Stewarte73d05c2012-03-29 16:26:05 -0700382void Manager::RemoveProfile(const string &name, Error *error) {
383 Profile::Identifier ident;
384 if (!Profile::ParseIdentifier(name, &ident)) {
385 Error::PopulateAndLog(error, Error::kInvalidArguments,
386 "Invalid profile name " + name);
387 return;
388 }
389
390 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
391 it != profiles_.end();
392 ++it) {
393 if ((*it)->MatchesIdentifier(ident)) {
394 Error::PopulateAndLog(error, Error::kInvalidArguments,
395 "Cannot remove profile name " + name +
396 " since it is on stack");
397 return;
398 }
399 }
400
401 ProfileRefPtr profile;
402 if (ident.user.empty()) {
403 profile = new DefaultProfile(control_interface_,
404 this,
405 storage_path_,
406 ident.identifier,
407 props_);
408 } else {
409 profile = new Profile(control_interface_,
410 this,
411 ident,
412 user_storage_format_,
413 false);
414 }
415
416
417 // |error| will have been populated if RemoveStorage fails.
418 profile->RemoveStorage(glib_, error);
419
420 return;
421}
422
Paul Stewart75225512012-01-26 22:51:33 -0800423bool Manager::HandleProfileEntryDeletion(const ProfileRefPtr &profile,
424 const std::string &entry_name) {
425 bool moved_services = false;
426 for (vector<ServiceRefPtr>::iterator it = services_.begin();
Paul Stewart65512e12012-03-26 18:01:08 -0700427 it != services_.end();) {
Paul Stewart75225512012-01-26 22:51:33 -0800428 if ((*it)->profile().get() == profile.get() &&
429 (*it)->GetStorageIdentifier() == entry_name) {
430 profile->AbandonService(*it);
Paul Stewart65512e12012-03-26 18:01:08 -0700431 if (MatchProfileWithService(*it) ||
432 !UnloadService(&it)) {
433 ++it;
Paul Stewart75225512012-01-26 22:51:33 -0800434 }
435 moved_services = true;
Paul Stewart65512e12012-03-26 18:01:08 -0700436 } else {
437 ++it;
Paul Stewart75225512012-01-26 22:51:33 -0800438 }
439 }
440 return moved_services;
441}
442
Paul Stewart0756db92012-01-27 08:34:47 -0800443ServiceRefPtr Manager::GetServiceWithStorageIdentifier(
444 const ProfileRefPtr &profile, const std::string &entry_name, Error *error) {
445 for (vector<ServiceRefPtr>::iterator it = services_.begin();
446 it != services_.end(); ++it) {
447 if ((*it)->profile().get() == profile.get() &&
448 (*it)->GetStorageIdentifier() == entry_name) {
449 return *it;
450 }
451 }
452
453 Error::PopulateAndLog(error, Error::kNotFound,
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500454 StringPrintf("Entry %s is not registered in the manager",
455 entry_name.c_str()));
Paul Stewart0756db92012-01-27 08:34:47 -0800456 return NULL;
457}
458
Paul Stewart13ed2252012-03-21 12:52:46 -0700459ServiceRefPtr Manager::GetServiceWithGUID(
460 const std::string &guid, Error *error) {
461 for (vector<ServiceRefPtr>::iterator it = services_.begin();
462 it != services_.end(); ++it) {
463 if ((*it)->guid() == guid) {
464 return *it;
465 }
466 }
467
468 Error::PopulateAndLog(error, Error::kNotFound,
469 StringPrintf("Service wth GUID %s is not registered in the manager",
470 guid.c_str()));
471 return NULL;
472}
473
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700474ServiceRefPtr Manager::GetDefaultService() const {
475 if (services_.empty() || !services_[0]->connection().get()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700476 SLOG(Manager, 2) << "In " << __func__ << ": No default connection exists.";
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700477 return NULL;
478 }
479 return services_[0];
480}
481
Paul Stewart20088d82012-02-16 06:58:55 -0800482bool Manager::IsPortalDetectionEnabled(Technology::Identifier tech) {
483 Error error;
484 vector<Technology::Identifier> portal_technologies;
Paul Stewart10e9e4e2012-04-26 19:46:28 -0700485 return Technology::GetTechnologyVectorFromString(GetCheckPortalList(NULL),
Paul Stewart20088d82012-02-16 06:58:55 -0800486 &portal_technologies,
487 &error) &&
488 std::find(portal_technologies.begin(), portal_technologies.end(),
489 tech) != portal_technologies.end();
490}
491
Paul Stewart10e9e4e2012-04-26 19:46:28 -0700492void Manager::SetStartupPortalList(const string &portal_list) {
493 startup_portal_list_ = portal_list;
494 use_startup_portal_list_ = true;
495}
496
Paul Stewart10ccbb32012-04-26 15:59:30 -0700497bool Manager::IsServiceEphemeral(const ServiceConstRefPtr &service) const {
498 return service->profile() == ephemeral_profile_;
499}
500
Paul Stewart1b253142012-01-26 14:05:52 -0800501const ProfileRefPtr &Manager::ActiveProfile() const {
Eric Shienbroodc74cf9c2012-03-02 15:00:35 -0500502 DCHECK_NE(profiles_.size(), 0U);
Chris Masone7aa5f902011-07-11 11:13:35 -0700503 return profiles_.back();
504}
505
Paul Stewart1b253142012-01-26 14:05:52 -0800506bool Manager::IsActiveProfile(const ProfileRefPtr &profile) const {
507 return (profiles_.size() > 0 &&
508 ActiveProfile().get() == profile.get());
509}
510
Eric Shienbrood9a245532012-03-07 14:20:39 -0500511void Manager::SaveActiveProfile() {
512 if (!profiles_.empty()) {
513 ActiveProfile()->Save();
514 }
515}
516
Chris Masone6515aab2011-10-12 16:19:09 -0700517bool Manager::MoveServiceToProfile(const ServiceRefPtr &to_move,
518 const ProfileRefPtr &destination) {
519 const ProfileRefPtr from = to_move->profile();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700520 SLOG(Manager, 2) << "Moving service "
521 << to_move->UniqueName()
522 << " to profile "
523 << destination->GetFriendlyName()
524 << " from "
525 << from->GetFriendlyName();
Chris Masone6515aab2011-10-12 16:19:09 -0700526 return destination->AdoptService(to_move) &&
527 from->AbandonService(to_move);
Chris Masone6791a432011-07-12 13:23:19 -0700528}
529
Paul Stewart7f61e522012-03-22 11:13:45 -0700530ProfileRefPtr Manager::LookupProfileByRpcIdentifier(
531 const string &profile_rpcid) {
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800532 for (vector<ProfileRefPtr>::iterator it = profiles_.begin();
533 it != profiles_.end();
534 ++it) {
535 if (profile_rpcid == (*it)->GetRpcIdentifier()) {
Paul Stewart7f61e522012-03-22 11:13:45 -0700536 return *it;
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800537 }
538 }
Paul Stewart7f61e522012-03-22 11:13:45 -0700539 return NULL;
540}
541
542void Manager::SetProfileForService(const ServiceRefPtr &to_set,
543 const string &profile_rpcid,
544 Error *error) {
545 ProfileRefPtr profile = LookupProfileByRpcIdentifier(profile_rpcid);
546 if (!profile) {
547 Error::PopulateAndLog(error, Error::kInvalidArguments,
548 StringPrintf("Unknown Profile %s requested for "
549 "Service", profile_rpcid.c_str()));
550 return;
551 }
552
553 if (to_set->profile().get() == profile.get()) {
554 Error::PopulateAndLog(error, Error::kInvalidArguments,
555 "Service is already connected to this profile");
556 } else if (!MoveServiceToProfile(to_set, profile)) {
557 Error::PopulateAndLog(error, Error::kInternalError,
558 "Unable to move service to profile");
559 }
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800560}
561
Eric Shienbrood9a245532012-03-07 14:20:39 -0500562void Manager::EnableTechnology(const std::string &technology_name,
563 Error *error,
564 const ResultCallback &callback) {
565 Technology::Identifier id = Technology::IdentifierFromName(technology_name);
566 if (id == Technology::kUnknown) {
567 error->Populate(Error::kInvalidArguments, "Unknown technology");
568 return;
569 }
570 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
571 it != devices_.end(); ++it) {
572 DeviceRefPtr device = *it;
573 if (device->technology() == id && !device->enabled()) {
574 device->SetEnabledPersistent(true, error, callback);
575 // Continue with other devices even if one fails
576 // TODO(ers): Decide whether an error should be returned
577 // for the overall EnableTechnology operation if some
578 // devices succeed and some fail.
579 }
580 }
581}
582
583void Manager::DisableTechnology(const std::string &technology_name,
584 Error *error,
585 const ResultCallback &callback) {
586 Technology::Identifier id = Technology::IdentifierFromName(technology_name);
587 if (id == Technology::kUnknown) {
588 error->Populate(Error::kInvalidArguments, "Unknown technology");
589 return;
590 }
591 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
592 it != devices_.end(); ++it) {
593 DeviceRefPtr device = *it;
594 if (device->technology() == id && device->enabled()) {
595 device->SetEnabledPersistent(false, error, callback);
596 // Continue with other devices even if one fails
597 // TODO(ers): Decide whether an error should be returned
598 // for the overall DisableTechnology operation if some
599 // devices succeed and some fail.
600 }
601 }
602}
603
604void Manager::UpdateEnabledTechnologies() {
605 Error error;
606 adaptor_->EmitStringsChanged(flimflam::kEnabledTechnologiesProperty,
607 EnabledTechnologies(&error));
608}
609
Chris Masone2b105542011-06-22 10:58:09 -0700610void Manager::RegisterDevice(const DeviceRefPtr &to_manage) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700611 SLOG(Manager, 2) << __func__ << "(" << to_manage->FriendlyName() << ")";
Chris Masonec1e50412011-06-07 13:04:53 -0700612 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700613 for (it = devices_.begin(); it != devices_.end(); ++it) {
Chris Masonec1e50412011-06-07 13:04:53 -0700614 if (to_manage.get() == it->get())
Chris Masone9be4a9d2011-05-16 15:44:09 -0700615 return;
616 }
Chris Masonec1e50412011-06-07 13:04:53 -0700617 devices_.push_back(to_manage);
Paul Stewartf1ce5d22011-05-19 13:10:20 -0700618
Paul Stewarta41e38d2011-11-11 07:47:29 -0800619 // We are applying device properties from the DefaultProfile, and adding
620 // the union of hidden services in all loaded profiles to the device.
Chris Masone6515aab2011-10-12 16:19:09 -0700621 for (vector<ProfileRefPtr>::iterator it = profiles_.begin();
622 it != profiles_.end();
623 ++it) {
Paul Stewarta41e38d2011-11-11 07:47:29 -0800624 // Load device configuration, if any exists, as well as hidden services.
625 (*it)->ConfigureDevice(to_manage);
626
627 // Currently the only profile for which "Save" is implemented is the
628 // DefaultProfile. It iterates over all Devices and stores their state.
629 // We perform the Save now in case the device we have just registered
630 // is new and needs to be added to the stored DefaultProfile.
Chris Masone6515aab2011-10-12 16:19:09 -0700631 (*it)->Save();
632 }
Paul Stewarta41e38d2011-11-11 07:47:29 -0800633
634 // In normal usage, running_ will always be true when we are here, however
635 // unit tests sometimes do things in otherwise invalid states.
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400636 if (running_ && (to_manage->enabled_persistent() ||
637 to_manage->IsUnderlyingDeviceEnabled()))
Eric Shienbrood9a245532012-03-07 14:20:39 -0500638 to_manage->SetEnabled(true);
Gaurav Shah435de2c2011-11-17 19:01:07 -0800639
Eric Shienbrood8839a892012-03-29 10:33:48 -0400640 EmitDeviceProperties();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700641}
642
mukesh agrawal5029c6c2011-08-25 11:12:40 -0700643void Manager::DeregisterDevice(const DeviceRefPtr &to_forget) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700644 SLOG(Manager, 2) << __func__ << "(" << to_forget->FriendlyName() << ")";
Chris Masonec1e50412011-06-07 13:04:53 -0700645 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700646 for (it = devices_.begin(); it != devices_.end(); ++it) {
Chris Masonec1e50412011-06-07 13:04:53 -0700647 if (to_forget.get() == it->get()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700648 SLOG(Manager, 2) << "Deregistered device: " << to_forget->UniqueName();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500649 to_forget->SetEnabled(false);
Chris Masone9be4a9d2011-05-16 15:44:09 -0700650 devices_.erase(it);
Eric Shienbrood8839a892012-03-29 10:33:48 -0400651 EmitDeviceProperties();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700652 return;
653 }
654 }
Ben Chanfad4a0b2012-04-18 15:49:59 -0700655 SLOG(Manager, 2) << __func__ << " unknown device: "
656 << to_forget->UniqueName();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700657}
658
Eric Shienbrood8839a892012-03-29 10:33:48 -0400659void Manager::EmitDeviceProperties() {
660 vector<DeviceRefPtr>::iterator it;
661 vector<string> device_paths;
662 for (it = devices_.begin(); it != devices_.end(); ++it) {
663 device_paths.push_back((*it)->GetRpcIdentifier());
664 }
665 adaptor_->EmitRpcIdentifierArrayChanged(flimflam::kDevicesProperty,
666 device_paths);
667 Error error;
668 adaptor_->EmitStringsChanged(flimflam::kAvailableTechnologiesProperty,
669 AvailableTechnologies(&error));
670 adaptor_->EmitStringsChanged(flimflam::kEnabledTechnologiesProperty,
671 EnabledTechnologies(&error));
672}
673
mukesh agrawal4eb4d782011-12-05 17:34:37 +0000674bool Manager::HasService(const ServiceRefPtr &service) {
675 vector<ServiceRefPtr>::iterator it;
676 for (it = services_.begin(); it != services_.end(); ++it) {
677 if ((*it)->UniqueName() == service->UniqueName())
678 return true;
679 }
680 return false;
681}
682
Chris Masone2b105542011-06-22 10:58:09 -0700683void Manager::RegisterService(const ServiceRefPtr &to_manage) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700684 SLOG(Manager, 2) << "In " << __func__ << "(): Registering service "
685 << to_manage->UniqueName();
mukesh agrawald835b202011-10-07 15:26:47 -0700686
Paul Stewart75225512012-01-26 22:51:33 -0800687 MatchProfileWithService(to_manage);
Chris Masone6791a432011-07-12 13:23:19 -0700688
689 // Now add to OUR list.
Chris Masonec1e50412011-06-07 13:04:53 -0700690 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700691 for (it = services_.begin(); it != services_.end(); ++it) {
mukesh agrawald835b202011-10-07 15:26:47 -0700692 CHECK(to_manage->UniqueName() != (*it)->UniqueName());
Chris Masone9be4a9d2011-05-16 15:44:09 -0700693 }
Chris Masonec1e50412011-06-07 13:04:53 -0700694 services_.push_back(to_manage);
Paul Stewart22aa71b2011-09-16 12:15:11 -0700695 SortServices();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700696}
697
Chris Masone6515aab2011-10-12 16:19:09 -0700698void Manager::DeregisterService(const ServiceRefPtr &to_forget) {
Chris Masonec1e50412011-06-07 13:04:53 -0700699 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700700 for (it = services_.begin(); it != services_.end(); ++it) {
Chris Masone6791a432011-07-12 13:23:19 -0700701 if (to_forget->UniqueName() == (*it)->UniqueName()) {
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800702 DCHECK(!(*it)->connection());
Chris Masone9be4a9d2011-05-16 15:44:09 -0700703 services_.erase(it);
Paul Stewart22aa71b2011-09-16 12:15:11 -0700704 SortServices();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700705 return;
706 }
707 }
708}
709
Paul Stewart65512e12012-03-26 18:01:08 -0700710bool Manager::UnloadService(vector<ServiceRefPtr>::iterator *service_iterator) {
711 if (!(**service_iterator)->Unload()) {
712 return false;
713 }
714
715 DCHECK(!(**service_iterator)->connection());
716 *service_iterator = services_.erase(*service_iterator);
717
718 return true;
719}
720
mukesh agrawal00917ce2011-11-22 23:56:55 +0000721void Manager::UpdateService(const ServiceRefPtr &to_update) {
722 CHECK(to_update);
Paul Stewart03dba0b2011-08-22 16:32:45 -0700723 LOG(INFO) << "Service " << to_update->UniqueName() << " updated;"
Gaurav Shahc6d6c722011-11-17 18:59:39 -0800724 << " state: " << Service::ConnectStateToString(to_update->state())
725 << " failure: "
726 << Service::ConnectFailureToString(to_update->failure());
Ben Chanfad4a0b2012-04-18 15:49:59 -0700727 SLOG(Manager, 2) << "IsConnected(): " << to_update->IsConnected();
728 SLOG(Manager, 2) << "IsConnecting(): " << to_update->IsConnecting();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800729 if (to_update->IsConnected()) {
Thieu Led4e9e552012-02-16 16:26:07 -0800730 bool originally_favorite = to_update->favorite();
mukesh agrawal00917ce2011-11-22 23:56:55 +0000731 to_update->MakeFavorite();
Paul Stewart10ccbb32012-04-26 15:59:30 -0700732 if (IsServiceEphemeral(to_update)) {
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800733 if (profiles_.empty()) {
734 LOG(ERROR) << "Cannot assign profile to service: no profiles exist!";
735 } else {
736 MoveServiceToProfile(to_update, profiles_.back());
737 }
Thieu Led4e9e552012-02-16 16:26:07 -0800738 } else if (!originally_favorite) {
739 // Persists the updated favorite setting in the profile.
740 to_update->SaveToCurrentProfile();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800741 }
742 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700743 SortServices();
Paul Stewart03dba0b2011-08-22 16:32:45 -0700744}
745
Paul Stewartfdd16072011-09-16 12:41:35 -0700746void Manager::FilterByTechnology(Technology::Identifier tech,
Chris Masonec1e50412011-06-07 13:04:53 -0700747 vector<DeviceRefPtr> *found) {
Chris Masone9be4a9d2011-05-16 15:44:09 -0700748 CHECK(found);
Chris Masonec1e50412011-06-07 13:04:53 -0700749 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700750 for (it = devices_.begin(); it != devices_.end(); ++it) {
751 if ((*it)->TechnologyIs(tech))
752 found->push_back(*it);
753 }
754}
755
Paul Stewart22aa71b2011-09-16 12:15:11 -0700756ServiceRefPtr Manager::FindService(const string& name) {
Chris Masonec1e50412011-06-07 13:04:53 -0700757 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700758 for (it = services_.begin(); it != services_.end(); ++it) {
Chris Masone6791a432011-07-12 13:23:19 -0700759 if (name == (*it)->UniqueName())
Chris Masonee0dea762011-06-09 09:06:03 -0700760 return *it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700761 }
Chris Masonee0dea762011-06-09 09:06:03 -0700762 return NULL;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700763}
764
mukesh agrawal2366eed2012-03-20 18:21:50 -0700765void Manager::HelpRegisterConstDerivedRpcIdentifiers(
766 const string &name,
767 RpcIdentifiers(Manager::*get)(Error *)) {
768 store_.RegisterDerivedRpcIdentifiers(
769 name,
770 RpcIdentifiersAccessor(
771 new CustomAccessor<Manager, RpcIdentifiers>(this, get, NULL)));
772}
773
mukesh agrawalffa3d042011-10-06 15:26:10 -0700774void Manager::HelpRegisterDerivedString(
775 const string &name,
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800776 string(Manager::*get)(Error *),
mukesh agrawalffa3d042011-10-06 15:26:10 -0700777 void(Manager::*set)(const string&, Error *)) {
Chris Masone27c4aa52011-07-02 13:10:14 -0700778 store_.RegisterDerivedString(
779 name,
780 StringAccessor(new CustomAccessor<Manager, string>(this, get, set)));
Chris Masoneb925cc82011-06-22 15:39:57 -0700781}
782
mukesh agrawalffa3d042011-10-06 15:26:10 -0700783void Manager::HelpRegisterDerivedStrings(
784 const string &name,
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800785 Strings(Manager::*get)(Error *),
mukesh agrawalffa3d042011-10-06 15:26:10 -0700786 void(Manager::*set)(const Strings &, Error *)) {
Chris Masone27c4aa52011-07-02 13:10:14 -0700787 store_.RegisterDerivedStrings(
788 name,
789 StringsAccessor(new CustomAccessor<Manager, Strings>(this, get, set)));
Chris Masoneb925cc82011-06-22 15:39:57 -0700790}
791
Paul Stewart22aa71b2011-09-16 12:15:11 -0700792void Manager::SortServices() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700793 SLOG(Manager, 4) << "In " << __func__;
Thieu Lea20cbc22012-01-09 22:01:43 +0000794 ServiceRefPtr default_service;
795
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800796 if (!services_.empty()) {
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700797 // Keep track of the service that is the candidate for the default
798 // service. We have not yet tested to see if this service has a
799 // connection.
Thieu Lea20cbc22012-01-09 22:01:43 +0000800 default_service = services_[0];
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800801 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700802 sort(services_.begin(), services_.end(), ServiceSorter(technology_order_));
Paul Stewarta41e38d2011-11-11 07:47:29 -0800803
804 vector<string> service_paths;
805 vector<ServiceRefPtr>::iterator it;
806 for (it = services_.begin(); it != services_.end(); ++it) {
807 if ((*it)->IsVisible()) {
808 service_paths.push_back((*it)->GetRpcIdentifier());
809 }
810 }
811 adaptor_->EmitRpcIdentifierArrayChanged(flimflam::kServicesProperty,
812 service_paths);
Gaurav Shah435de2c2011-11-17 19:01:07 -0800813
814 Error error;
815 adaptor_->EmitStringsChanged(flimflam::kConnectedTechnologiesProperty,
816 ConnectedTechnologies(&error));
817 adaptor_->EmitStringChanged(flimflam::kDefaultTechnologyProperty,
818 DefaultTechnology(&error));
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800819
820 if (!services_.empty()) {
Thieu Lea20cbc22012-01-09 22:01:43 +0000821 ConnectionRefPtr default_connection = default_service->connection();
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800822 if (default_connection.get() &&
823 (services_[0]->connection().get() != default_connection.get())) {
824 default_connection->SetIsDefault(false);
825 }
826 if (services_[0]->connection().get()) {
827 services_[0]->connection()->SetIsDefault(true);
Thieu Lea20cbc22012-01-09 22:01:43 +0000828 default_service = services_[0];
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700829 } else {
830 default_service = NULL;
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800831 }
832 }
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700833 metrics_->NotifyDefaultServiceChanged(default_service);
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800834
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000835 AutoConnect();
836}
837
Paul Stewart75225512012-01-26 22:51:33 -0800838bool Manager::MatchProfileWithService(const ServiceRefPtr &service) {
839 vector<ProfileRefPtr>::reverse_iterator it;
840 for (it = profiles_.rbegin(); it != profiles_.rend(); ++it) {
841 if ((*it)->ConfigureService(service)) {
842 break;
843 }
844 }
845 if (it == profiles_.rend()) {
846 ephemeral_profile_->AdoptService(service);
847 return false;
848 }
849 return true;
850}
851
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000852void Manager::AutoConnect() {
853 // We might be called in the middle of another request (e.g., as a
854 // consequence of Service::SetState calling UpdateService). To avoid
855 // re-entrancy issues in dbus-c++, defer to the event loop.
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500856 dispatcher_->PostTask(Bind(&Manager::AutoConnectTask, AsWeakPtr()));
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000857}
858
859void Manager::AutoConnectTask() {
860 if (services_.empty()) {
861 LOG(INFO) << "No services.";
862 return;
863 }
864
Ben Chanfad4a0b2012-04-18 15:49:59 -0700865 if (SLOG_IS_ON(Manager, 4)) {
866 SLOG(Manager, 4) << "Sorted service list: ";
mukesh agrawalddc378f2012-02-17 18:26:20 -0800867 for (size_t i = 0; i < services_.size(); ++i) {
868 ServiceRefPtr service = services_[i];
869 const char *compare_reason = NULL;
870 if (i + 1 < services_.size()) {
871 Service::Compare(
872 service, services_[i+1], technology_order_, &compare_reason);
873 } else {
mukesh agrawalbf14e942012-03-02 14:36:34 -0800874 compare_reason = "last";
mukesh agrawalddc378f2012-02-17 18:26:20 -0800875 }
Ben Chanfad4a0b2012-04-18 15:49:59 -0700876 SLOG(Manager, 4) << "Service " << service->friendly_name()
877 << " IsConnected: " << service->IsConnected()
878 << " IsConnecting: " << service->IsConnecting()
879 << " IsFailed: " << service->IsFailed()
880 << " connectable: " << service->connectable()
881 << " auto_connect: " << service->auto_connect()
882 << " favorite: " << service->favorite()
883 << " priority: " << service->priority()
884 << " security_level: " << service->security_level()
885 << " strength: " << service->strength()
886 << " UniqueName: " << service->UniqueName()
887 << " sorted: " << compare_reason;
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000888 }
889 }
890
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800891 // Perform auto-connect.
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000892 for (vector<ServiceRefPtr>::iterator it = services_.begin();
893 it != services_.end(); ++it) {
894 if ((*it)->auto_connect()) {
mukesh agrawal592516d2012-01-12 14:01:00 -0800895 LOG(INFO) << "Requesting autoconnect to service "
896 << (*it)->friendly_name() << ".";
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000897 (*it)->AutoConnect();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800898 }
899 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700900}
901
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800902string Manager::CalculateState(Error */*error*/) {
Gary Morain028545d2012-04-07 14:55:52 -0700903 // |services_| is sorted such that connected services are first.
904 if (!services_.empty() &&
905 services_.front()->IsConnected()) {
906 return flimflam::kStateOnline;
907 }
Chris Masoneb925cc82011-06-22 15:39:57 -0700908 return flimflam::kStateOffline;
909}
910
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800911vector<string> Manager::AvailableTechnologies(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -0800912 set<string> unique_technologies;
913 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
914 it != devices_.end(); ++it) {
915 unique_technologies.insert(
916 Technology::NameFromIdentifier((*it)->technology()));
917 }
918 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -0700919}
920
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800921vector<string> Manager::ConnectedTechnologies(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -0800922 set<string> unique_technologies;
923 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
924 it != devices_.end(); ++it) {
925 if ((*it)->IsConnected())
926 unique_technologies.insert(
927 Technology::NameFromIdentifier((*it)->technology()));
928 }
929 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -0700930}
931
Gaurav Shah435de2c2011-11-17 19:01:07 -0800932string Manager::DefaultTechnology(Error *error) {
933 return (!services_.empty() && services_[0]->IsConnected()) ?
934 services_[0]->GetTechnologyString(error) : "";
Chris Masoneb925cc82011-06-22 15:39:57 -0700935}
936
Eric Shienbrood9a245532012-03-07 14:20:39 -0500937vector<string> Manager::EnabledTechnologies(Error */*error*/) {
938 set<string> unique_technologies;
939 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
940 it != devices_.end(); ++it) {
941 if ((*it)->enabled())
942 unique_technologies.insert(
943 Technology::NameFromIdentifier((*it)->technology()));
944 }
945 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -0700946}
947
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800948vector<string> Manager::EnumerateDevices(Error */*error*/) {
Chris Masone3c3f6a12011-07-01 10:01:41 -0700949 vector<string> device_rpc_ids;
950 for (vector<DeviceRefPtr>::const_iterator it = devices_.begin();
951 it != devices_.end();
952 ++it) {
953 device_rpc_ids.push_back((*it)->GetRpcIdentifier());
954 }
955 return device_rpc_ids;
956}
957
Paul Stewart1b253142012-01-26 14:05:52 -0800958vector<string> Manager::EnumerateProfiles(Error */*error*/) {
959 vector<string> profile_rpc_ids;
960 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
961 it != profiles_.end();
962 ++it) {
963 profile_rpc_ids.push_back((*it)->GetRpcIdentifier());
964 }
965 return profile_rpc_ids;
966}
967
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800968vector<string> Manager::EnumerateAvailableServices(Error */*error*/) {
Chris Masone3c3f6a12011-07-01 10:01:41 -0700969 vector<string> service_rpc_ids;
970 for (vector<ServiceRefPtr>::const_iterator it = services_.begin();
971 it != services_.end();
972 ++it) {
973 service_rpc_ids.push_back((*it)->GetRpcIdentifier());
974 }
975 return service_rpc_ids;
976}
977
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800978vector<string> Manager::EnumerateWatchedServices(Error *error) {
Chris Masone6791a432011-07-12 13:23:19 -0700979 // TODO(cmasone): Filter this list for services in appropriate states.
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800980 return EnumerateAvailableServices(error);
Chris Masone3c3f6a12011-07-01 10:01:41 -0700981}
982
Paul Stewart1b253142012-01-26 14:05:52 -0800983string Manager::GetActiveProfileRpcIdentifier(Error */*error*/) {
984 return ActiveProfile()->GetRpcIdentifier();
Chris Masone7aa5f902011-07-11 11:13:35 -0700985}
986
Paul Stewart10e9e4e2012-04-26 19:46:28 -0700987string Manager::GetCheckPortalList(Error */*error*/) {
988 return use_startup_portal_list_ ? startup_portal_list_ :
989 props_.check_portal_list;
990}
991
992void Manager::SetCheckPortalList(const string &portal_list, Error *error) {
993 props_.check_portal_list = portal_list;
994 use_startup_portal_list_ = false;
995}
996
mukesh agrawal32399322011-09-01 10:53:43 -0700997// called via RPC (e.g., from ManagerDBusAdaptor)
Darin Petkovb65c2452012-02-23 15:17:06 +0100998ServiceRefPtr Manager::GetService(const KeyValueStore &args, Error *error) {
Paul Stewart13ed2252012-03-21 12:52:46 -0700999 if (args.ContainsString(flimflam::kGuidProperty)) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001000 SLOG(Manager, 2) << __func__ << ": searching by GUID";
Paul Stewart13ed2252012-03-21 12:52:46 -07001001 ServiceRefPtr service =
1002 GetServiceWithGUID(args.GetString(flimflam::kGuidProperty), NULL);
1003 if (service) {
Paul Stewartcb59fed2012-03-21 21:14:46 -07001004 service->Configure(args, error);
Paul Stewart13ed2252012-03-21 12:52:46 -07001005 return service;
1006 }
1007 }
1008
Darin Petkovb65c2452012-02-23 15:17:06 +01001009 if (!args.ContainsString(flimflam::kTypeProperty)) {
Paul Stewart7f61e522012-03-22 11:13:45 -07001010 Error::PopulateAndLog(error, Error::kInvalidArguments, kErrorTypeRequired);
Darin Petkovb65c2452012-02-23 15:17:06 +01001011 return NULL;
1012 }
1013
1014 string type = args.GetString(flimflam::kTypeProperty);
1015 if (type == flimflam::kTypeWifi) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001016 SLOG(Manager, 2) << __func__ << ": getting WiFi Service";
Darin Petkovb65c2452012-02-23 15:17:06 +01001017 return GetWifiService(args, error);
1018 }
1019 if (type == flimflam::kTypeVPN) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001020 SLOG(Manager, 2) << __func__ << ": getting VPN Service";
Darin Petkov33af05c2012-02-28 10:10:30 +01001021 return vpn_provider_.GetService(args, error);
Darin Petkovb65c2452012-02-23 15:17:06 +01001022 }
1023 error->Populate(Error::kNotSupported, kErrorUnsupportedServiceType);
1024 return NULL;
1025}
1026
mukesh agrawal7a4e4002011-09-06 11:26:05 -07001027WiFiServiceRefPtr Manager::GetWifiService(const KeyValueStore &args,
1028 Error *error) {
Paul Stewarta41e38d2011-11-11 07:47:29 -08001029 vector<DeviceRefPtr> wifi_devices;
Paul Stewart22aa71b2011-09-16 12:15:11 -07001030 FilterByTechnology(Technology::kWifi, &wifi_devices);
mukesh agrawal7a4e4002011-09-06 11:26:05 -07001031 if (wifi_devices.empty()) {
Darin Petkovb65c2452012-02-23 15:17:06 +01001032 error->Populate(Error::kInvalidArguments, kErrorNoDevice);
mukesh agrawal7a4e4002011-09-06 11:26:05 -07001033 return NULL;
1034 } else {
1035 WiFi *wifi = dynamic_cast<WiFi *>(wifi_devices.front().get());
1036 CHECK(wifi);
1037 return wifi->GetService(args, error);
1038 }
1039}
1040
Paul Stewart7f61e522012-03-22 11:13:45 -07001041// called via RPC (e.g., from ManagerDBusAdaptor)
1042void Manager::ConfigureService(const KeyValueStore &args, Error *error) {
1043 ProfileRefPtr profile = ActiveProfile();
1044 bool profile_specified = args.ContainsString(flimflam::kProfileProperty);
1045 if (profile_specified) {
1046 string profile_rpcid = args.GetString(flimflam::kProfileProperty);
1047 profile = LookupProfileByRpcIdentifier(profile_rpcid);
1048 if (!profile) {
1049 Error::PopulateAndLog(error, Error::kInvalidArguments,
1050 "Invalid profile name " + profile_rpcid);
1051 return;
1052 }
1053 }
1054
1055 ServiceRefPtr service = GetService(args, error);
1056 if (error->IsFailure() || !service) {
1057 LOG(ERROR) << "GetService failed; returning upstream error.";
1058 return;
1059 }
1060
1061 // Overwrte the profile data with the resulting configured service.
1062 if (!profile->UpdateService(service)) {
1063 Error::PopulateAndLog(error, Error::kInternalError,
1064 "Unable to save service to profile");
1065 return;
1066 }
1067
1068 if (HasService(service)) {
1069 // If the service has been registered (it may not be -- as is the case
1070 // with invisible WiFi networks), we can now transfer the service between
1071 // profiles.
Paul Stewart10ccbb32012-04-26 15:59:30 -07001072 if (IsServiceEphemeral(service) ||
Paul Stewart7f61e522012-03-22 11:13:45 -07001073 (profile_specified && service->profile() != profile)) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001074 SLOG(Manager, 2) << "Moving service to profile "
1075 << profile->GetFriendlyName();
Paul Stewart7f61e522012-03-22 11:13:45 -07001076 if (!MoveServiceToProfile(service, profile)) {
1077 Error::PopulateAndLog(error, Error::kInternalError,
1078 "Unable to move service to profile");
1079 }
1080 }
1081 }
Paul Stewart4357f4e2012-04-26 17:39:26 -07001082
1083 // Notify the service that a profile has been configured for it.
1084 service->OnProfileConfigured();
Paul Stewart7f61e522012-03-22 11:13:45 -07001085}
1086
Paul Stewartc681fa02012-03-02 19:40:04 -08001087void Manager::RecheckPortal(Error */*error*/) {
1088 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1089 it != devices_.end(); ++it) {
1090 if ((*it)->RequestPortalDetection()) {
1091 // Only start Portal Detection on the device with the default connection.
1092 // We will get a "true" return value when we've found that device, and
1093 // can end our loop early as a result.
1094 break;
1095 }
1096 }
1097}
1098
Paul Stewartd215af62012-04-24 23:25:50 -07001099void Manager::RecheckPortalOnService(const ServiceRefPtr &service) {
1100 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1101 it != devices_.end(); ++it) {
1102 if ((*it)->IsConnectedToService(service)) {
1103 // As opposed to RecheckPortal() above, we explicitly stop and then
1104 // restart portal detection, since the service to recheck was explicitly
1105 // specified.
1106 (*it)->RestartPortalDetection();
1107 break;
1108 }
1109 }
1110}
1111
mukesh agrawal7a4e4002011-09-06 11:26:05 -07001112// called via RPC (e.g., from ManagerDBusAdaptor)
Paul Stewart22aa71b2011-09-16 12:15:11 -07001113void Manager::RequestScan(const string &technology, Error *error) {
mukesh agrawal32399322011-09-01 10:53:43 -07001114 if (technology == flimflam::kTypeWifi || technology == "") {
1115 vector<DeviceRefPtr> wifi_devices;
Paul Stewartfdd16072011-09-16 12:41:35 -07001116 FilterByTechnology(Technology::kWifi, &wifi_devices);
mukesh agrawal32399322011-09-01 10:53:43 -07001117
1118 for (vector<DeviceRefPtr>::iterator it = wifi_devices.begin();
1119 it != wifi_devices.end();
1120 ++it) {
Darin Petkovc0865312011-09-16 15:31:20 -07001121 (*it)->Scan(error);
mukesh agrawal32399322011-09-01 10:53:43 -07001122 }
1123 } else {
1124 // TODO(quiche): support scanning for other technologies?
Paul Stewartbe005172011-11-02 18:10:29 -07001125 Error::PopulateAndLog(error, Error::kInvalidArguments,
1126 "Unrecognized technology " + technology);
mukesh agrawal32399322011-09-01 10:53:43 -07001127 }
1128}
1129
Paul Stewart22aa71b2011-09-16 12:15:11 -07001130string Manager::GetTechnologyOrder() {
1131 vector<string> technology_names;
1132 for (vector<Technology::Identifier>::iterator it = technology_order_.begin();
1133 it != technology_order_.end();
1134 ++it) {
1135 technology_names.push_back(Technology::NameFromIdentifier(*it));
1136 }
1137
1138 return JoinString(technology_names, ',');
1139}
1140
1141void Manager::SetTechnologyOrder(const string &order, Error *error) {
1142 vector<Technology::Identifier> new_order;
Ben Chanfad4a0b2012-04-18 15:49:59 -07001143 SLOG(Manager, 2) << "Setting technology order to " << order;
Paul Stewart20088d82012-02-16 06:58:55 -08001144 if (!Technology::GetTechnologyVectorFromString(order, &new_order, error)) {
1145 return;
Paul Stewart22aa71b2011-09-16 12:15:11 -07001146 }
1147
1148 technology_order_ = new_order;
1149 SortServices();
1150}
1151
Paul Stewart75897df2011-04-27 09:05:53 -07001152} // namespace shill