blob: db587a687e75cbae835fee1c925f7960c711585b [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"
Chris Masone9be4a9d2011-05-16 15:44:09 -070038#include "shill/service.h"
Thieu Lea20cbc22012-01-09 22:01:43 +000039#include "shill/service_sorter.h"
Darin Petkov33af05c2012-02-28 10:10:30 +010040#include "shill/vpn_service.h"
mukesh agrawal7a4e4002011-09-06 11:26:05 -070041#include "shill/wifi.h"
42#include "shill/wifi_service.h"
Paul Stewart75897df2011-04-27 09:05:53 -070043
Eric Shienbrood3e20a232012-02-16 11:35:56 -050044using base::Bind;
45using base::StringPrintf;
46using base::Unretained;
Gaurav Shah435de2c2011-11-17 19:01:07 -080047using std::set;
Paul Stewart75897df2011-04-27 09:05:53 -070048using std::string;
Chris Masone9be4a9d2011-05-16 15:44:09 -070049using std::vector;
Paul Stewart75897df2011-04-27 09:05:53 -070050
51namespace shill {
Paul Stewarte6132022011-08-16 09:11:02 -070052
Darin Petkovb65c2452012-02-23 15:17:06 +010053// statics
54const char Manager::kErrorNoDevice[] = "no wifi devices available";
55const char Manager::kErrorTypeRequired[] = "must specify service type";
56const char Manager::kErrorUnsupportedServiceType[] =
57 "service type is unsupported";
mukesh agrawal7a4e4002011-09-06 11:26:05 -070058
Paul Stewart75897df2011-04-27 09:05:53 -070059Manager::Manager(ControlInterface *control_interface,
Darin Petkov887f2982011-07-14 16:10:17 -070060 EventDispatcher *dispatcher,
Thieu Le3426c8f2012-01-11 17:35:11 -080061 Metrics *metrics,
Chris Masone2ae797d2011-08-23 20:41:00 -070062 GLib *glib,
63 const string &run_directory,
64 const string &storage_directory,
65 const string &user_storage_format)
mukesh agrawal8a3188d2011-12-01 20:56:44 +000066 : dispatcher_(dispatcher),
mukesh agrawal8a3188d2011-12-01 20:56:44 +000067 run_path_(FilePath(run_directory)),
68 storage_path_(FilePath(storage_directory)),
69 user_storage_format_(user_storage_format),
70 adaptor_(control_interface->CreateManagerAdaptor(this)),
Thieu Le3426c8f2012-01-11 17:35:11 -080071 device_info_(control_interface, dispatcher, metrics, this),
72 modem_info_(control_interface, dispatcher, metrics, this, glib),
Darin Petkov33af05c2012-02-28 10:10:30 +010073 vpn_provider_(control_interface, dispatcher, metrics, this),
mukesh agrawal8a3188d2011-12-01 20:56:44 +000074 running_(false),
75 connect_profiles_to_rpc_(true),
76 ephemeral_profile_(new EphemeralProfile(control_interface, this)),
77 control_interface_(control_interface),
Thieu Le3426c8f2012-01-11 17:35:11 -080078 metrics_(metrics),
mukesh agrawal8a3188d2011-12-01 20:56:44 +000079 glib_(glib) {
Chris Masone7aa5f902011-07-11 11:13:35 -070080 HelpRegisterDerivedString(flimflam::kActiveProfileProperty,
Paul Stewart1b253142012-01-26 14:05:52 -080081 &Manager::GetActiveProfileRpcIdentifier,
Chris Masone7aa5f902011-07-11 11:13:35 -070082 NULL);
Chris Masone27c4aa52011-07-02 13:10:14 -070083 HelpRegisterDerivedStrings(flimflam::kAvailableTechnologiesProperty,
84 &Manager::AvailableTechnologies,
85 NULL);
Chris Masone88cbd5f2011-07-03 14:30:04 -070086 store_.RegisterString(flimflam::kCheckPortalListProperty,
87 &props_.check_portal_list);
Chris Masone27c4aa52011-07-02 13:10:14 -070088 HelpRegisterDerivedStrings(flimflam::kConnectedTechnologiesProperty,
89 &Manager::ConnectedTechnologies,
90 NULL);
Chris Masone88cbd5f2011-07-03 14:30:04 -070091 store_.RegisterString(flimflam::kCountryProperty, &props_.country);
Chris Masone27c4aa52011-07-02 13:10:14 -070092 HelpRegisterDerivedString(flimflam::kDefaultTechnologyProperty,
93 &Manager::DefaultTechnology,
94 NULL);
Chris Masone27c4aa52011-07-02 13:10:14 -070095 HelpRegisterDerivedStrings(flimflam::kDevicesProperty,
96 &Manager::EnumerateDevices,
97 NULL);
Chris Masone88cbd5f2011-07-03 14:30:04 -070098 HelpRegisterDerivedStrings(flimflam::kEnabledTechnologiesProperty,
99 &Manager::EnabledTechnologies,
100 NULL);
101 store_.RegisterBool(flimflam::kOfflineModeProperty, &props_.offline_mode);
102 store_.RegisterString(flimflam::kPortalURLProperty, &props_.portal_url);
Paul Stewartc681fa02012-03-02 19:40:04 -0800103 store_.RegisterInt32(kPortalCheckIntervalProperty,
104 &props_.portal_check_interval_seconds);
Paul Stewart1b253142012-01-26 14:05:52 -0800105 HelpRegisterDerivedStrings(flimflam::kProfilesProperty,
106 &Manager::EnumerateProfiles,
107 NULL);
Paul Stewartc681fa02012-03-02 19:40:04 -0800108 store_.RegisterString(kHostNameProperty, &props_.host_name);
Chris Masone88cbd5f2011-07-03 14:30:04 -0700109 HelpRegisterDerivedString(flimflam::kStateProperty,
110 &Manager::CalculateState,
111 NULL);
mukesh agrawal2366eed2012-03-20 18:21:50 -0700112 HelpRegisterConstDerivedRpcIdentifiers(flimflam::kServicesProperty,
113 &Manager::EnumerateAvailableServices);
Chris Masone27c4aa52011-07-02 13:10:14 -0700114 HelpRegisterDerivedStrings(flimflam::kServiceWatchListProperty,
115 &Manager::EnumerateWatchedServices,
116 NULL);
Chris Masone3c3f6a12011-07-01 10:01:41 -0700117
mukesh agrawal84de5d22012-02-17 19:29:15 -0800118 // Set default technology order "by hand", to avoid invoking side
119 // effects of SetTechnologyOrder.
120 technology_order_.push_back(
121 Technology::IdentifierFromName(flimflam::kTypeEthernet));
122 technology_order_.push_back(
123 Technology::IdentifierFromName(flimflam::kTypeWifi));
124 technology_order_.push_back(
125 Technology::IdentifierFromName(flimflam::kTypeCellular));
126
Chris Masoneb07006b2011-05-14 16:10:04 -0700127 VLOG(2) << "Manager initialized.";
Paul Stewart75897df2011-04-27 09:05:53 -0700128}
129
Chris Masone6791a432011-07-12 13:23:19 -0700130Manager::~Manager() {
Chris Masone9d779932011-08-25 16:33:41 -0700131 profiles_.clear();
Chris Masone6791a432011-07-12 13:23:19 -0700132}
Paul Stewart75897df2011-04-27 09:05:53 -0700133
mukesh agrawal8f317b62011-07-15 11:53:23 -0700134void Manager::AddDeviceToBlackList(const string &device_name) {
135 device_info_.AddDeviceToBlackList(device_name);
136}
137
Paul Stewart75897df2011-04-27 09:05:53 -0700138void Manager::Start() {
Paul Stewart0af98bf2011-05-10 17:38:08 -0700139 LOG(INFO) << "Manager started.";
Paul Stewarte6132022011-08-16 09:11:02 -0700140
Gary Morainac1bdb42012-02-16 17:42:29 -0800141 power_manager_.reset(new PowerManager(ProxyFactory::GetInstance()));
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500142 // TODO(ers): weak ptr for metrics_?
143 PowerManager::PowerStateCallback cb =
144 Bind(&Metrics::NotifyPowerStateChange, Unretained(metrics_));
Thieu Leb84ba342012-03-02 15:15:19 -0800145 power_manager_->AddStateChangeCallback(Metrics::kMetricPowerManagerKey, cb);
146
Chris Masone2ae797d2011-08-23 20:41:00 -0700147 CHECK(file_util::CreateDirectory(run_path_)) << run_path_.value();
Paul Stewarte6132022011-08-16 09:11:02 -0700148 Resolver::GetInstance()->set_path(run_path_.Append("resolv.conf"));
Chris Masone2ae797d2011-08-23 20:41:00 -0700149
Gaurav Shah71354762011-11-28 19:22:49 -0800150 InitializeProfiles();
Paul Stewart75897df2011-04-27 09:05:53 -0700151 running_ = true;
Chris Masone413a3192011-05-09 17:10:05 -0700152 adaptor_->UpdateRunning();
Paul Stewart0af98bf2011-05-10 17:38:08 -0700153 device_info_.Start();
Darin Petkov887f2982011-07-14 16:10:17 -0700154 modem_info_.Start();
Darin Petkov33af05c2012-02-28 10:10:30 +0100155 vpn_provider_.Start();
Paul Stewart75897df2011-04-27 09:05:53 -0700156}
157
158void Manager::Stop() {
159 running_ = false;
Chris Masone9d779932011-08-25 16:33:41 -0700160 // Persist profile, device, service information to disk.
161 vector<ProfileRefPtr>::iterator it;
162 for (it = profiles_.begin(); it != profiles_.end(); ++it) {
Paul Stewartd0a3b812012-03-28 22:48:22 -0700163 // Since this happens in a loop, the current manager state is stored to
164 // all default profiles in the stack. This is acceptable because the
165 // only time multiple default profiles are loaded are during autotests.
Chris Masone6515aab2011-10-12 16:19:09 -0700166 (*it)->Save();
Chris Masone9d779932011-08-25 16:33:41 -0700167 }
Chris Masone9d779932011-08-25 16:33:41 -0700168
Thieu Le1271d682011-11-02 22:48:19 +0000169 vector<ServiceRefPtr>::iterator services_it;
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000170 Error e;
Thieu Le1271d682011-11-02 22:48:19 +0000171 for (services_it = services_.begin(); services_it != services_.end();
172 ++services_it) {
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000173 (*services_it)->Disconnect(&e);
Thieu Le1271d682011-11-02 22:48:19 +0000174 }
175
Chris Masone413a3192011-05-09 17:10:05 -0700176 adaptor_->UpdateRunning();
Darin Petkov33af05c2012-02-28 10:10:30 +0100177 vpn_provider_.Stop();
Darin Petkov887f2982011-07-14 16:10:17 -0700178 modem_info_.Stop();
179 device_info_.Stop();
Thieu Leb84ba342012-03-02 15:15:19 -0800180
181 // Some unit tests do not call Manager::Start().
182 if (power_manager_.get())
183 power_manager_->RemoveStateChangeCallback(Metrics::kMetricPowerManagerKey);
Paul Stewart75897df2011-04-27 09:05:53 -0700184}
185
Gaurav Shah71354762011-11-28 19:22:49 -0800186void Manager::InitializeProfiles() {
187 DCHECK(profiles_.empty());
188 // The default profile must go first on the stack.
189 CHECK(file_util::CreateDirectory(storage_path_)) << storage_path_.value();
Paul Stewart870523b2012-01-11 17:00:42 -0800190 scoped_refptr<DefaultProfile>
191 default_profile(new DefaultProfile(control_interface_,
Gaurav Shah71354762011-11-28 19:22:49 -0800192 this,
193 storage_path_,
Paul Stewartd0a3b812012-03-28 22:48:22 -0700194 DefaultProfile::kDefaultId,
Gaurav Shah71354762011-11-28 19:22:49 -0800195 props_));
Paul Stewart870523b2012-01-11 17:00:42 -0800196 CHECK(default_profile->InitStorage(glib_, Profile::kCreateOrOpenExisting,
197 NULL));
198 CHECK(default_profile->LoadManagerProperties(&props_));
199 profiles_.push_back(default_profile.release());
Gaurav Shah71354762011-11-28 19:22:49 -0800200 Error error;
Paul Stewart19c871d2011-12-15 16:10:13 -0800201 string path;
Gaurav Shah71354762011-11-28 19:22:49 -0800202 for (vector<string>::iterator it = startup_profiles_.begin();
203 it != startup_profiles_.end(); ++it)
Paul Stewart19c871d2011-12-15 16:10:13 -0800204 PushProfile(*it, &path, &error);
Gaurav Shah71354762011-11-28 19:22:49 -0800205}
206
Paul Stewart19c871d2011-12-15 16:10:13 -0800207void Manager::CreateProfile(const string &name, string *path, Error *error) {
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700208 Profile::Identifier ident;
209 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700210 Error::PopulateAndLog(error, Error::kInvalidArguments,
211 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700212 return;
213 }
Paul Stewartd0a3b812012-03-28 22:48:22 -0700214
215 ProfileRefPtr profile;
216 if (ident.user.empty()) {
217 profile = new DefaultProfile(control_interface_,
218 this,
219 storage_path_,
220 ident.identifier,
221 props_);
222 } else {
223 profile = new Profile(control_interface_,
224 this,
225 ident,
226 user_storage_format_,
Paul Stewarte73d05c2012-03-29 16:26:05 -0700227 false);
Paul Stewartd0a3b812012-03-28 22:48:22 -0700228 }
229
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700230 if (!profile->InitStorage(glib_, Profile::kCreateNew, error)) {
Paul Stewart19c871d2011-12-15 16:10:13 -0800231 // |error| will have been populated by InitStorage().
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700232 return;
233 }
234
235 // Save profile data out, and then let the scoped pointer fall out of scope.
236 if (!profile->Save()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700237 Error::PopulateAndLog(error, Error::kInternalError,
238 "Profile name " + name + " could not be saved");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700239 return;
240 }
Paul Stewart19c871d2011-12-15 16:10:13 -0800241
242 *path = profile->GetRpcIdentifier();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700243}
244
Paul Stewart19c871d2011-12-15 16:10:13 -0800245void Manager::PushProfile(const string &name, string *path, Error *error) {
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700246 Profile::Identifier ident;
247 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700248 Error::PopulateAndLog(error, Error::kInvalidArguments,
249 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700250 return;
251 }
252
253 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
254 it != profiles_.end();
255 ++it) {
256 if ((*it)->MatchesIdentifier(ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700257 Error::PopulateAndLog(error, Error::kAlreadyExists,
258 "Profile name " + name + " is already on stack");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700259 return;
260 }
261 }
262
Paul Stewartd0a3b812012-03-28 22:48:22 -0700263 ProfileRefPtr profile;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700264 if (ident.user.empty()) {
Paul Stewartd0a3b812012-03-28 22:48:22 -0700265 // Allow a machine-wide-profile to be pushed on the stack only if the
266 // profile stack is empty, or if the topmost profile on the stack is
267 // also a machine-wide (non-user) profile.
268 if (!profiles_.empty() && !profiles_.back()->GetUser().empty()) {
269 Error::PopulateAndLog(error, Error::kInvalidArguments,
270 "Cannot load non-default global profile " + name +
271 " on top of a user profile");
272 return;
273 }
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700274
Paul Stewartd0a3b812012-03-28 22:48:22 -0700275 scoped_refptr<DefaultProfile>
276 default_profile(new DefaultProfile(control_interface_,
277 this,
278 storage_path_,
279 ident.identifier,
280 props_));
281 if (!default_profile->InitStorage(glib_, Profile::kOpenExisting, error)) {
282 // |error| will have been populated by InitStorage().
283 return;
284 }
285
286 if (!default_profile->LoadManagerProperties(&props_)) {
287 Error::PopulateAndLog(error, Error::kInvalidArguments,
288 "Could not load Manager properties from profile " +
289 name);
290 return;
291 }
292 profile = default_profile;
293 } else {
294 profile = new Profile(control_interface_,
295 this,
296 ident,
297 user_storage_format_,
298 connect_profiles_to_rpc_);
299 if (!profile->InitStorage(glib_, Profile::kOpenExisting, error)) {
300 // |error| will have been populated by InitStorage().
301 return;
302 }
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700303 }
304
Paul Stewarta849a3d2011-11-03 05:54:09 -0700305 profiles_.push_back(profile);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700306
307 // Offer each registered Service the opportunity to join this new Profile.
Paul Stewarta41e38d2011-11-11 07:47:29 -0800308 for (vector<ServiceRefPtr>::iterator it = services_.begin();
309 it != services_.end(); ++it) {
Paul Stewartbba6a5b2011-11-02 18:45:59 -0700310 profile->ConfigureService(*it);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700311 }
312
Paul Stewarta41e38d2011-11-11 07:47:29 -0800313 // Shop the Profile contents around to Devices which can create
314 // non-visible services.
315 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
316 it != devices_.end(); ++it) {
317 profile->ConfigureDevice(*it);
318 }
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800319
Paul Stewart19c871d2011-12-15 16:10:13 -0800320 *path = profile->GetRpcIdentifier();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800321 SortServices();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700322}
323
324void Manager::PopProfileInternal() {
325 CHECK(!profiles_.empty());
326 ProfileRefPtr active_profile = profiles_.back();
327 profiles_.pop_back();
Paul Stewart75225512012-01-26 22:51:33 -0800328 vector<ServiceRefPtr>::iterator it;
Paul Stewart65512e12012-03-26 18:01:08 -0700329 for (it = services_.begin(); it != services_.end();) {
330 if ((*it)->profile().get() != active_profile.get() ||
331 MatchProfileWithService(*it) ||
332 !UnloadService(&it)) {
333 LOG(ERROR) << "Skipping unload of service";
334 ++it;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700335 }
336 }
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800337 SortServices();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700338}
339
Paul Stewarta41e38d2011-11-11 07:47:29 -0800340void Manager::PopProfile(const string &name, Error *error) {
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700341 Profile::Identifier ident;
342 if (profiles_.empty()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700343 Error::PopulateAndLog(error, Error::kNotFound, "Profile stack is empty");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700344 return;
345 }
346 ProfileRefPtr active_profile = profiles_.back();
347 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700348 Error::PopulateAndLog(error, Error::kInvalidArguments,
349 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700350 return;
351 }
352 if (!active_profile->MatchesIdentifier(ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700353 Error::PopulateAndLog(error, Error::kNotSupported,
354 name + " is not the active profile");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700355 return;
356 }
357 PopProfileInternal();
358}
359
360void Manager::PopAnyProfile(Error *error) {
361 Profile::Identifier ident;
362 if (profiles_.empty()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700363 Error::PopulateAndLog(error, Error::kNotFound, "Profile stack is empty");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700364 return;
365 }
366 PopProfileInternal();
367}
368
Paul Stewarte73d05c2012-03-29 16:26:05 -0700369void Manager::RemoveProfile(const string &name, Error *error) {
370 Profile::Identifier ident;
371 if (!Profile::ParseIdentifier(name, &ident)) {
372 Error::PopulateAndLog(error, Error::kInvalidArguments,
373 "Invalid profile name " + name);
374 return;
375 }
376
377 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
378 it != profiles_.end();
379 ++it) {
380 if ((*it)->MatchesIdentifier(ident)) {
381 Error::PopulateAndLog(error, Error::kInvalidArguments,
382 "Cannot remove profile name " + name +
383 " since it is on stack");
384 return;
385 }
386 }
387
388 ProfileRefPtr profile;
389 if (ident.user.empty()) {
390 profile = new DefaultProfile(control_interface_,
391 this,
392 storage_path_,
393 ident.identifier,
394 props_);
395 } else {
396 profile = new Profile(control_interface_,
397 this,
398 ident,
399 user_storage_format_,
400 false);
401 }
402
403
404 // |error| will have been populated if RemoveStorage fails.
405 profile->RemoveStorage(glib_, error);
406
407 return;
408}
409
Paul Stewart75225512012-01-26 22:51:33 -0800410bool Manager::HandleProfileEntryDeletion(const ProfileRefPtr &profile,
411 const std::string &entry_name) {
412 bool moved_services = false;
413 for (vector<ServiceRefPtr>::iterator it = services_.begin();
Paul Stewart65512e12012-03-26 18:01:08 -0700414 it != services_.end();) {
Paul Stewart75225512012-01-26 22:51:33 -0800415 if ((*it)->profile().get() == profile.get() &&
416 (*it)->GetStorageIdentifier() == entry_name) {
417 profile->AbandonService(*it);
Paul Stewart65512e12012-03-26 18:01:08 -0700418 if (MatchProfileWithService(*it) ||
419 !UnloadService(&it)) {
420 ++it;
Paul Stewart75225512012-01-26 22:51:33 -0800421 }
422 moved_services = true;
Paul Stewart65512e12012-03-26 18:01:08 -0700423 } else {
424 ++it;
Paul Stewart75225512012-01-26 22:51:33 -0800425 }
426 }
427 return moved_services;
428}
429
Paul Stewart0756db92012-01-27 08:34:47 -0800430ServiceRefPtr Manager::GetServiceWithStorageIdentifier(
431 const ProfileRefPtr &profile, const std::string &entry_name, Error *error) {
432 for (vector<ServiceRefPtr>::iterator it = services_.begin();
433 it != services_.end(); ++it) {
434 if ((*it)->profile().get() == profile.get() &&
435 (*it)->GetStorageIdentifier() == entry_name) {
436 return *it;
437 }
438 }
439
440 Error::PopulateAndLog(error, Error::kNotFound,
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500441 StringPrintf("Entry %s is not registered in the manager",
442 entry_name.c_str()));
Paul Stewart0756db92012-01-27 08:34:47 -0800443 return NULL;
444}
445
Paul Stewart13ed2252012-03-21 12:52:46 -0700446ServiceRefPtr Manager::GetServiceWithGUID(
447 const std::string &guid, Error *error) {
448 for (vector<ServiceRefPtr>::iterator it = services_.begin();
449 it != services_.end(); ++it) {
450 if ((*it)->guid() == guid) {
451 return *it;
452 }
453 }
454
455 Error::PopulateAndLog(error, Error::kNotFound,
456 StringPrintf("Service wth GUID %s is not registered in the manager",
457 guid.c_str()));
458 return NULL;
459}
460
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700461ServiceRefPtr Manager::GetDefaultService() const {
462 if (services_.empty() || !services_[0]->connection().get()) {
463 VLOG(2) << "In " << __func__ << ": No default connection exists.";
464 return NULL;
465 }
466 return services_[0];
467}
468
Paul Stewart20088d82012-02-16 06:58:55 -0800469bool Manager::IsPortalDetectionEnabled(Technology::Identifier tech) {
470 Error error;
471 vector<Technology::Identifier> portal_technologies;
472 return Technology::GetTechnologyVectorFromString(props_.check_portal_list,
473 &portal_technologies,
474 &error) &&
475 std::find(portal_technologies.begin(), portal_technologies.end(),
476 tech) != portal_technologies.end();
477}
478
Paul Stewart1b253142012-01-26 14:05:52 -0800479const ProfileRefPtr &Manager::ActiveProfile() const {
Eric Shienbroodc74cf9c2012-03-02 15:00:35 -0500480 DCHECK_NE(profiles_.size(), 0U);
Chris Masone7aa5f902011-07-11 11:13:35 -0700481 return profiles_.back();
482}
483
Paul Stewart1b253142012-01-26 14:05:52 -0800484bool Manager::IsActiveProfile(const ProfileRefPtr &profile) const {
485 return (profiles_.size() > 0 &&
486 ActiveProfile().get() == profile.get());
487}
488
Eric Shienbrood9a245532012-03-07 14:20:39 -0500489void Manager::SaveActiveProfile() {
490 if (!profiles_.empty()) {
491 ActiveProfile()->Save();
492 }
493}
494
Chris Masone6515aab2011-10-12 16:19:09 -0700495bool Manager::MoveServiceToProfile(const ServiceRefPtr &to_move,
496 const ProfileRefPtr &destination) {
497 const ProfileRefPtr from = to_move->profile();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800498 VLOG(2) << "Moving service "
499 << to_move->UniqueName()
500 << " to profile "
501 << destination->GetFriendlyName()
502 << " from "
503 << from->GetFriendlyName();
Chris Masone6515aab2011-10-12 16:19:09 -0700504 return destination->AdoptService(to_move) &&
505 from->AbandonService(to_move);
Chris Masone6791a432011-07-12 13:23:19 -0700506}
507
Paul Stewart7f61e522012-03-22 11:13:45 -0700508ProfileRefPtr Manager::LookupProfileByRpcIdentifier(
509 const string &profile_rpcid) {
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800510 for (vector<ProfileRefPtr>::iterator it = profiles_.begin();
511 it != profiles_.end();
512 ++it) {
513 if (profile_rpcid == (*it)->GetRpcIdentifier()) {
Paul Stewart7f61e522012-03-22 11:13:45 -0700514 return *it;
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800515 }
516 }
Paul Stewart7f61e522012-03-22 11:13:45 -0700517 return NULL;
518}
519
520void Manager::SetProfileForService(const ServiceRefPtr &to_set,
521 const string &profile_rpcid,
522 Error *error) {
523 ProfileRefPtr profile = LookupProfileByRpcIdentifier(profile_rpcid);
524 if (!profile) {
525 Error::PopulateAndLog(error, Error::kInvalidArguments,
526 StringPrintf("Unknown Profile %s requested for "
527 "Service", profile_rpcid.c_str()));
528 return;
529 }
530
531 if (to_set->profile().get() == profile.get()) {
532 Error::PopulateAndLog(error, Error::kInvalidArguments,
533 "Service is already connected to this profile");
534 } else if (!MoveServiceToProfile(to_set, profile)) {
535 Error::PopulateAndLog(error, Error::kInternalError,
536 "Unable to move service to profile");
537 }
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800538}
539
Eric Shienbrood9a245532012-03-07 14:20:39 -0500540void Manager::EnableTechnology(const std::string &technology_name,
541 Error *error,
542 const ResultCallback &callback) {
543 Technology::Identifier id = Technology::IdentifierFromName(technology_name);
544 if (id == Technology::kUnknown) {
545 error->Populate(Error::kInvalidArguments, "Unknown technology");
546 return;
547 }
548 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
549 it != devices_.end(); ++it) {
550 DeviceRefPtr device = *it;
551 if (device->technology() == id && !device->enabled()) {
552 device->SetEnabledPersistent(true, error, callback);
553 // Continue with other devices even if one fails
554 // TODO(ers): Decide whether an error should be returned
555 // for the overall EnableTechnology operation if some
556 // devices succeed and some fail.
557 }
558 }
559}
560
561void Manager::DisableTechnology(const std::string &technology_name,
562 Error *error,
563 const ResultCallback &callback) {
564 Technology::Identifier id = Technology::IdentifierFromName(technology_name);
565 if (id == Technology::kUnknown) {
566 error->Populate(Error::kInvalidArguments, "Unknown technology");
567 return;
568 }
569 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
570 it != devices_.end(); ++it) {
571 DeviceRefPtr device = *it;
572 if (device->technology() == id && device->enabled()) {
573 device->SetEnabledPersistent(false, error, callback);
574 // Continue with other devices even if one fails
575 // TODO(ers): Decide whether an error should be returned
576 // for the overall DisableTechnology operation if some
577 // devices succeed and some fail.
578 }
579 }
580}
581
582void Manager::UpdateEnabledTechnologies() {
583 Error error;
584 adaptor_->EmitStringsChanged(flimflam::kEnabledTechnologiesProperty,
585 EnabledTechnologies(&error));
586}
587
Chris Masone2b105542011-06-22 10:58:09 -0700588void Manager::RegisterDevice(const DeviceRefPtr &to_manage) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500589 VLOG(2) << __func__ << "(" << to_manage->FriendlyName() << ")";
Chris Masonec1e50412011-06-07 13:04:53 -0700590 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700591 for (it = devices_.begin(); it != devices_.end(); ++it) {
Chris Masonec1e50412011-06-07 13:04:53 -0700592 if (to_manage.get() == it->get())
Chris Masone9be4a9d2011-05-16 15:44:09 -0700593 return;
594 }
Chris Masonec1e50412011-06-07 13:04:53 -0700595 devices_.push_back(to_manage);
Paul Stewartf1ce5d22011-05-19 13:10:20 -0700596
Paul Stewarta41e38d2011-11-11 07:47:29 -0800597 // We are applying device properties from the DefaultProfile, and adding
598 // the union of hidden services in all loaded profiles to the device.
Chris Masone6515aab2011-10-12 16:19:09 -0700599 for (vector<ProfileRefPtr>::iterator it = profiles_.begin();
600 it != profiles_.end();
601 ++it) {
Paul Stewarta41e38d2011-11-11 07:47:29 -0800602 // Load device configuration, if any exists, as well as hidden services.
603 (*it)->ConfigureDevice(to_manage);
604
605 // Currently the only profile for which "Save" is implemented is the
606 // DefaultProfile. It iterates over all Devices and stores their state.
607 // We perform the Save now in case the device we have just registered
608 // is new and needs to be added to the stored DefaultProfile.
Chris Masone6515aab2011-10-12 16:19:09 -0700609 (*it)->Save();
610 }
Paul Stewarta41e38d2011-11-11 07:47:29 -0800611
612 // In normal usage, running_ will always be true when we are here, however
613 // unit tests sometimes do things in otherwise invalid states.
Eric Shienbrood9a245532012-03-07 14:20:39 -0500614 if (running_ && to_manage->enabled_persistent())
615 to_manage->SetEnabled(true);
Gaurav Shah435de2c2011-11-17 19:01:07 -0800616
Eric Shienbrood8839a892012-03-29 10:33:48 -0400617 EmitDeviceProperties();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700618}
619
mukesh agrawal5029c6c2011-08-25 11:12:40 -0700620void Manager::DeregisterDevice(const DeviceRefPtr &to_forget) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500621 VLOG(2) << __func__ << "(" << to_forget->FriendlyName() << ")";
Chris Masonec1e50412011-06-07 13:04:53 -0700622 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700623 for (it = devices_.begin(); it != devices_.end(); ++it) {
Chris Masonec1e50412011-06-07 13:04:53 -0700624 if (to_forget.get() == it->get()) {
mukesh agrawal5029c6c2011-08-25 11:12:40 -0700625 VLOG(2) << "Deregistered device: " << to_forget->UniqueName();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500626 to_forget->SetEnabled(false);
Chris Masone9be4a9d2011-05-16 15:44:09 -0700627 devices_.erase(it);
Eric Shienbrood8839a892012-03-29 10:33:48 -0400628 EmitDeviceProperties();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700629 return;
630 }
631 }
mukesh agrawal5029c6c2011-08-25 11:12:40 -0700632 VLOG(2) << __func__ << " unknown device: " << to_forget->UniqueName();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700633}
634
Eric Shienbrood8839a892012-03-29 10:33:48 -0400635void Manager::EmitDeviceProperties() {
636 vector<DeviceRefPtr>::iterator it;
637 vector<string> device_paths;
638 for (it = devices_.begin(); it != devices_.end(); ++it) {
639 device_paths.push_back((*it)->GetRpcIdentifier());
640 }
641 adaptor_->EmitRpcIdentifierArrayChanged(flimflam::kDevicesProperty,
642 device_paths);
643 Error error;
644 adaptor_->EmitStringsChanged(flimflam::kAvailableTechnologiesProperty,
645 AvailableTechnologies(&error));
646 adaptor_->EmitStringsChanged(flimflam::kEnabledTechnologiesProperty,
647 EnabledTechnologies(&error));
648}
649
mukesh agrawal4eb4d782011-12-05 17:34:37 +0000650bool Manager::HasService(const ServiceRefPtr &service) {
651 vector<ServiceRefPtr>::iterator it;
652 for (it = services_.begin(); it != services_.end(); ++it) {
653 if ((*it)->UniqueName() == service->UniqueName())
654 return true;
655 }
656 return false;
657}
658
Chris Masone2b105542011-06-22 10:58:09 -0700659void Manager::RegisterService(const ServiceRefPtr &to_manage) {
Gaurav Shahc6d6c722011-11-17 18:59:39 -0800660 VLOG(2) << "In " << __func__ << "(): Registering service "
661 << to_manage->UniqueName();
mukesh agrawald835b202011-10-07 15:26:47 -0700662
Paul Stewart75225512012-01-26 22:51:33 -0800663 MatchProfileWithService(to_manage);
Chris Masone6791a432011-07-12 13:23:19 -0700664
665 // Now add to OUR list.
Chris Masonec1e50412011-06-07 13:04:53 -0700666 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700667 for (it = services_.begin(); it != services_.end(); ++it) {
mukesh agrawald835b202011-10-07 15:26:47 -0700668 CHECK(to_manage->UniqueName() != (*it)->UniqueName());
Chris Masone9be4a9d2011-05-16 15:44:09 -0700669 }
Chris Masonec1e50412011-06-07 13:04:53 -0700670 services_.push_back(to_manage);
Paul Stewart22aa71b2011-09-16 12:15:11 -0700671 SortServices();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700672}
673
Chris Masone6515aab2011-10-12 16:19:09 -0700674void Manager::DeregisterService(const ServiceRefPtr &to_forget) {
Chris Masonec1e50412011-06-07 13:04:53 -0700675 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700676 for (it = services_.begin(); it != services_.end(); ++it) {
Chris Masone6791a432011-07-12 13:23:19 -0700677 if (to_forget->UniqueName() == (*it)->UniqueName()) {
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800678 DCHECK(!(*it)->connection());
Chris Masone9be4a9d2011-05-16 15:44:09 -0700679 services_.erase(it);
Paul Stewart22aa71b2011-09-16 12:15:11 -0700680 SortServices();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700681 return;
682 }
683 }
684}
685
Paul Stewart65512e12012-03-26 18:01:08 -0700686bool Manager::UnloadService(vector<ServiceRefPtr>::iterator *service_iterator) {
687 if (!(**service_iterator)->Unload()) {
688 return false;
689 }
690
691 DCHECK(!(**service_iterator)->connection());
692 *service_iterator = services_.erase(*service_iterator);
693
694 return true;
695}
696
mukesh agrawal00917ce2011-11-22 23:56:55 +0000697void Manager::UpdateService(const ServiceRefPtr &to_update) {
698 CHECK(to_update);
Paul Stewart03dba0b2011-08-22 16:32:45 -0700699 LOG(INFO) << "Service " << to_update->UniqueName() << " updated;"
Gaurav Shahc6d6c722011-11-17 18:59:39 -0800700 << " state: " << Service::ConnectStateToString(to_update->state())
701 << " failure: "
702 << Service::ConnectFailureToString(to_update->failure());
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000703 VLOG(2) << "IsConnected(): " << to_update->IsConnected();
704 VLOG(2) << "IsConnecting(): " << to_update->IsConnecting();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800705 if (to_update->IsConnected()) {
Thieu Led4e9e552012-02-16 16:26:07 -0800706 bool originally_favorite = to_update->favorite();
mukesh agrawal00917ce2011-11-22 23:56:55 +0000707 to_update->MakeFavorite();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800708 if (to_update->profile().get() == ephemeral_profile_.get()) {
709 if (profiles_.empty()) {
710 LOG(ERROR) << "Cannot assign profile to service: no profiles exist!";
711 } else {
712 MoveServiceToProfile(to_update, profiles_.back());
713 }
Thieu Led4e9e552012-02-16 16:26:07 -0800714 } else if (!originally_favorite) {
715 // Persists the updated favorite setting in the profile.
716 to_update->SaveToCurrentProfile();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800717 }
718 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700719 SortServices();
Paul Stewart03dba0b2011-08-22 16:32:45 -0700720}
721
Paul Stewartfdd16072011-09-16 12:41:35 -0700722void Manager::FilterByTechnology(Technology::Identifier tech,
Chris Masonec1e50412011-06-07 13:04:53 -0700723 vector<DeviceRefPtr> *found) {
Chris Masone9be4a9d2011-05-16 15:44:09 -0700724 CHECK(found);
Chris Masonec1e50412011-06-07 13:04:53 -0700725 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700726 for (it = devices_.begin(); it != devices_.end(); ++it) {
727 if ((*it)->TechnologyIs(tech))
728 found->push_back(*it);
729 }
730}
731
Paul Stewart22aa71b2011-09-16 12:15:11 -0700732ServiceRefPtr Manager::FindService(const string& name) {
Chris Masonec1e50412011-06-07 13:04:53 -0700733 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700734 for (it = services_.begin(); it != services_.end(); ++it) {
Chris Masone6791a432011-07-12 13:23:19 -0700735 if (name == (*it)->UniqueName())
Chris Masonee0dea762011-06-09 09:06:03 -0700736 return *it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700737 }
Chris Masonee0dea762011-06-09 09:06:03 -0700738 return NULL;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700739}
740
mukesh agrawal2366eed2012-03-20 18:21:50 -0700741void Manager::HelpRegisterConstDerivedRpcIdentifiers(
742 const string &name,
743 RpcIdentifiers(Manager::*get)(Error *)) {
744 store_.RegisterDerivedRpcIdentifiers(
745 name,
746 RpcIdentifiersAccessor(
747 new CustomAccessor<Manager, RpcIdentifiers>(this, get, NULL)));
748}
749
mukesh agrawalffa3d042011-10-06 15:26:10 -0700750void Manager::HelpRegisterDerivedString(
751 const string &name,
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800752 string(Manager::*get)(Error *),
mukesh agrawalffa3d042011-10-06 15:26:10 -0700753 void(Manager::*set)(const string&, Error *)) {
Chris Masone27c4aa52011-07-02 13:10:14 -0700754 store_.RegisterDerivedString(
755 name,
756 StringAccessor(new CustomAccessor<Manager, string>(this, get, set)));
Chris Masoneb925cc82011-06-22 15:39:57 -0700757}
758
mukesh agrawalffa3d042011-10-06 15:26:10 -0700759void Manager::HelpRegisterDerivedStrings(
760 const string &name,
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800761 Strings(Manager::*get)(Error *),
mukesh agrawalffa3d042011-10-06 15:26:10 -0700762 void(Manager::*set)(const Strings &, Error *)) {
Chris Masone27c4aa52011-07-02 13:10:14 -0700763 store_.RegisterDerivedStrings(
764 name,
765 StringsAccessor(new CustomAccessor<Manager, Strings>(this, get, set)));
Chris Masoneb925cc82011-06-22 15:39:57 -0700766}
767
Paul Stewart22aa71b2011-09-16 12:15:11 -0700768void Manager::SortServices() {
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800769 VLOG(4) << "In " << __func__;
Thieu Lea20cbc22012-01-09 22:01:43 +0000770 ServiceRefPtr default_service;
771
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800772 if (!services_.empty()) {
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700773 // Keep track of the service that is the candidate for the default
774 // service. We have not yet tested to see if this service has a
775 // connection.
Thieu Lea20cbc22012-01-09 22:01:43 +0000776 default_service = services_[0];
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800777 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700778 sort(services_.begin(), services_.end(), ServiceSorter(technology_order_));
Paul Stewarta41e38d2011-11-11 07:47:29 -0800779
780 vector<string> service_paths;
781 vector<ServiceRefPtr>::iterator it;
782 for (it = services_.begin(); it != services_.end(); ++it) {
783 if ((*it)->IsVisible()) {
784 service_paths.push_back((*it)->GetRpcIdentifier());
785 }
786 }
787 adaptor_->EmitRpcIdentifierArrayChanged(flimflam::kServicesProperty,
788 service_paths);
Gaurav Shah435de2c2011-11-17 19:01:07 -0800789
790 Error error;
791 adaptor_->EmitStringsChanged(flimflam::kConnectedTechnologiesProperty,
792 ConnectedTechnologies(&error));
793 adaptor_->EmitStringChanged(flimflam::kDefaultTechnologyProperty,
794 DefaultTechnology(&error));
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800795
796 if (!services_.empty()) {
Thieu Lea20cbc22012-01-09 22:01:43 +0000797 ConnectionRefPtr default_connection = default_service->connection();
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800798 if (default_connection.get() &&
799 (services_[0]->connection().get() != default_connection.get())) {
800 default_connection->SetIsDefault(false);
801 }
802 if (services_[0]->connection().get()) {
803 services_[0]->connection()->SetIsDefault(true);
Thieu Lea20cbc22012-01-09 22:01:43 +0000804 default_service = services_[0];
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700805 } else {
806 default_service = NULL;
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800807 }
808 }
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700809 metrics_->NotifyDefaultServiceChanged(default_service);
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800810
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000811 AutoConnect();
812}
813
Paul Stewart75225512012-01-26 22:51:33 -0800814bool Manager::MatchProfileWithService(const ServiceRefPtr &service) {
815 vector<ProfileRefPtr>::reverse_iterator it;
816 for (it = profiles_.rbegin(); it != profiles_.rend(); ++it) {
817 if ((*it)->ConfigureService(service)) {
818 break;
819 }
820 }
821 if (it == profiles_.rend()) {
822 ephemeral_profile_->AdoptService(service);
823 return false;
824 }
825 return true;
826}
827
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000828void Manager::AutoConnect() {
829 // We might be called in the middle of another request (e.g., as a
830 // consequence of Service::SetState calling UpdateService). To avoid
831 // re-entrancy issues in dbus-c++, defer to the event loop.
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500832 dispatcher_->PostTask(Bind(&Manager::AutoConnectTask, AsWeakPtr()));
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000833}
834
835void Manager::AutoConnectTask() {
836 if (services_.empty()) {
837 LOG(INFO) << "No services.";
838 return;
839 }
840
841 if (VLOG_IS_ON(4)) {
mukesh agrawalddc378f2012-02-17 18:26:20 -0800842 VLOG(4) << "Sorted service list: ";
843 for (size_t i = 0; i < services_.size(); ++i) {
844 ServiceRefPtr service = services_[i];
845 const char *compare_reason = NULL;
846 if (i + 1 < services_.size()) {
847 Service::Compare(
848 service, services_[i+1], technology_order_, &compare_reason);
849 } else {
mukesh agrawalbf14e942012-03-02 14:36:34 -0800850 compare_reason = "last";
mukesh agrawalddc378f2012-02-17 18:26:20 -0800851 }
852 VLOG(4) << "Service " << service->friendly_name()
853 << " IsConnected: " << service->IsConnected()
854 << " IsConnecting: " << service->IsConnecting()
855 << " IsFailed: " << service->IsFailed()
856 << " connectable: " << service->connectable()
857 << " auto_connect: " << service->auto_connect()
858 << " favorite: " << service->favorite()
859 << " priority: " << service->priority()
860 << " security_level: " << service->security_level()
861 << " strength: " << service->strength()
862 << " UniqueName: " << service->UniqueName()
mukesh agrawalbf14e942012-03-02 14:36:34 -0800863 << " sorted: " << compare_reason;
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000864 }
865 }
866
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800867 // Perform auto-connect.
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000868 for (vector<ServiceRefPtr>::iterator it = services_.begin();
869 it != services_.end(); ++it) {
870 if ((*it)->auto_connect()) {
mukesh agrawal592516d2012-01-12 14:01:00 -0800871 LOG(INFO) << "Requesting autoconnect to service "
872 << (*it)->friendly_name() << ".";
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000873 (*it)->AutoConnect();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800874 }
875 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700876}
877
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800878string Manager::CalculateState(Error */*error*/) {
Chris Masoneb925cc82011-06-22 15:39:57 -0700879 return flimflam::kStateOffline;
880}
881
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800882vector<string> Manager::AvailableTechnologies(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -0800883 set<string> unique_technologies;
884 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
885 it != devices_.end(); ++it) {
886 unique_technologies.insert(
887 Technology::NameFromIdentifier((*it)->technology()));
888 }
889 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -0700890}
891
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800892vector<string> Manager::ConnectedTechnologies(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -0800893 set<string> unique_technologies;
894 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
895 it != devices_.end(); ++it) {
896 if ((*it)->IsConnected())
897 unique_technologies.insert(
898 Technology::NameFromIdentifier((*it)->technology()));
899 }
900 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -0700901}
902
Gaurav Shah435de2c2011-11-17 19:01:07 -0800903string Manager::DefaultTechnology(Error *error) {
904 return (!services_.empty() && services_[0]->IsConnected()) ?
905 services_[0]->GetTechnologyString(error) : "";
Chris Masoneb925cc82011-06-22 15:39:57 -0700906}
907
Eric Shienbrood9a245532012-03-07 14:20:39 -0500908vector<string> Manager::EnabledTechnologies(Error */*error*/) {
909 set<string> unique_technologies;
910 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
911 it != devices_.end(); ++it) {
912 if ((*it)->enabled())
913 unique_technologies.insert(
914 Technology::NameFromIdentifier((*it)->technology()));
915 }
916 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -0700917}
918
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800919vector<string> Manager::EnumerateDevices(Error */*error*/) {
Chris Masone3c3f6a12011-07-01 10:01:41 -0700920 vector<string> device_rpc_ids;
921 for (vector<DeviceRefPtr>::const_iterator it = devices_.begin();
922 it != devices_.end();
923 ++it) {
924 device_rpc_ids.push_back((*it)->GetRpcIdentifier());
925 }
926 return device_rpc_ids;
927}
928
Paul Stewart1b253142012-01-26 14:05:52 -0800929vector<string> Manager::EnumerateProfiles(Error */*error*/) {
930 vector<string> profile_rpc_ids;
931 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
932 it != profiles_.end();
933 ++it) {
934 profile_rpc_ids.push_back((*it)->GetRpcIdentifier());
935 }
936 return profile_rpc_ids;
937}
938
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800939vector<string> Manager::EnumerateAvailableServices(Error */*error*/) {
Chris Masone3c3f6a12011-07-01 10:01:41 -0700940 vector<string> service_rpc_ids;
941 for (vector<ServiceRefPtr>::const_iterator it = services_.begin();
942 it != services_.end();
943 ++it) {
944 service_rpc_ids.push_back((*it)->GetRpcIdentifier());
945 }
946 return service_rpc_ids;
947}
948
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800949vector<string> Manager::EnumerateWatchedServices(Error *error) {
Chris Masone6791a432011-07-12 13:23:19 -0700950 // TODO(cmasone): Filter this list for services in appropriate states.
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800951 return EnumerateAvailableServices(error);
Chris Masone3c3f6a12011-07-01 10:01:41 -0700952}
953
Paul Stewart1b253142012-01-26 14:05:52 -0800954string Manager::GetActiveProfileRpcIdentifier(Error */*error*/) {
955 return ActiveProfile()->GetRpcIdentifier();
Chris Masone7aa5f902011-07-11 11:13:35 -0700956}
957
mukesh agrawal32399322011-09-01 10:53:43 -0700958// called via RPC (e.g., from ManagerDBusAdaptor)
Darin Petkovb65c2452012-02-23 15:17:06 +0100959ServiceRefPtr Manager::GetService(const KeyValueStore &args, Error *error) {
Paul Stewart13ed2252012-03-21 12:52:46 -0700960 if (args.ContainsString(flimflam::kGuidProperty)) {
961 ServiceRefPtr service =
962 GetServiceWithGUID(args.GetString(flimflam::kGuidProperty), NULL);
963 if (service) {
Paul Stewartcb59fed2012-03-21 21:14:46 -0700964 service->Configure(args, error);
Paul Stewart13ed2252012-03-21 12:52:46 -0700965 return service;
966 }
967 }
968
Darin Petkovb65c2452012-02-23 15:17:06 +0100969 if (!args.ContainsString(flimflam::kTypeProperty)) {
Paul Stewart7f61e522012-03-22 11:13:45 -0700970 Error::PopulateAndLog(error, Error::kInvalidArguments, kErrorTypeRequired);
Darin Petkovb65c2452012-02-23 15:17:06 +0100971 return NULL;
972 }
973
974 string type = args.GetString(flimflam::kTypeProperty);
975 if (type == flimflam::kTypeWifi) {
976 return GetWifiService(args, error);
977 }
978 if (type == flimflam::kTypeVPN) {
Darin Petkov33af05c2012-02-28 10:10:30 +0100979 return vpn_provider_.GetService(args, error);
Darin Petkovb65c2452012-02-23 15:17:06 +0100980 }
981 error->Populate(Error::kNotSupported, kErrorUnsupportedServiceType);
982 return NULL;
983}
984
mukesh agrawal7a4e4002011-09-06 11:26:05 -0700985WiFiServiceRefPtr Manager::GetWifiService(const KeyValueStore &args,
986 Error *error) {
Paul Stewarta41e38d2011-11-11 07:47:29 -0800987 vector<DeviceRefPtr> wifi_devices;
Paul Stewart22aa71b2011-09-16 12:15:11 -0700988 FilterByTechnology(Technology::kWifi, &wifi_devices);
mukesh agrawal7a4e4002011-09-06 11:26:05 -0700989 if (wifi_devices.empty()) {
Darin Petkovb65c2452012-02-23 15:17:06 +0100990 error->Populate(Error::kInvalidArguments, kErrorNoDevice);
mukesh agrawal7a4e4002011-09-06 11:26:05 -0700991 return NULL;
992 } else {
993 WiFi *wifi = dynamic_cast<WiFi *>(wifi_devices.front().get());
994 CHECK(wifi);
995 return wifi->GetService(args, error);
996 }
997}
998
Paul Stewart7f61e522012-03-22 11:13:45 -0700999// called via RPC (e.g., from ManagerDBusAdaptor)
1000void Manager::ConfigureService(const KeyValueStore &args, Error *error) {
1001 ProfileRefPtr profile = ActiveProfile();
1002 bool profile_specified = args.ContainsString(flimflam::kProfileProperty);
1003 if (profile_specified) {
1004 string profile_rpcid = args.GetString(flimflam::kProfileProperty);
1005 profile = LookupProfileByRpcIdentifier(profile_rpcid);
1006 if (!profile) {
1007 Error::PopulateAndLog(error, Error::kInvalidArguments,
1008 "Invalid profile name " + profile_rpcid);
1009 return;
1010 }
1011 }
1012
1013 ServiceRefPtr service = GetService(args, error);
1014 if (error->IsFailure() || !service) {
1015 LOG(ERROR) << "GetService failed; returning upstream error.";
1016 return;
1017 }
1018
1019 // Overwrte the profile data with the resulting configured service.
1020 if (!profile->UpdateService(service)) {
1021 Error::PopulateAndLog(error, Error::kInternalError,
1022 "Unable to save service to profile");
1023 return;
1024 }
1025
1026 if (HasService(service)) {
1027 // If the service has been registered (it may not be -- as is the case
1028 // with invisible WiFi networks), we can now transfer the service between
1029 // profiles.
1030 if (service->profile() == ephemeral_profile_ ||
1031 (profile_specified && service->profile() != profile)) {
1032 VLOG(2) << "Moving service to profile "
1033 << profile->GetFriendlyName();
1034 if (!MoveServiceToProfile(service, profile)) {
1035 Error::PopulateAndLog(error, Error::kInternalError,
1036 "Unable to move service to profile");
1037 }
1038 }
1039 }
1040}
1041
Paul Stewartc681fa02012-03-02 19:40:04 -08001042void Manager::RecheckPortal(Error */*error*/) {
1043 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1044 it != devices_.end(); ++it) {
1045 if ((*it)->RequestPortalDetection()) {
1046 // Only start Portal Detection on the device with the default connection.
1047 // We will get a "true" return value when we've found that device, and
1048 // can end our loop early as a result.
1049 break;
1050 }
1051 }
1052}
1053
mukesh agrawal7a4e4002011-09-06 11:26:05 -07001054// called via RPC (e.g., from ManagerDBusAdaptor)
Paul Stewart22aa71b2011-09-16 12:15:11 -07001055void Manager::RequestScan(const string &technology, Error *error) {
mukesh agrawal32399322011-09-01 10:53:43 -07001056 if (technology == flimflam::kTypeWifi || technology == "") {
1057 vector<DeviceRefPtr> wifi_devices;
Paul Stewartfdd16072011-09-16 12:41:35 -07001058 FilterByTechnology(Technology::kWifi, &wifi_devices);
mukesh agrawal32399322011-09-01 10:53:43 -07001059
1060 for (vector<DeviceRefPtr>::iterator it = wifi_devices.begin();
1061 it != wifi_devices.end();
1062 ++it) {
Darin Petkovc0865312011-09-16 15:31:20 -07001063 (*it)->Scan(error);
mukesh agrawal32399322011-09-01 10:53:43 -07001064 }
1065 } else {
1066 // TODO(quiche): support scanning for other technologies?
Paul Stewartbe005172011-11-02 18:10:29 -07001067 Error::PopulateAndLog(error, Error::kInvalidArguments,
1068 "Unrecognized technology " + technology);
mukesh agrawal32399322011-09-01 10:53:43 -07001069 }
1070}
1071
Paul Stewart22aa71b2011-09-16 12:15:11 -07001072string Manager::GetTechnologyOrder() {
1073 vector<string> technology_names;
1074 for (vector<Technology::Identifier>::iterator it = technology_order_.begin();
1075 it != technology_order_.end();
1076 ++it) {
1077 technology_names.push_back(Technology::NameFromIdentifier(*it));
1078 }
1079
1080 return JoinString(technology_names, ',');
1081}
1082
1083void Manager::SetTechnologyOrder(const string &order, Error *error) {
1084 vector<Technology::Identifier> new_order;
mukesh agrawal84de5d22012-02-17 19:29:15 -08001085 VLOG(2) << "Setting technology order to " << order;
Paul Stewart20088d82012-02-16 06:58:55 -08001086 if (!Technology::GetTechnologyVectorFromString(order, &new_order, error)) {
1087 return;
Paul Stewart22aa71b2011-09-16 12:15:11 -07001088 }
1089
1090 technology_order_ = new_order;
1091 SortServices();
1092}
1093
Paul Stewart75897df2011-04-27 09:05:53 -07001094} // namespace shill