blob: 015aa35df3adc120102ce308be7fada766a60cf8 [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),
mukesh agrawal8a3188d2011-12-01 20:56:44 +000080 glib_(glib) {
Chris Masone7aa5f902011-07-11 11:13:35 -070081 HelpRegisterDerivedString(flimflam::kActiveProfileProperty,
Paul Stewart1b253142012-01-26 14:05:52 -080082 &Manager::GetActiveProfileRpcIdentifier,
Chris Masone7aa5f902011-07-11 11:13:35 -070083 NULL);
Chris Masone27c4aa52011-07-02 13:10:14 -070084 HelpRegisterDerivedStrings(flimflam::kAvailableTechnologiesProperty,
85 &Manager::AvailableTechnologies,
86 NULL);
Chris Masone88cbd5f2011-07-03 14:30:04 -070087 store_.RegisterString(flimflam::kCheckPortalListProperty,
88 &props_.check_portal_list);
Chris Masone27c4aa52011-07-02 13:10:14 -070089 HelpRegisterDerivedStrings(flimflam::kConnectedTechnologiesProperty,
90 &Manager::ConnectedTechnologies,
91 NULL);
Chris Masone88cbd5f2011-07-03 14:30:04 -070092 store_.RegisterString(flimflam::kCountryProperty, &props_.country);
Chris Masone27c4aa52011-07-02 13:10:14 -070093 HelpRegisterDerivedString(flimflam::kDefaultTechnologyProperty,
94 &Manager::DefaultTechnology,
95 NULL);
Chris Masone27c4aa52011-07-02 13:10:14 -070096 HelpRegisterDerivedStrings(flimflam::kDevicesProperty,
97 &Manager::EnumerateDevices,
98 NULL);
Chris Masone88cbd5f2011-07-03 14:30:04 -070099 HelpRegisterDerivedStrings(flimflam::kEnabledTechnologiesProperty,
100 &Manager::EnabledTechnologies,
101 NULL);
102 store_.RegisterBool(flimflam::kOfflineModeProperty, &props_.offline_mode);
103 store_.RegisterString(flimflam::kPortalURLProperty, &props_.portal_url);
Paul Stewartc681fa02012-03-02 19:40:04 -0800104 store_.RegisterInt32(kPortalCheckIntervalProperty,
105 &props_.portal_check_interval_seconds);
Paul Stewart1b253142012-01-26 14:05:52 -0800106 HelpRegisterDerivedStrings(flimflam::kProfilesProperty,
107 &Manager::EnumerateProfiles,
108 NULL);
Paul Stewartc681fa02012-03-02 19:40:04 -0800109 store_.RegisterString(kHostNameProperty, &props_.host_name);
Chris Masone88cbd5f2011-07-03 14:30:04 -0700110 HelpRegisterDerivedString(flimflam::kStateProperty,
111 &Manager::CalculateState,
112 NULL);
mukesh agrawal2366eed2012-03-20 18:21:50 -0700113 HelpRegisterConstDerivedRpcIdentifiers(flimflam::kServicesProperty,
114 &Manager::EnumerateAvailableServices);
Chris Masone27c4aa52011-07-02 13:10:14 -0700115 HelpRegisterDerivedStrings(flimflam::kServiceWatchListProperty,
116 &Manager::EnumerateWatchedServices,
117 NULL);
Chris Masone3c3f6a12011-07-01 10:01:41 -0700118
mukesh agrawal84de5d22012-02-17 19:29:15 -0800119 // Set default technology order "by hand", to avoid invoking side
120 // effects of SetTechnologyOrder.
121 technology_order_.push_back(
Darin Petkov2f903b32012-04-18 12:56:43 +0200122 Technology::IdentifierFromName(flimflam::kTypeVPN));
123 technology_order_.push_back(
mukesh agrawal84de5d22012-02-17 19:29:15 -0800124 Technology::IdentifierFromName(flimflam::kTypeEthernet));
125 technology_order_.push_back(
126 Technology::IdentifierFromName(flimflam::kTypeWifi));
127 technology_order_.push_back(
128 Technology::IdentifierFromName(flimflam::kTypeCellular));
129
Ben Chanfad4a0b2012-04-18 15:49:59 -0700130 SLOG(Manager, 2) << "Manager initialized.";
Paul Stewart75897df2011-04-27 09:05:53 -0700131}
132
Chris Masone6791a432011-07-12 13:23:19 -0700133Manager::~Manager() {
Chris Masone9d779932011-08-25 16:33:41 -0700134 profiles_.clear();
Chris Masone6791a432011-07-12 13:23:19 -0700135}
Paul Stewart75897df2011-04-27 09:05:53 -0700136
mukesh agrawal8f317b62011-07-15 11:53:23 -0700137void Manager::AddDeviceToBlackList(const string &device_name) {
138 device_info_.AddDeviceToBlackList(device_name);
139}
140
Paul Stewart75897df2011-04-27 09:05:53 -0700141void Manager::Start() {
Paul Stewart0af98bf2011-05-10 17:38:08 -0700142 LOG(INFO) << "Manager started.";
Paul Stewarte6132022011-08-16 09:11:02 -0700143
Gary Morainac1bdb42012-02-16 17:42:29 -0800144 power_manager_.reset(new PowerManager(ProxyFactory::GetInstance()));
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500145 // TODO(ers): weak ptr for metrics_?
146 PowerManager::PowerStateCallback cb =
147 Bind(&Metrics::NotifyPowerStateChange, Unretained(metrics_));
Thieu Leb84ba342012-03-02 15:15:19 -0800148 power_manager_->AddStateChangeCallback(Metrics::kMetricPowerManagerKey, cb);
149
Chris Masone2ae797d2011-08-23 20:41:00 -0700150 CHECK(file_util::CreateDirectory(run_path_)) << run_path_.value();
Paul Stewarte6132022011-08-16 09:11:02 -0700151 Resolver::GetInstance()->set_path(run_path_.Append("resolv.conf"));
Chris Masone2ae797d2011-08-23 20:41:00 -0700152
Gaurav Shah71354762011-11-28 19:22:49 -0800153 InitializeProfiles();
Paul Stewart75897df2011-04-27 09:05:53 -0700154 running_ = true;
Chris Masone413a3192011-05-09 17:10:05 -0700155 adaptor_->UpdateRunning();
Paul Stewart0af98bf2011-05-10 17:38:08 -0700156 device_info_.Start();
Darin Petkov887f2982011-07-14 16:10:17 -0700157 modem_info_.Start();
Darin Petkov33af05c2012-02-28 10:10:30 +0100158 vpn_provider_.Start();
Paul Stewart75897df2011-04-27 09:05:53 -0700159}
160
161void Manager::Stop() {
162 running_ = false;
Chris Masone9d779932011-08-25 16:33:41 -0700163 // Persist profile, device, service information to disk.
164 vector<ProfileRefPtr>::iterator it;
165 for (it = profiles_.begin(); it != profiles_.end(); ++it) {
Paul Stewartd0a3b812012-03-28 22:48:22 -0700166 // Since this happens in a loop, the current manager state is stored to
167 // all default profiles in the stack. This is acceptable because the
168 // only time multiple default profiles are loaded are during autotests.
Chris Masone6515aab2011-10-12 16:19:09 -0700169 (*it)->Save();
Chris Masone9d779932011-08-25 16:33:41 -0700170 }
Chris Masone9d779932011-08-25 16:33:41 -0700171
Thieu Le1271d682011-11-02 22:48:19 +0000172 vector<ServiceRefPtr>::iterator services_it;
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000173 Error e;
Thieu Le1271d682011-11-02 22:48:19 +0000174 for (services_it = services_.begin(); services_it != services_.end();
175 ++services_it) {
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000176 (*services_it)->Disconnect(&e);
Thieu Le1271d682011-11-02 22:48:19 +0000177 }
178
Chris Masone413a3192011-05-09 17:10:05 -0700179 adaptor_->UpdateRunning();
Darin Petkov33af05c2012-02-28 10:10:30 +0100180 vpn_provider_.Stop();
Darin Petkov887f2982011-07-14 16:10:17 -0700181 modem_info_.Stop();
182 device_info_.Stop();
Thieu Leb84ba342012-03-02 15:15:19 -0800183
184 // Some unit tests do not call Manager::Start().
185 if (power_manager_.get())
186 power_manager_->RemoveStateChangeCallback(Metrics::kMetricPowerManagerKey);
Paul Stewart75897df2011-04-27 09:05:53 -0700187}
188
Gaurav Shah71354762011-11-28 19:22:49 -0800189void Manager::InitializeProfiles() {
190 DCHECK(profiles_.empty());
191 // The default profile must go first on the stack.
192 CHECK(file_util::CreateDirectory(storage_path_)) << storage_path_.value();
Paul Stewart870523b2012-01-11 17:00:42 -0800193 scoped_refptr<DefaultProfile>
194 default_profile(new DefaultProfile(control_interface_,
Gaurav Shah71354762011-11-28 19:22:49 -0800195 this,
196 storage_path_,
Paul Stewartd0a3b812012-03-28 22:48:22 -0700197 DefaultProfile::kDefaultId,
Gaurav Shah71354762011-11-28 19:22:49 -0800198 props_));
Paul Stewart870523b2012-01-11 17:00:42 -0800199 CHECK(default_profile->InitStorage(glib_, Profile::kCreateOrOpenExisting,
200 NULL));
201 CHECK(default_profile->LoadManagerProperties(&props_));
202 profiles_.push_back(default_profile.release());
Gaurav Shah71354762011-11-28 19:22:49 -0800203 Error error;
Paul Stewart19c871d2011-12-15 16:10:13 -0800204 string path;
Gaurav Shah71354762011-11-28 19:22:49 -0800205 for (vector<string>::iterator it = startup_profiles_.begin();
206 it != startup_profiles_.end(); ++it)
Paul Stewart19c871d2011-12-15 16:10:13 -0800207 PushProfile(*it, &path, &error);
Gaurav Shah71354762011-11-28 19:22:49 -0800208}
209
Paul Stewart19c871d2011-12-15 16:10:13 -0800210void Manager::CreateProfile(const string &name, string *path, Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700211 SLOG(Manager, 2) << __func__ << " " << name;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700212 Profile::Identifier ident;
213 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700214 Error::PopulateAndLog(error, Error::kInvalidArguments,
215 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700216 return;
217 }
Paul Stewartd0a3b812012-03-28 22:48:22 -0700218
219 ProfileRefPtr profile;
220 if (ident.user.empty()) {
221 profile = new DefaultProfile(control_interface_,
222 this,
223 storage_path_,
224 ident.identifier,
225 props_);
226 } else {
227 profile = new Profile(control_interface_,
228 this,
229 ident,
230 user_storage_format_,
Paul Stewarte73d05c2012-03-29 16:26:05 -0700231 false);
Paul Stewartd0a3b812012-03-28 22:48:22 -0700232 }
233
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700234 if (!profile->InitStorage(glib_, Profile::kCreateNew, error)) {
Paul Stewart19c871d2011-12-15 16:10:13 -0800235 // |error| will have been populated by InitStorage().
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700236 return;
237 }
238
239 // Save profile data out, and then let the scoped pointer fall out of scope.
240 if (!profile->Save()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700241 Error::PopulateAndLog(error, Error::kInternalError,
242 "Profile name " + name + " could not be saved");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700243 return;
244 }
Paul Stewart19c871d2011-12-15 16:10:13 -0800245
246 *path = profile->GetRpcIdentifier();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700247}
248
Paul Stewart19c871d2011-12-15 16:10:13 -0800249void Manager::PushProfile(const string &name, string *path, Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700250 SLOG(Manager, 2) << __func__ << " " << name;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700251 Profile::Identifier ident;
252 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700253 Error::PopulateAndLog(error, Error::kInvalidArguments,
254 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700255 return;
256 }
257
258 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
259 it != profiles_.end();
260 ++it) {
261 if ((*it)->MatchesIdentifier(ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700262 Error::PopulateAndLog(error, Error::kAlreadyExists,
263 "Profile name " + name + " is already on stack");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700264 return;
265 }
266 }
267
Paul Stewartd0a3b812012-03-28 22:48:22 -0700268 ProfileRefPtr profile;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700269 if (ident.user.empty()) {
Paul Stewartd0a3b812012-03-28 22:48:22 -0700270 // Allow a machine-wide-profile to be pushed on the stack only if the
271 // profile stack is empty, or if the topmost profile on the stack is
272 // also a machine-wide (non-user) profile.
273 if (!profiles_.empty() && !profiles_.back()->GetUser().empty()) {
274 Error::PopulateAndLog(error, Error::kInvalidArguments,
275 "Cannot load non-default global profile " + name +
276 " on top of a user profile");
277 return;
278 }
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700279
Paul Stewartd0a3b812012-03-28 22:48:22 -0700280 scoped_refptr<DefaultProfile>
281 default_profile(new DefaultProfile(control_interface_,
282 this,
283 storage_path_,
284 ident.identifier,
285 props_));
286 if (!default_profile->InitStorage(glib_, Profile::kOpenExisting, error)) {
287 // |error| will have been populated by InitStorage().
288 return;
289 }
290
291 if (!default_profile->LoadManagerProperties(&props_)) {
292 Error::PopulateAndLog(error, Error::kInvalidArguments,
293 "Could not load Manager properties from profile " +
294 name);
295 return;
296 }
297 profile = default_profile;
298 } else {
299 profile = new Profile(control_interface_,
300 this,
301 ident,
302 user_storage_format_,
303 connect_profiles_to_rpc_);
304 if (!profile->InitStorage(glib_, Profile::kOpenExisting, error)) {
305 // |error| will have been populated by InitStorage().
306 return;
307 }
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700308 }
309
Paul Stewarta849a3d2011-11-03 05:54:09 -0700310 profiles_.push_back(profile);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700311
312 // Offer each registered Service the opportunity to join this new Profile.
Paul Stewarta41e38d2011-11-11 07:47:29 -0800313 for (vector<ServiceRefPtr>::iterator it = services_.begin();
314 it != services_.end(); ++it) {
Paul Stewartbba6a5b2011-11-02 18:45:59 -0700315 profile->ConfigureService(*it);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700316 }
317
Paul Stewarta41e38d2011-11-11 07:47:29 -0800318 // Shop the Profile contents around to Devices which can create
319 // non-visible services.
320 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
321 it != devices_.end(); ++it) {
322 profile->ConfigureDevice(*it);
323 }
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800324
Paul Stewart66815332012-04-09 18:09:36 -0700325 // Offer the Profile contents to the VPNProvider which will create
326 // new VPN services if necessary.
327 vpn_provider_.CreateServicesFromProfile(profile);
328
Paul Stewart19c871d2011-12-15 16:10:13 -0800329 *path = profile->GetRpcIdentifier();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800330 SortServices();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700331}
332
333void Manager::PopProfileInternal() {
334 CHECK(!profiles_.empty());
335 ProfileRefPtr active_profile = profiles_.back();
336 profiles_.pop_back();
Paul Stewart75225512012-01-26 22:51:33 -0800337 vector<ServiceRefPtr>::iterator it;
Paul Stewart65512e12012-03-26 18:01:08 -0700338 for (it = services_.begin(); it != services_.end();) {
339 if ((*it)->profile().get() != active_profile.get() ||
340 MatchProfileWithService(*it) ||
341 !UnloadService(&it)) {
342 LOG(ERROR) << "Skipping unload of service";
343 ++it;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700344 }
345 }
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800346 SortServices();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700347}
348
Paul Stewarta41e38d2011-11-11 07:47:29 -0800349void Manager::PopProfile(const string &name, Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700350 SLOG(Manager, 2) << __func__ << " " << name;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700351 Profile::Identifier ident;
352 if (profiles_.empty()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700353 Error::PopulateAndLog(error, Error::kNotFound, "Profile stack is empty");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700354 return;
355 }
356 ProfileRefPtr active_profile = profiles_.back();
357 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700358 Error::PopulateAndLog(error, Error::kInvalidArguments,
359 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700360 return;
361 }
362 if (!active_profile->MatchesIdentifier(ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700363 Error::PopulateAndLog(error, Error::kNotSupported,
364 name + " is not the active profile");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700365 return;
366 }
367 PopProfileInternal();
368}
369
370void Manager::PopAnyProfile(Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700371 SLOG(Manager, 2) << __func__;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700372 Profile::Identifier ident;
373 if (profiles_.empty()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700374 Error::PopulateAndLog(error, Error::kNotFound, "Profile stack is empty");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700375 return;
376 }
377 PopProfileInternal();
378}
379
Paul Stewarte73d05c2012-03-29 16:26:05 -0700380void Manager::RemoveProfile(const string &name, Error *error) {
381 Profile::Identifier ident;
382 if (!Profile::ParseIdentifier(name, &ident)) {
383 Error::PopulateAndLog(error, Error::kInvalidArguments,
384 "Invalid profile name " + name);
385 return;
386 }
387
388 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
389 it != profiles_.end();
390 ++it) {
391 if ((*it)->MatchesIdentifier(ident)) {
392 Error::PopulateAndLog(error, Error::kInvalidArguments,
393 "Cannot remove profile name " + name +
394 " since it is on stack");
395 return;
396 }
397 }
398
399 ProfileRefPtr profile;
400 if (ident.user.empty()) {
401 profile = new DefaultProfile(control_interface_,
402 this,
403 storage_path_,
404 ident.identifier,
405 props_);
406 } else {
407 profile = new Profile(control_interface_,
408 this,
409 ident,
410 user_storage_format_,
411 false);
412 }
413
414
415 // |error| will have been populated if RemoveStorage fails.
416 profile->RemoveStorage(glib_, error);
417
418 return;
419}
420
Paul Stewart75225512012-01-26 22:51:33 -0800421bool Manager::HandleProfileEntryDeletion(const ProfileRefPtr &profile,
422 const std::string &entry_name) {
423 bool moved_services = false;
424 for (vector<ServiceRefPtr>::iterator it = services_.begin();
Paul Stewart65512e12012-03-26 18:01:08 -0700425 it != services_.end();) {
Paul Stewart75225512012-01-26 22:51:33 -0800426 if ((*it)->profile().get() == profile.get() &&
427 (*it)->GetStorageIdentifier() == entry_name) {
428 profile->AbandonService(*it);
Paul Stewart65512e12012-03-26 18:01:08 -0700429 if (MatchProfileWithService(*it) ||
430 !UnloadService(&it)) {
431 ++it;
Paul Stewart75225512012-01-26 22:51:33 -0800432 }
433 moved_services = true;
Paul Stewart65512e12012-03-26 18:01:08 -0700434 } else {
435 ++it;
Paul Stewart75225512012-01-26 22:51:33 -0800436 }
437 }
438 return moved_services;
439}
440
Paul Stewart0756db92012-01-27 08:34:47 -0800441ServiceRefPtr Manager::GetServiceWithStorageIdentifier(
442 const ProfileRefPtr &profile, const std::string &entry_name, Error *error) {
443 for (vector<ServiceRefPtr>::iterator it = services_.begin();
444 it != services_.end(); ++it) {
445 if ((*it)->profile().get() == profile.get() &&
446 (*it)->GetStorageIdentifier() == entry_name) {
447 return *it;
448 }
449 }
450
451 Error::PopulateAndLog(error, Error::kNotFound,
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500452 StringPrintf("Entry %s is not registered in the manager",
453 entry_name.c_str()));
Paul Stewart0756db92012-01-27 08:34:47 -0800454 return NULL;
455}
456
Paul Stewart13ed2252012-03-21 12:52:46 -0700457ServiceRefPtr Manager::GetServiceWithGUID(
458 const std::string &guid, Error *error) {
459 for (vector<ServiceRefPtr>::iterator it = services_.begin();
460 it != services_.end(); ++it) {
461 if ((*it)->guid() == guid) {
462 return *it;
463 }
464 }
465
466 Error::PopulateAndLog(error, Error::kNotFound,
467 StringPrintf("Service wth GUID %s is not registered in the manager",
468 guid.c_str()));
469 return NULL;
470}
471
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700472ServiceRefPtr Manager::GetDefaultService() const {
473 if (services_.empty() || !services_[0]->connection().get()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700474 SLOG(Manager, 2) << "In " << __func__ << ": No default connection exists.";
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700475 return NULL;
476 }
477 return services_[0];
478}
479
Paul Stewart20088d82012-02-16 06:58:55 -0800480bool Manager::IsPortalDetectionEnabled(Technology::Identifier tech) {
481 Error error;
482 vector<Technology::Identifier> portal_technologies;
483 return Technology::GetTechnologyVectorFromString(props_.check_portal_list,
484 &portal_technologies,
485 &error) &&
486 std::find(portal_technologies.begin(), portal_technologies.end(),
487 tech) != portal_technologies.end();
488}
489
Paul Stewart1b253142012-01-26 14:05:52 -0800490const ProfileRefPtr &Manager::ActiveProfile() const {
Eric Shienbroodc74cf9c2012-03-02 15:00:35 -0500491 DCHECK_NE(profiles_.size(), 0U);
Chris Masone7aa5f902011-07-11 11:13:35 -0700492 return profiles_.back();
493}
494
Paul Stewart1b253142012-01-26 14:05:52 -0800495bool Manager::IsActiveProfile(const ProfileRefPtr &profile) const {
496 return (profiles_.size() > 0 &&
497 ActiveProfile().get() == profile.get());
498}
499
Eric Shienbrood9a245532012-03-07 14:20:39 -0500500void Manager::SaveActiveProfile() {
501 if (!profiles_.empty()) {
502 ActiveProfile()->Save();
503 }
504}
505
Chris Masone6515aab2011-10-12 16:19:09 -0700506bool Manager::MoveServiceToProfile(const ServiceRefPtr &to_move,
507 const ProfileRefPtr &destination) {
508 const ProfileRefPtr from = to_move->profile();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700509 SLOG(Manager, 2) << "Moving service "
510 << to_move->UniqueName()
511 << " to profile "
512 << destination->GetFriendlyName()
513 << " from "
514 << from->GetFriendlyName();
Chris Masone6515aab2011-10-12 16:19:09 -0700515 return destination->AdoptService(to_move) &&
516 from->AbandonService(to_move);
Chris Masone6791a432011-07-12 13:23:19 -0700517}
518
Paul Stewart7f61e522012-03-22 11:13:45 -0700519ProfileRefPtr Manager::LookupProfileByRpcIdentifier(
520 const string &profile_rpcid) {
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800521 for (vector<ProfileRefPtr>::iterator it = profiles_.begin();
522 it != profiles_.end();
523 ++it) {
524 if (profile_rpcid == (*it)->GetRpcIdentifier()) {
Paul Stewart7f61e522012-03-22 11:13:45 -0700525 return *it;
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800526 }
527 }
Paul Stewart7f61e522012-03-22 11:13:45 -0700528 return NULL;
529}
530
531void Manager::SetProfileForService(const ServiceRefPtr &to_set,
532 const string &profile_rpcid,
533 Error *error) {
534 ProfileRefPtr profile = LookupProfileByRpcIdentifier(profile_rpcid);
535 if (!profile) {
536 Error::PopulateAndLog(error, Error::kInvalidArguments,
537 StringPrintf("Unknown Profile %s requested for "
538 "Service", profile_rpcid.c_str()));
539 return;
540 }
541
542 if (to_set->profile().get() == profile.get()) {
543 Error::PopulateAndLog(error, Error::kInvalidArguments,
544 "Service is already connected to this profile");
545 } else if (!MoveServiceToProfile(to_set, profile)) {
546 Error::PopulateAndLog(error, Error::kInternalError,
547 "Unable to move service to profile");
548 }
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800549}
550
Eric Shienbrood9a245532012-03-07 14:20:39 -0500551void Manager::EnableTechnology(const std::string &technology_name,
552 Error *error,
553 const ResultCallback &callback) {
554 Technology::Identifier id = Technology::IdentifierFromName(technology_name);
555 if (id == Technology::kUnknown) {
556 error->Populate(Error::kInvalidArguments, "Unknown technology");
557 return;
558 }
559 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
560 it != devices_.end(); ++it) {
561 DeviceRefPtr device = *it;
562 if (device->technology() == id && !device->enabled()) {
563 device->SetEnabledPersistent(true, error, callback);
564 // Continue with other devices even if one fails
565 // TODO(ers): Decide whether an error should be returned
566 // for the overall EnableTechnology operation if some
567 // devices succeed and some fail.
568 }
569 }
570}
571
572void Manager::DisableTechnology(const std::string &technology_name,
573 Error *error,
574 const ResultCallback &callback) {
575 Technology::Identifier id = Technology::IdentifierFromName(technology_name);
576 if (id == Technology::kUnknown) {
577 error->Populate(Error::kInvalidArguments, "Unknown technology");
578 return;
579 }
580 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
581 it != devices_.end(); ++it) {
582 DeviceRefPtr device = *it;
583 if (device->technology() == id && device->enabled()) {
584 device->SetEnabledPersistent(false, 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 DisableTechnology operation if some
588 // devices succeed and some fail.
589 }
590 }
591}
592
593void Manager::UpdateEnabledTechnologies() {
594 Error error;
595 adaptor_->EmitStringsChanged(flimflam::kEnabledTechnologiesProperty,
596 EnabledTechnologies(&error));
597}
598
Chris Masone2b105542011-06-22 10:58:09 -0700599void Manager::RegisterDevice(const DeviceRefPtr &to_manage) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700600 SLOG(Manager, 2) << __func__ << "(" << to_manage->FriendlyName() << ")";
Chris Masonec1e50412011-06-07 13:04:53 -0700601 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700602 for (it = devices_.begin(); it != devices_.end(); ++it) {
Chris Masonec1e50412011-06-07 13:04:53 -0700603 if (to_manage.get() == it->get())
Chris Masone9be4a9d2011-05-16 15:44:09 -0700604 return;
605 }
Chris Masonec1e50412011-06-07 13:04:53 -0700606 devices_.push_back(to_manage);
Paul Stewartf1ce5d22011-05-19 13:10:20 -0700607
Paul Stewarta41e38d2011-11-11 07:47:29 -0800608 // We are applying device properties from the DefaultProfile, and adding
609 // the union of hidden services in all loaded profiles to the device.
Chris Masone6515aab2011-10-12 16:19:09 -0700610 for (vector<ProfileRefPtr>::iterator it = profiles_.begin();
611 it != profiles_.end();
612 ++it) {
Paul Stewarta41e38d2011-11-11 07:47:29 -0800613 // Load device configuration, if any exists, as well as hidden services.
614 (*it)->ConfigureDevice(to_manage);
615
616 // Currently the only profile for which "Save" is implemented is the
617 // DefaultProfile. It iterates over all Devices and stores their state.
618 // We perform the Save now in case the device we have just registered
619 // is new and needs to be added to the stored DefaultProfile.
Chris Masone6515aab2011-10-12 16:19:09 -0700620 (*it)->Save();
621 }
Paul Stewarta41e38d2011-11-11 07:47:29 -0800622
623 // In normal usage, running_ will always be true when we are here, however
624 // unit tests sometimes do things in otherwise invalid states.
Eric Shienbrood9a245532012-03-07 14:20:39 -0500625 if (running_ && to_manage->enabled_persistent())
626 to_manage->SetEnabled(true);
Gaurav Shah435de2c2011-11-17 19:01:07 -0800627
Eric Shienbrood8839a892012-03-29 10:33:48 -0400628 EmitDeviceProperties();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700629}
630
mukesh agrawal5029c6c2011-08-25 11:12:40 -0700631void Manager::DeregisterDevice(const DeviceRefPtr &to_forget) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700632 SLOG(Manager, 2) << __func__ << "(" << to_forget->FriendlyName() << ")";
Chris Masonec1e50412011-06-07 13:04:53 -0700633 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700634 for (it = devices_.begin(); it != devices_.end(); ++it) {
Chris Masonec1e50412011-06-07 13:04:53 -0700635 if (to_forget.get() == it->get()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700636 SLOG(Manager, 2) << "Deregistered device: " << to_forget->UniqueName();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500637 to_forget->SetEnabled(false);
Chris Masone9be4a9d2011-05-16 15:44:09 -0700638 devices_.erase(it);
Eric Shienbrood8839a892012-03-29 10:33:48 -0400639 EmitDeviceProperties();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700640 return;
641 }
642 }
Ben Chanfad4a0b2012-04-18 15:49:59 -0700643 SLOG(Manager, 2) << __func__ << " unknown device: "
644 << to_forget->UniqueName();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700645}
646
Eric Shienbrood8839a892012-03-29 10:33:48 -0400647void Manager::EmitDeviceProperties() {
648 vector<DeviceRefPtr>::iterator it;
649 vector<string> device_paths;
650 for (it = devices_.begin(); it != devices_.end(); ++it) {
651 device_paths.push_back((*it)->GetRpcIdentifier());
652 }
653 adaptor_->EmitRpcIdentifierArrayChanged(flimflam::kDevicesProperty,
654 device_paths);
655 Error error;
656 adaptor_->EmitStringsChanged(flimflam::kAvailableTechnologiesProperty,
657 AvailableTechnologies(&error));
658 adaptor_->EmitStringsChanged(flimflam::kEnabledTechnologiesProperty,
659 EnabledTechnologies(&error));
660}
661
mukesh agrawal4eb4d782011-12-05 17:34:37 +0000662bool Manager::HasService(const ServiceRefPtr &service) {
663 vector<ServiceRefPtr>::iterator it;
664 for (it = services_.begin(); it != services_.end(); ++it) {
665 if ((*it)->UniqueName() == service->UniqueName())
666 return true;
667 }
668 return false;
669}
670
Chris Masone2b105542011-06-22 10:58:09 -0700671void Manager::RegisterService(const ServiceRefPtr &to_manage) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700672 SLOG(Manager, 2) << "In " << __func__ << "(): Registering service "
673 << to_manage->UniqueName();
mukesh agrawald835b202011-10-07 15:26:47 -0700674
Paul Stewart75225512012-01-26 22:51:33 -0800675 MatchProfileWithService(to_manage);
Chris Masone6791a432011-07-12 13:23:19 -0700676
677 // Now add to OUR list.
Chris Masonec1e50412011-06-07 13:04:53 -0700678 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700679 for (it = services_.begin(); it != services_.end(); ++it) {
mukesh agrawald835b202011-10-07 15:26:47 -0700680 CHECK(to_manage->UniqueName() != (*it)->UniqueName());
Chris Masone9be4a9d2011-05-16 15:44:09 -0700681 }
Chris Masonec1e50412011-06-07 13:04:53 -0700682 services_.push_back(to_manage);
Paul Stewart22aa71b2011-09-16 12:15:11 -0700683 SortServices();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700684}
685
Chris Masone6515aab2011-10-12 16:19:09 -0700686void Manager::DeregisterService(const ServiceRefPtr &to_forget) {
Chris Masonec1e50412011-06-07 13:04:53 -0700687 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700688 for (it = services_.begin(); it != services_.end(); ++it) {
Chris Masone6791a432011-07-12 13:23:19 -0700689 if (to_forget->UniqueName() == (*it)->UniqueName()) {
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800690 DCHECK(!(*it)->connection());
Chris Masone9be4a9d2011-05-16 15:44:09 -0700691 services_.erase(it);
Paul Stewart22aa71b2011-09-16 12:15:11 -0700692 SortServices();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700693 return;
694 }
695 }
696}
697
Paul Stewart65512e12012-03-26 18:01:08 -0700698bool Manager::UnloadService(vector<ServiceRefPtr>::iterator *service_iterator) {
699 if (!(**service_iterator)->Unload()) {
700 return false;
701 }
702
703 DCHECK(!(**service_iterator)->connection());
704 *service_iterator = services_.erase(*service_iterator);
705
706 return true;
707}
708
mukesh agrawal00917ce2011-11-22 23:56:55 +0000709void Manager::UpdateService(const ServiceRefPtr &to_update) {
710 CHECK(to_update);
Paul Stewart03dba0b2011-08-22 16:32:45 -0700711 LOG(INFO) << "Service " << to_update->UniqueName() << " updated;"
Gaurav Shahc6d6c722011-11-17 18:59:39 -0800712 << " state: " << Service::ConnectStateToString(to_update->state())
713 << " failure: "
714 << Service::ConnectFailureToString(to_update->failure());
Ben Chanfad4a0b2012-04-18 15:49:59 -0700715 SLOG(Manager, 2) << "IsConnected(): " << to_update->IsConnected();
716 SLOG(Manager, 2) << "IsConnecting(): " << to_update->IsConnecting();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800717 if (to_update->IsConnected()) {
Thieu Led4e9e552012-02-16 16:26:07 -0800718 bool originally_favorite = to_update->favorite();
mukesh agrawal00917ce2011-11-22 23:56:55 +0000719 to_update->MakeFavorite();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800720 if (to_update->profile().get() == ephemeral_profile_.get()) {
721 if (profiles_.empty()) {
722 LOG(ERROR) << "Cannot assign profile to service: no profiles exist!";
723 } else {
724 MoveServiceToProfile(to_update, profiles_.back());
725 }
Thieu Led4e9e552012-02-16 16:26:07 -0800726 } else if (!originally_favorite) {
727 // Persists the updated favorite setting in the profile.
728 to_update->SaveToCurrentProfile();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800729 }
730 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700731 SortServices();
Paul Stewart03dba0b2011-08-22 16:32:45 -0700732}
733
Paul Stewartfdd16072011-09-16 12:41:35 -0700734void Manager::FilterByTechnology(Technology::Identifier tech,
Chris Masonec1e50412011-06-07 13:04:53 -0700735 vector<DeviceRefPtr> *found) {
Chris Masone9be4a9d2011-05-16 15:44:09 -0700736 CHECK(found);
Chris Masonec1e50412011-06-07 13:04:53 -0700737 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700738 for (it = devices_.begin(); it != devices_.end(); ++it) {
739 if ((*it)->TechnologyIs(tech))
740 found->push_back(*it);
741 }
742}
743
Paul Stewart22aa71b2011-09-16 12:15:11 -0700744ServiceRefPtr Manager::FindService(const string& name) {
Chris Masonec1e50412011-06-07 13:04:53 -0700745 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700746 for (it = services_.begin(); it != services_.end(); ++it) {
Chris Masone6791a432011-07-12 13:23:19 -0700747 if (name == (*it)->UniqueName())
Chris Masonee0dea762011-06-09 09:06:03 -0700748 return *it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700749 }
Chris Masonee0dea762011-06-09 09:06:03 -0700750 return NULL;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700751}
752
mukesh agrawal2366eed2012-03-20 18:21:50 -0700753void Manager::HelpRegisterConstDerivedRpcIdentifiers(
754 const string &name,
755 RpcIdentifiers(Manager::*get)(Error *)) {
756 store_.RegisterDerivedRpcIdentifiers(
757 name,
758 RpcIdentifiersAccessor(
759 new CustomAccessor<Manager, RpcIdentifiers>(this, get, NULL)));
760}
761
mukesh agrawalffa3d042011-10-06 15:26:10 -0700762void Manager::HelpRegisterDerivedString(
763 const string &name,
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800764 string(Manager::*get)(Error *),
mukesh agrawalffa3d042011-10-06 15:26:10 -0700765 void(Manager::*set)(const string&, Error *)) {
Chris Masone27c4aa52011-07-02 13:10:14 -0700766 store_.RegisterDerivedString(
767 name,
768 StringAccessor(new CustomAccessor<Manager, string>(this, get, set)));
Chris Masoneb925cc82011-06-22 15:39:57 -0700769}
770
mukesh agrawalffa3d042011-10-06 15:26:10 -0700771void Manager::HelpRegisterDerivedStrings(
772 const string &name,
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800773 Strings(Manager::*get)(Error *),
mukesh agrawalffa3d042011-10-06 15:26:10 -0700774 void(Manager::*set)(const Strings &, Error *)) {
Chris Masone27c4aa52011-07-02 13:10:14 -0700775 store_.RegisterDerivedStrings(
776 name,
777 StringsAccessor(new CustomAccessor<Manager, Strings>(this, get, set)));
Chris Masoneb925cc82011-06-22 15:39:57 -0700778}
779
Paul Stewart22aa71b2011-09-16 12:15:11 -0700780void Manager::SortServices() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700781 SLOG(Manager, 4) << "In " << __func__;
Thieu Lea20cbc22012-01-09 22:01:43 +0000782 ServiceRefPtr default_service;
783
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800784 if (!services_.empty()) {
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700785 // Keep track of the service that is the candidate for the default
786 // service. We have not yet tested to see if this service has a
787 // connection.
Thieu Lea20cbc22012-01-09 22:01:43 +0000788 default_service = services_[0];
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800789 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700790 sort(services_.begin(), services_.end(), ServiceSorter(technology_order_));
Paul Stewarta41e38d2011-11-11 07:47:29 -0800791
792 vector<string> service_paths;
793 vector<ServiceRefPtr>::iterator it;
794 for (it = services_.begin(); it != services_.end(); ++it) {
795 if ((*it)->IsVisible()) {
796 service_paths.push_back((*it)->GetRpcIdentifier());
797 }
798 }
799 adaptor_->EmitRpcIdentifierArrayChanged(flimflam::kServicesProperty,
800 service_paths);
Gaurav Shah435de2c2011-11-17 19:01:07 -0800801
802 Error error;
803 adaptor_->EmitStringsChanged(flimflam::kConnectedTechnologiesProperty,
804 ConnectedTechnologies(&error));
805 adaptor_->EmitStringChanged(flimflam::kDefaultTechnologyProperty,
806 DefaultTechnology(&error));
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800807
808 if (!services_.empty()) {
Thieu Lea20cbc22012-01-09 22:01:43 +0000809 ConnectionRefPtr default_connection = default_service->connection();
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800810 if (default_connection.get() &&
811 (services_[0]->connection().get() != default_connection.get())) {
812 default_connection->SetIsDefault(false);
813 }
814 if (services_[0]->connection().get()) {
815 services_[0]->connection()->SetIsDefault(true);
Thieu Lea20cbc22012-01-09 22:01:43 +0000816 default_service = services_[0];
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700817 } else {
818 default_service = NULL;
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800819 }
820 }
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700821 metrics_->NotifyDefaultServiceChanged(default_service);
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800822
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000823 AutoConnect();
824}
825
Paul Stewart75225512012-01-26 22:51:33 -0800826bool Manager::MatchProfileWithService(const ServiceRefPtr &service) {
827 vector<ProfileRefPtr>::reverse_iterator it;
828 for (it = profiles_.rbegin(); it != profiles_.rend(); ++it) {
829 if ((*it)->ConfigureService(service)) {
830 break;
831 }
832 }
833 if (it == profiles_.rend()) {
834 ephemeral_profile_->AdoptService(service);
835 return false;
836 }
837 return true;
838}
839
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000840void Manager::AutoConnect() {
841 // We might be called in the middle of another request (e.g., as a
842 // consequence of Service::SetState calling UpdateService). To avoid
843 // re-entrancy issues in dbus-c++, defer to the event loop.
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500844 dispatcher_->PostTask(Bind(&Manager::AutoConnectTask, AsWeakPtr()));
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000845}
846
847void Manager::AutoConnectTask() {
848 if (services_.empty()) {
849 LOG(INFO) << "No services.";
850 return;
851 }
852
Ben Chanfad4a0b2012-04-18 15:49:59 -0700853 if (SLOG_IS_ON(Manager, 4)) {
854 SLOG(Manager, 4) << "Sorted service list: ";
mukesh agrawalddc378f2012-02-17 18:26:20 -0800855 for (size_t i = 0; i < services_.size(); ++i) {
856 ServiceRefPtr service = services_[i];
857 const char *compare_reason = NULL;
858 if (i + 1 < services_.size()) {
859 Service::Compare(
860 service, services_[i+1], technology_order_, &compare_reason);
861 } else {
mukesh agrawalbf14e942012-03-02 14:36:34 -0800862 compare_reason = "last";
mukesh agrawalddc378f2012-02-17 18:26:20 -0800863 }
Ben Chanfad4a0b2012-04-18 15:49:59 -0700864 SLOG(Manager, 4) << "Service " << service->friendly_name()
865 << " IsConnected: " << service->IsConnected()
866 << " IsConnecting: " << service->IsConnecting()
867 << " IsFailed: " << service->IsFailed()
868 << " connectable: " << service->connectable()
869 << " auto_connect: " << service->auto_connect()
870 << " favorite: " << service->favorite()
871 << " priority: " << service->priority()
872 << " security_level: " << service->security_level()
873 << " strength: " << service->strength()
874 << " UniqueName: " << service->UniqueName()
875 << " sorted: " << compare_reason;
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000876 }
877 }
878
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800879 // Perform auto-connect.
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000880 for (vector<ServiceRefPtr>::iterator it = services_.begin();
881 it != services_.end(); ++it) {
882 if ((*it)->auto_connect()) {
mukesh agrawal592516d2012-01-12 14:01:00 -0800883 LOG(INFO) << "Requesting autoconnect to service "
884 << (*it)->friendly_name() << ".";
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000885 (*it)->AutoConnect();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800886 }
887 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700888}
889
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800890string Manager::CalculateState(Error */*error*/) {
Gary Morain028545d2012-04-07 14:55:52 -0700891 // |services_| is sorted such that connected services are first.
892 if (!services_.empty() &&
893 services_.front()->IsConnected()) {
894 return flimflam::kStateOnline;
895 }
Chris Masoneb925cc82011-06-22 15:39:57 -0700896 return flimflam::kStateOffline;
897}
898
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800899vector<string> Manager::AvailableTechnologies(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -0800900 set<string> unique_technologies;
901 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
902 it != devices_.end(); ++it) {
903 unique_technologies.insert(
904 Technology::NameFromIdentifier((*it)->technology()));
905 }
906 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -0700907}
908
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800909vector<string> Manager::ConnectedTechnologies(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -0800910 set<string> unique_technologies;
911 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
912 it != devices_.end(); ++it) {
913 if ((*it)->IsConnected())
914 unique_technologies.insert(
915 Technology::NameFromIdentifier((*it)->technology()));
916 }
917 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -0700918}
919
Gaurav Shah435de2c2011-11-17 19:01:07 -0800920string Manager::DefaultTechnology(Error *error) {
921 return (!services_.empty() && services_[0]->IsConnected()) ?
922 services_[0]->GetTechnologyString(error) : "";
Chris Masoneb925cc82011-06-22 15:39:57 -0700923}
924
Eric Shienbrood9a245532012-03-07 14:20:39 -0500925vector<string> Manager::EnabledTechnologies(Error */*error*/) {
926 set<string> unique_technologies;
927 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
928 it != devices_.end(); ++it) {
929 if ((*it)->enabled())
930 unique_technologies.insert(
931 Technology::NameFromIdentifier((*it)->technology()));
932 }
933 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -0700934}
935
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800936vector<string> Manager::EnumerateDevices(Error */*error*/) {
Chris Masone3c3f6a12011-07-01 10:01:41 -0700937 vector<string> device_rpc_ids;
938 for (vector<DeviceRefPtr>::const_iterator it = devices_.begin();
939 it != devices_.end();
940 ++it) {
941 device_rpc_ids.push_back((*it)->GetRpcIdentifier());
942 }
943 return device_rpc_ids;
944}
945
Paul Stewart1b253142012-01-26 14:05:52 -0800946vector<string> Manager::EnumerateProfiles(Error */*error*/) {
947 vector<string> profile_rpc_ids;
948 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
949 it != profiles_.end();
950 ++it) {
951 profile_rpc_ids.push_back((*it)->GetRpcIdentifier());
952 }
953 return profile_rpc_ids;
954}
955
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800956vector<string> Manager::EnumerateAvailableServices(Error */*error*/) {
Chris Masone3c3f6a12011-07-01 10:01:41 -0700957 vector<string> service_rpc_ids;
958 for (vector<ServiceRefPtr>::const_iterator it = services_.begin();
959 it != services_.end();
960 ++it) {
961 service_rpc_ids.push_back((*it)->GetRpcIdentifier());
962 }
963 return service_rpc_ids;
964}
965
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800966vector<string> Manager::EnumerateWatchedServices(Error *error) {
Chris Masone6791a432011-07-12 13:23:19 -0700967 // TODO(cmasone): Filter this list for services in appropriate states.
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800968 return EnumerateAvailableServices(error);
Chris Masone3c3f6a12011-07-01 10:01:41 -0700969}
970
Paul Stewart1b253142012-01-26 14:05:52 -0800971string Manager::GetActiveProfileRpcIdentifier(Error */*error*/) {
972 return ActiveProfile()->GetRpcIdentifier();
Chris Masone7aa5f902011-07-11 11:13:35 -0700973}
974
mukesh agrawal32399322011-09-01 10:53:43 -0700975// called via RPC (e.g., from ManagerDBusAdaptor)
Darin Petkovb65c2452012-02-23 15:17:06 +0100976ServiceRefPtr Manager::GetService(const KeyValueStore &args, Error *error) {
Paul Stewart13ed2252012-03-21 12:52:46 -0700977 if (args.ContainsString(flimflam::kGuidProperty)) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700978 SLOG(Manager, 2) << __func__ << ": searching by GUID";
Paul Stewart13ed2252012-03-21 12:52:46 -0700979 ServiceRefPtr service =
980 GetServiceWithGUID(args.GetString(flimflam::kGuidProperty), NULL);
981 if (service) {
Paul Stewartcb59fed2012-03-21 21:14:46 -0700982 service->Configure(args, error);
Paul Stewart13ed2252012-03-21 12:52:46 -0700983 return service;
984 }
985 }
986
Darin Petkovb65c2452012-02-23 15:17:06 +0100987 if (!args.ContainsString(flimflam::kTypeProperty)) {
Paul Stewart7f61e522012-03-22 11:13:45 -0700988 Error::PopulateAndLog(error, Error::kInvalidArguments, kErrorTypeRequired);
Darin Petkovb65c2452012-02-23 15:17:06 +0100989 return NULL;
990 }
991
992 string type = args.GetString(flimflam::kTypeProperty);
993 if (type == flimflam::kTypeWifi) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700994 SLOG(Manager, 2) << __func__ << ": getting WiFi Service";
Darin Petkovb65c2452012-02-23 15:17:06 +0100995 return GetWifiService(args, error);
996 }
997 if (type == flimflam::kTypeVPN) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700998 SLOG(Manager, 2) << __func__ << ": getting VPN Service";
Darin Petkov33af05c2012-02-28 10:10:30 +0100999 return vpn_provider_.GetService(args, error);
Darin Petkovb65c2452012-02-23 15:17:06 +01001000 }
1001 error->Populate(Error::kNotSupported, kErrorUnsupportedServiceType);
1002 return NULL;
1003}
1004
mukesh agrawal7a4e4002011-09-06 11:26:05 -07001005WiFiServiceRefPtr Manager::GetWifiService(const KeyValueStore &args,
1006 Error *error) {
Paul Stewarta41e38d2011-11-11 07:47:29 -08001007 vector<DeviceRefPtr> wifi_devices;
Paul Stewart22aa71b2011-09-16 12:15:11 -07001008 FilterByTechnology(Technology::kWifi, &wifi_devices);
mukesh agrawal7a4e4002011-09-06 11:26:05 -07001009 if (wifi_devices.empty()) {
Darin Petkovb65c2452012-02-23 15:17:06 +01001010 error->Populate(Error::kInvalidArguments, kErrorNoDevice);
mukesh agrawal7a4e4002011-09-06 11:26:05 -07001011 return NULL;
1012 } else {
1013 WiFi *wifi = dynamic_cast<WiFi *>(wifi_devices.front().get());
1014 CHECK(wifi);
1015 return wifi->GetService(args, error);
1016 }
1017}
1018
Paul Stewart7f61e522012-03-22 11:13:45 -07001019// called via RPC (e.g., from ManagerDBusAdaptor)
1020void Manager::ConfigureService(const KeyValueStore &args, Error *error) {
1021 ProfileRefPtr profile = ActiveProfile();
1022 bool profile_specified = args.ContainsString(flimflam::kProfileProperty);
1023 if (profile_specified) {
1024 string profile_rpcid = args.GetString(flimflam::kProfileProperty);
1025 profile = LookupProfileByRpcIdentifier(profile_rpcid);
1026 if (!profile) {
1027 Error::PopulateAndLog(error, Error::kInvalidArguments,
1028 "Invalid profile name " + profile_rpcid);
1029 return;
1030 }
1031 }
1032
1033 ServiceRefPtr service = GetService(args, error);
1034 if (error->IsFailure() || !service) {
1035 LOG(ERROR) << "GetService failed; returning upstream error.";
1036 return;
1037 }
1038
1039 // Overwrte the profile data with the resulting configured service.
1040 if (!profile->UpdateService(service)) {
1041 Error::PopulateAndLog(error, Error::kInternalError,
1042 "Unable to save service to profile");
1043 return;
1044 }
1045
1046 if (HasService(service)) {
1047 // If the service has been registered (it may not be -- as is the case
1048 // with invisible WiFi networks), we can now transfer the service between
1049 // profiles.
1050 if (service->profile() == ephemeral_profile_ ||
1051 (profile_specified && service->profile() != profile)) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001052 SLOG(Manager, 2) << "Moving service to profile "
1053 << profile->GetFriendlyName();
Paul Stewart7f61e522012-03-22 11:13:45 -07001054 if (!MoveServiceToProfile(service, profile)) {
1055 Error::PopulateAndLog(error, Error::kInternalError,
1056 "Unable to move service to profile");
1057 }
1058 }
1059 }
1060}
1061
Paul Stewartc681fa02012-03-02 19:40:04 -08001062void Manager::RecheckPortal(Error */*error*/) {
1063 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1064 it != devices_.end(); ++it) {
1065 if ((*it)->RequestPortalDetection()) {
1066 // Only start Portal Detection on the device with the default connection.
1067 // We will get a "true" return value when we've found that device, and
1068 // can end our loop early as a result.
1069 break;
1070 }
1071 }
1072}
1073
mukesh agrawal7a4e4002011-09-06 11:26:05 -07001074// called via RPC (e.g., from ManagerDBusAdaptor)
Paul Stewart22aa71b2011-09-16 12:15:11 -07001075void Manager::RequestScan(const string &technology, Error *error) {
mukesh agrawal32399322011-09-01 10:53:43 -07001076 if (technology == flimflam::kTypeWifi || technology == "") {
1077 vector<DeviceRefPtr> wifi_devices;
Paul Stewartfdd16072011-09-16 12:41:35 -07001078 FilterByTechnology(Technology::kWifi, &wifi_devices);
mukesh agrawal32399322011-09-01 10:53:43 -07001079
1080 for (vector<DeviceRefPtr>::iterator it = wifi_devices.begin();
1081 it != wifi_devices.end();
1082 ++it) {
Darin Petkovc0865312011-09-16 15:31:20 -07001083 (*it)->Scan(error);
mukesh agrawal32399322011-09-01 10:53:43 -07001084 }
1085 } else {
1086 // TODO(quiche): support scanning for other technologies?
Paul Stewartbe005172011-11-02 18:10:29 -07001087 Error::PopulateAndLog(error, Error::kInvalidArguments,
1088 "Unrecognized technology " + technology);
mukesh agrawal32399322011-09-01 10:53:43 -07001089 }
1090}
1091
Paul Stewart22aa71b2011-09-16 12:15:11 -07001092string Manager::GetTechnologyOrder() {
1093 vector<string> technology_names;
1094 for (vector<Technology::Identifier>::iterator it = technology_order_.begin();
1095 it != technology_order_.end();
1096 ++it) {
1097 technology_names.push_back(Technology::NameFromIdentifier(*it));
1098 }
1099
1100 return JoinString(technology_names, ',');
1101}
1102
1103void Manager::SetTechnologyOrder(const string &order, Error *error) {
1104 vector<Technology::Identifier> new_order;
Ben Chanfad4a0b2012-04-18 15:49:59 -07001105 SLOG(Manager, 2) << "Setting technology order to " << order;
Paul Stewart20088d82012-02-16 06:58:55 -08001106 if (!Technology::GetTechnologyVectorFromString(order, &new_order, error)) {
1107 return;
Paul Stewart22aa71b2011-09-16 12:15:11 -07001108 }
1109
1110 technology_order_ = new_order;
1111 SortServices();
1112}
1113
Paul Stewart75897df2011-04-27 09:05:53 -07001114} // namespace shill