blob: bf469b07817a244f9b2f72aebc017eeccb7dd380 [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 Stewart66815332012-04-09 18:09:36 -0700320 // Offer the Profile contents to the VPNProvider which will create
321 // new VPN services if necessary.
322 vpn_provider_.CreateServicesFromProfile(profile);
323
Paul Stewart19c871d2011-12-15 16:10:13 -0800324 *path = profile->GetRpcIdentifier();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800325 SortServices();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700326}
327
328void Manager::PopProfileInternal() {
329 CHECK(!profiles_.empty());
330 ProfileRefPtr active_profile = profiles_.back();
331 profiles_.pop_back();
Paul Stewart75225512012-01-26 22:51:33 -0800332 vector<ServiceRefPtr>::iterator it;
Paul Stewart65512e12012-03-26 18:01:08 -0700333 for (it = services_.begin(); it != services_.end();) {
334 if ((*it)->profile().get() != active_profile.get() ||
335 MatchProfileWithService(*it) ||
336 !UnloadService(&it)) {
337 LOG(ERROR) << "Skipping unload of service";
338 ++it;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700339 }
340 }
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800341 SortServices();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700342}
343
Paul Stewarta41e38d2011-11-11 07:47:29 -0800344void Manager::PopProfile(const string &name, Error *error) {
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700345 Profile::Identifier ident;
346 if (profiles_.empty()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700347 Error::PopulateAndLog(error, Error::kNotFound, "Profile stack is empty");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700348 return;
349 }
350 ProfileRefPtr active_profile = profiles_.back();
351 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700352 Error::PopulateAndLog(error, Error::kInvalidArguments,
353 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700354 return;
355 }
356 if (!active_profile->MatchesIdentifier(ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700357 Error::PopulateAndLog(error, Error::kNotSupported,
358 name + " is not the active profile");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700359 return;
360 }
361 PopProfileInternal();
362}
363
364void Manager::PopAnyProfile(Error *error) {
365 Profile::Identifier ident;
366 if (profiles_.empty()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700367 Error::PopulateAndLog(error, Error::kNotFound, "Profile stack is empty");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700368 return;
369 }
370 PopProfileInternal();
371}
372
Paul Stewarte73d05c2012-03-29 16:26:05 -0700373void Manager::RemoveProfile(const string &name, Error *error) {
374 Profile::Identifier ident;
375 if (!Profile::ParseIdentifier(name, &ident)) {
376 Error::PopulateAndLog(error, Error::kInvalidArguments,
377 "Invalid profile name " + name);
378 return;
379 }
380
381 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
382 it != profiles_.end();
383 ++it) {
384 if ((*it)->MatchesIdentifier(ident)) {
385 Error::PopulateAndLog(error, Error::kInvalidArguments,
386 "Cannot remove profile name " + name +
387 " since it is on stack");
388 return;
389 }
390 }
391
392 ProfileRefPtr profile;
393 if (ident.user.empty()) {
394 profile = new DefaultProfile(control_interface_,
395 this,
396 storage_path_,
397 ident.identifier,
398 props_);
399 } else {
400 profile = new Profile(control_interface_,
401 this,
402 ident,
403 user_storage_format_,
404 false);
405 }
406
407
408 // |error| will have been populated if RemoveStorage fails.
409 profile->RemoveStorage(glib_, error);
410
411 return;
412}
413
Paul Stewart75225512012-01-26 22:51:33 -0800414bool Manager::HandleProfileEntryDeletion(const ProfileRefPtr &profile,
415 const std::string &entry_name) {
416 bool moved_services = false;
417 for (vector<ServiceRefPtr>::iterator it = services_.begin();
Paul Stewart65512e12012-03-26 18:01:08 -0700418 it != services_.end();) {
Paul Stewart75225512012-01-26 22:51:33 -0800419 if ((*it)->profile().get() == profile.get() &&
420 (*it)->GetStorageIdentifier() == entry_name) {
421 profile->AbandonService(*it);
Paul Stewart65512e12012-03-26 18:01:08 -0700422 if (MatchProfileWithService(*it) ||
423 !UnloadService(&it)) {
424 ++it;
Paul Stewart75225512012-01-26 22:51:33 -0800425 }
426 moved_services = true;
Paul Stewart65512e12012-03-26 18:01:08 -0700427 } else {
428 ++it;
Paul Stewart75225512012-01-26 22:51:33 -0800429 }
430 }
431 return moved_services;
432}
433
Paul Stewart0756db92012-01-27 08:34:47 -0800434ServiceRefPtr Manager::GetServiceWithStorageIdentifier(
435 const ProfileRefPtr &profile, const std::string &entry_name, Error *error) {
436 for (vector<ServiceRefPtr>::iterator it = services_.begin();
437 it != services_.end(); ++it) {
438 if ((*it)->profile().get() == profile.get() &&
439 (*it)->GetStorageIdentifier() == entry_name) {
440 return *it;
441 }
442 }
443
444 Error::PopulateAndLog(error, Error::kNotFound,
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500445 StringPrintf("Entry %s is not registered in the manager",
446 entry_name.c_str()));
Paul Stewart0756db92012-01-27 08:34:47 -0800447 return NULL;
448}
449
Paul Stewart13ed2252012-03-21 12:52:46 -0700450ServiceRefPtr Manager::GetServiceWithGUID(
451 const std::string &guid, Error *error) {
452 for (vector<ServiceRefPtr>::iterator it = services_.begin();
453 it != services_.end(); ++it) {
454 if ((*it)->guid() == guid) {
455 return *it;
456 }
457 }
458
459 Error::PopulateAndLog(error, Error::kNotFound,
460 StringPrintf("Service wth GUID %s is not registered in the manager",
461 guid.c_str()));
462 return NULL;
463}
464
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700465ServiceRefPtr Manager::GetDefaultService() const {
466 if (services_.empty() || !services_[0]->connection().get()) {
467 VLOG(2) << "In " << __func__ << ": No default connection exists.";
468 return NULL;
469 }
470 return services_[0];
471}
472
Paul Stewart20088d82012-02-16 06:58:55 -0800473bool Manager::IsPortalDetectionEnabled(Technology::Identifier tech) {
474 Error error;
475 vector<Technology::Identifier> portal_technologies;
476 return Technology::GetTechnologyVectorFromString(props_.check_portal_list,
477 &portal_technologies,
478 &error) &&
479 std::find(portal_technologies.begin(), portal_technologies.end(),
480 tech) != portal_technologies.end();
481}
482
Paul Stewart1b253142012-01-26 14:05:52 -0800483const ProfileRefPtr &Manager::ActiveProfile() const {
Eric Shienbroodc74cf9c2012-03-02 15:00:35 -0500484 DCHECK_NE(profiles_.size(), 0U);
Chris Masone7aa5f902011-07-11 11:13:35 -0700485 return profiles_.back();
486}
487
Paul Stewart1b253142012-01-26 14:05:52 -0800488bool Manager::IsActiveProfile(const ProfileRefPtr &profile) const {
489 return (profiles_.size() > 0 &&
490 ActiveProfile().get() == profile.get());
491}
492
Eric Shienbrood9a245532012-03-07 14:20:39 -0500493void Manager::SaveActiveProfile() {
494 if (!profiles_.empty()) {
495 ActiveProfile()->Save();
496 }
497}
498
Chris Masone6515aab2011-10-12 16:19:09 -0700499bool Manager::MoveServiceToProfile(const ServiceRefPtr &to_move,
500 const ProfileRefPtr &destination) {
501 const ProfileRefPtr from = to_move->profile();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800502 VLOG(2) << "Moving service "
503 << to_move->UniqueName()
504 << " to profile "
505 << destination->GetFriendlyName()
506 << " from "
507 << from->GetFriendlyName();
Chris Masone6515aab2011-10-12 16:19:09 -0700508 return destination->AdoptService(to_move) &&
509 from->AbandonService(to_move);
Chris Masone6791a432011-07-12 13:23:19 -0700510}
511
Paul Stewart7f61e522012-03-22 11:13:45 -0700512ProfileRefPtr Manager::LookupProfileByRpcIdentifier(
513 const string &profile_rpcid) {
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800514 for (vector<ProfileRefPtr>::iterator it = profiles_.begin();
515 it != profiles_.end();
516 ++it) {
517 if (profile_rpcid == (*it)->GetRpcIdentifier()) {
Paul Stewart7f61e522012-03-22 11:13:45 -0700518 return *it;
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800519 }
520 }
Paul Stewart7f61e522012-03-22 11:13:45 -0700521 return NULL;
522}
523
524void Manager::SetProfileForService(const ServiceRefPtr &to_set,
525 const string &profile_rpcid,
526 Error *error) {
527 ProfileRefPtr profile = LookupProfileByRpcIdentifier(profile_rpcid);
528 if (!profile) {
529 Error::PopulateAndLog(error, Error::kInvalidArguments,
530 StringPrintf("Unknown Profile %s requested for "
531 "Service", profile_rpcid.c_str()));
532 return;
533 }
534
535 if (to_set->profile().get() == profile.get()) {
536 Error::PopulateAndLog(error, Error::kInvalidArguments,
537 "Service is already connected to this profile");
538 } else if (!MoveServiceToProfile(to_set, profile)) {
539 Error::PopulateAndLog(error, Error::kInternalError,
540 "Unable to move service to profile");
541 }
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800542}
543
Eric Shienbrood9a245532012-03-07 14:20:39 -0500544void Manager::EnableTechnology(const std::string &technology_name,
545 Error *error,
546 const ResultCallback &callback) {
547 Technology::Identifier id = Technology::IdentifierFromName(technology_name);
548 if (id == Technology::kUnknown) {
549 error->Populate(Error::kInvalidArguments, "Unknown technology");
550 return;
551 }
552 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
553 it != devices_.end(); ++it) {
554 DeviceRefPtr device = *it;
555 if (device->technology() == id && !device->enabled()) {
556 device->SetEnabledPersistent(true, error, callback);
557 // Continue with other devices even if one fails
558 // TODO(ers): Decide whether an error should be returned
559 // for the overall EnableTechnology operation if some
560 // devices succeed and some fail.
561 }
562 }
563}
564
565void Manager::DisableTechnology(const std::string &technology_name,
566 Error *error,
567 const ResultCallback &callback) {
568 Technology::Identifier id = Technology::IdentifierFromName(technology_name);
569 if (id == Technology::kUnknown) {
570 error->Populate(Error::kInvalidArguments, "Unknown technology");
571 return;
572 }
573 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
574 it != devices_.end(); ++it) {
575 DeviceRefPtr device = *it;
576 if (device->technology() == id && device->enabled()) {
577 device->SetEnabledPersistent(false, error, callback);
578 // Continue with other devices even if one fails
579 // TODO(ers): Decide whether an error should be returned
580 // for the overall DisableTechnology operation if some
581 // devices succeed and some fail.
582 }
583 }
584}
585
586void Manager::UpdateEnabledTechnologies() {
587 Error error;
588 adaptor_->EmitStringsChanged(flimflam::kEnabledTechnologiesProperty,
589 EnabledTechnologies(&error));
590}
591
Chris Masone2b105542011-06-22 10:58:09 -0700592void Manager::RegisterDevice(const DeviceRefPtr &to_manage) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500593 VLOG(2) << __func__ << "(" << to_manage->FriendlyName() << ")";
Chris Masonec1e50412011-06-07 13:04:53 -0700594 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700595 for (it = devices_.begin(); it != devices_.end(); ++it) {
Chris Masonec1e50412011-06-07 13:04:53 -0700596 if (to_manage.get() == it->get())
Chris Masone9be4a9d2011-05-16 15:44:09 -0700597 return;
598 }
Chris Masonec1e50412011-06-07 13:04:53 -0700599 devices_.push_back(to_manage);
Paul Stewartf1ce5d22011-05-19 13:10:20 -0700600
Paul Stewarta41e38d2011-11-11 07:47:29 -0800601 // We are applying device properties from the DefaultProfile, and adding
602 // the union of hidden services in all loaded profiles to the device.
Chris Masone6515aab2011-10-12 16:19:09 -0700603 for (vector<ProfileRefPtr>::iterator it = profiles_.begin();
604 it != profiles_.end();
605 ++it) {
Paul Stewarta41e38d2011-11-11 07:47:29 -0800606 // Load device configuration, if any exists, as well as hidden services.
607 (*it)->ConfigureDevice(to_manage);
608
609 // Currently the only profile for which "Save" is implemented is the
610 // DefaultProfile. It iterates over all Devices and stores their state.
611 // We perform the Save now in case the device we have just registered
612 // is new and needs to be added to the stored DefaultProfile.
Chris Masone6515aab2011-10-12 16:19:09 -0700613 (*it)->Save();
614 }
Paul Stewarta41e38d2011-11-11 07:47:29 -0800615
616 // In normal usage, running_ will always be true when we are here, however
617 // unit tests sometimes do things in otherwise invalid states.
Eric Shienbrood9a245532012-03-07 14:20:39 -0500618 if (running_ && to_manage->enabled_persistent())
619 to_manage->SetEnabled(true);
Gaurav Shah435de2c2011-11-17 19:01:07 -0800620
Eric Shienbrood8839a892012-03-29 10:33:48 -0400621 EmitDeviceProperties();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700622}
623
mukesh agrawal5029c6c2011-08-25 11:12:40 -0700624void Manager::DeregisterDevice(const DeviceRefPtr &to_forget) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500625 VLOG(2) << __func__ << "(" << to_forget->FriendlyName() << ")";
Chris Masonec1e50412011-06-07 13:04:53 -0700626 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700627 for (it = devices_.begin(); it != devices_.end(); ++it) {
Chris Masonec1e50412011-06-07 13:04:53 -0700628 if (to_forget.get() == it->get()) {
mukesh agrawal5029c6c2011-08-25 11:12:40 -0700629 VLOG(2) << "Deregistered device: " << to_forget->UniqueName();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500630 to_forget->SetEnabled(false);
Chris Masone9be4a9d2011-05-16 15:44:09 -0700631 devices_.erase(it);
Eric Shienbrood8839a892012-03-29 10:33:48 -0400632 EmitDeviceProperties();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700633 return;
634 }
635 }
mukesh agrawal5029c6c2011-08-25 11:12:40 -0700636 VLOG(2) << __func__ << " unknown device: " << to_forget->UniqueName();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700637}
638
Eric Shienbrood8839a892012-03-29 10:33:48 -0400639void Manager::EmitDeviceProperties() {
640 vector<DeviceRefPtr>::iterator it;
641 vector<string> device_paths;
642 for (it = devices_.begin(); it != devices_.end(); ++it) {
643 device_paths.push_back((*it)->GetRpcIdentifier());
644 }
645 adaptor_->EmitRpcIdentifierArrayChanged(flimflam::kDevicesProperty,
646 device_paths);
647 Error error;
648 adaptor_->EmitStringsChanged(flimflam::kAvailableTechnologiesProperty,
649 AvailableTechnologies(&error));
650 adaptor_->EmitStringsChanged(flimflam::kEnabledTechnologiesProperty,
651 EnabledTechnologies(&error));
652}
653
mukesh agrawal4eb4d782011-12-05 17:34:37 +0000654bool Manager::HasService(const ServiceRefPtr &service) {
655 vector<ServiceRefPtr>::iterator it;
656 for (it = services_.begin(); it != services_.end(); ++it) {
657 if ((*it)->UniqueName() == service->UniqueName())
658 return true;
659 }
660 return false;
661}
662
Chris Masone2b105542011-06-22 10:58:09 -0700663void Manager::RegisterService(const ServiceRefPtr &to_manage) {
Gaurav Shahc6d6c722011-11-17 18:59:39 -0800664 VLOG(2) << "In " << __func__ << "(): Registering service "
665 << to_manage->UniqueName();
mukesh agrawald835b202011-10-07 15:26:47 -0700666
Paul Stewart75225512012-01-26 22:51:33 -0800667 MatchProfileWithService(to_manage);
Chris Masone6791a432011-07-12 13:23:19 -0700668
669 // Now add to OUR list.
Chris Masonec1e50412011-06-07 13:04:53 -0700670 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700671 for (it = services_.begin(); it != services_.end(); ++it) {
mukesh agrawald835b202011-10-07 15:26:47 -0700672 CHECK(to_manage->UniqueName() != (*it)->UniqueName());
Chris Masone9be4a9d2011-05-16 15:44:09 -0700673 }
Chris Masonec1e50412011-06-07 13:04:53 -0700674 services_.push_back(to_manage);
Paul Stewart22aa71b2011-09-16 12:15:11 -0700675 SortServices();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700676}
677
Chris Masone6515aab2011-10-12 16:19:09 -0700678void Manager::DeregisterService(const ServiceRefPtr &to_forget) {
Chris Masonec1e50412011-06-07 13:04:53 -0700679 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700680 for (it = services_.begin(); it != services_.end(); ++it) {
Chris Masone6791a432011-07-12 13:23:19 -0700681 if (to_forget->UniqueName() == (*it)->UniqueName()) {
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800682 DCHECK(!(*it)->connection());
Chris Masone9be4a9d2011-05-16 15:44:09 -0700683 services_.erase(it);
Paul Stewart22aa71b2011-09-16 12:15:11 -0700684 SortServices();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700685 return;
686 }
687 }
688}
689
Paul Stewart65512e12012-03-26 18:01:08 -0700690bool Manager::UnloadService(vector<ServiceRefPtr>::iterator *service_iterator) {
691 if (!(**service_iterator)->Unload()) {
692 return false;
693 }
694
695 DCHECK(!(**service_iterator)->connection());
696 *service_iterator = services_.erase(*service_iterator);
697
698 return true;
699}
700
mukesh agrawal00917ce2011-11-22 23:56:55 +0000701void Manager::UpdateService(const ServiceRefPtr &to_update) {
702 CHECK(to_update);
Paul Stewart03dba0b2011-08-22 16:32:45 -0700703 LOG(INFO) << "Service " << to_update->UniqueName() << " updated;"
Gaurav Shahc6d6c722011-11-17 18:59:39 -0800704 << " state: " << Service::ConnectStateToString(to_update->state())
705 << " failure: "
706 << Service::ConnectFailureToString(to_update->failure());
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000707 VLOG(2) << "IsConnected(): " << to_update->IsConnected();
708 VLOG(2) << "IsConnecting(): " << to_update->IsConnecting();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800709 if (to_update->IsConnected()) {
Thieu Led4e9e552012-02-16 16:26:07 -0800710 bool originally_favorite = to_update->favorite();
mukesh agrawal00917ce2011-11-22 23:56:55 +0000711 to_update->MakeFavorite();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800712 if (to_update->profile().get() == ephemeral_profile_.get()) {
713 if (profiles_.empty()) {
714 LOG(ERROR) << "Cannot assign profile to service: no profiles exist!";
715 } else {
716 MoveServiceToProfile(to_update, profiles_.back());
717 }
Thieu Led4e9e552012-02-16 16:26:07 -0800718 } else if (!originally_favorite) {
719 // Persists the updated favorite setting in the profile.
720 to_update->SaveToCurrentProfile();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800721 }
722 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700723 SortServices();
Paul Stewart03dba0b2011-08-22 16:32:45 -0700724}
725
Paul Stewartfdd16072011-09-16 12:41:35 -0700726void Manager::FilterByTechnology(Technology::Identifier tech,
Chris Masonec1e50412011-06-07 13:04:53 -0700727 vector<DeviceRefPtr> *found) {
Chris Masone9be4a9d2011-05-16 15:44:09 -0700728 CHECK(found);
Chris Masonec1e50412011-06-07 13:04:53 -0700729 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700730 for (it = devices_.begin(); it != devices_.end(); ++it) {
731 if ((*it)->TechnologyIs(tech))
732 found->push_back(*it);
733 }
734}
735
Paul Stewart22aa71b2011-09-16 12:15:11 -0700736ServiceRefPtr Manager::FindService(const string& name) {
Chris Masonec1e50412011-06-07 13:04:53 -0700737 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700738 for (it = services_.begin(); it != services_.end(); ++it) {
Chris Masone6791a432011-07-12 13:23:19 -0700739 if (name == (*it)->UniqueName())
Chris Masonee0dea762011-06-09 09:06:03 -0700740 return *it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700741 }
Chris Masonee0dea762011-06-09 09:06:03 -0700742 return NULL;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700743}
744
mukesh agrawal2366eed2012-03-20 18:21:50 -0700745void Manager::HelpRegisterConstDerivedRpcIdentifiers(
746 const string &name,
747 RpcIdentifiers(Manager::*get)(Error *)) {
748 store_.RegisterDerivedRpcIdentifiers(
749 name,
750 RpcIdentifiersAccessor(
751 new CustomAccessor<Manager, RpcIdentifiers>(this, get, NULL)));
752}
753
mukesh agrawalffa3d042011-10-06 15:26:10 -0700754void Manager::HelpRegisterDerivedString(
755 const string &name,
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800756 string(Manager::*get)(Error *),
mukesh agrawalffa3d042011-10-06 15:26:10 -0700757 void(Manager::*set)(const string&, Error *)) {
Chris Masone27c4aa52011-07-02 13:10:14 -0700758 store_.RegisterDerivedString(
759 name,
760 StringAccessor(new CustomAccessor<Manager, string>(this, get, set)));
Chris Masoneb925cc82011-06-22 15:39:57 -0700761}
762
mukesh agrawalffa3d042011-10-06 15:26:10 -0700763void Manager::HelpRegisterDerivedStrings(
764 const string &name,
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800765 Strings(Manager::*get)(Error *),
mukesh agrawalffa3d042011-10-06 15:26:10 -0700766 void(Manager::*set)(const Strings &, Error *)) {
Chris Masone27c4aa52011-07-02 13:10:14 -0700767 store_.RegisterDerivedStrings(
768 name,
769 StringsAccessor(new CustomAccessor<Manager, Strings>(this, get, set)));
Chris Masoneb925cc82011-06-22 15:39:57 -0700770}
771
Paul Stewart22aa71b2011-09-16 12:15:11 -0700772void Manager::SortServices() {
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800773 VLOG(4) << "In " << __func__;
Thieu Lea20cbc22012-01-09 22:01:43 +0000774 ServiceRefPtr default_service;
775
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800776 if (!services_.empty()) {
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700777 // Keep track of the service that is the candidate for the default
778 // service. We have not yet tested to see if this service has a
779 // connection.
Thieu Lea20cbc22012-01-09 22:01:43 +0000780 default_service = services_[0];
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800781 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700782 sort(services_.begin(), services_.end(), ServiceSorter(technology_order_));
Paul Stewarta41e38d2011-11-11 07:47:29 -0800783
784 vector<string> service_paths;
785 vector<ServiceRefPtr>::iterator it;
786 for (it = services_.begin(); it != services_.end(); ++it) {
787 if ((*it)->IsVisible()) {
788 service_paths.push_back((*it)->GetRpcIdentifier());
789 }
790 }
791 adaptor_->EmitRpcIdentifierArrayChanged(flimflam::kServicesProperty,
792 service_paths);
Gaurav Shah435de2c2011-11-17 19:01:07 -0800793
794 Error error;
795 adaptor_->EmitStringsChanged(flimflam::kConnectedTechnologiesProperty,
796 ConnectedTechnologies(&error));
797 adaptor_->EmitStringChanged(flimflam::kDefaultTechnologyProperty,
798 DefaultTechnology(&error));
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800799
800 if (!services_.empty()) {
Thieu Lea20cbc22012-01-09 22:01:43 +0000801 ConnectionRefPtr default_connection = default_service->connection();
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800802 if (default_connection.get() &&
803 (services_[0]->connection().get() != default_connection.get())) {
804 default_connection->SetIsDefault(false);
805 }
806 if (services_[0]->connection().get()) {
807 services_[0]->connection()->SetIsDefault(true);
Thieu Lea20cbc22012-01-09 22:01:43 +0000808 default_service = services_[0];
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700809 } else {
810 default_service = NULL;
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800811 }
812 }
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700813 metrics_->NotifyDefaultServiceChanged(default_service);
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800814
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000815 AutoConnect();
816}
817
Paul Stewart75225512012-01-26 22:51:33 -0800818bool Manager::MatchProfileWithService(const ServiceRefPtr &service) {
819 vector<ProfileRefPtr>::reverse_iterator it;
820 for (it = profiles_.rbegin(); it != profiles_.rend(); ++it) {
821 if ((*it)->ConfigureService(service)) {
822 break;
823 }
824 }
825 if (it == profiles_.rend()) {
826 ephemeral_profile_->AdoptService(service);
827 return false;
828 }
829 return true;
830}
831
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000832void Manager::AutoConnect() {
833 // We might be called in the middle of another request (e.g., as a
834 // consequence of Service::SetState calling UpdateService). To avoid
835 // re-entrancy issues in dbus-c++, defer to the event loop.
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500836 dispatcher_->PostTask(Bind(&Manager::AutoConnectTask, AsWeakPtr()));
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000837}
838
839void Manager::AutoConnectTask() {
840 if (services_.empty()) {
841 LOG(INFO) << "No services.";
842 return;
843 }
844
845 if (VLOG_IS_ON(4)) {
mukesh agrawalddc378f2012-02-17 18:26:20 -0800846 VLOG(4) << "Sorted service list: ";
847 for (size_t i = 0; i < services_.size(); ++i) {
848 ServiceRefPtr service = services_[i];
849 const char *compare_reason = NULL;
850 if (i + 1 < services_.size()) {
851 Service::Compare(
852 service, services_[i+1], technology_order_, &compare_reason);
853 } else {
mukesh agrawalbf14e942012-03-02 14:36:34 -0800854 compare_reason = "last";
mukesh agrawalddc378f2012-02-17 18:26:20 -0800855 }
856 VLOG(4) << "Service " << service->friendly_name()
857 << " IsConnected: " << service->IsConnected()
858 << " IsConnecting: " << service->IsConnecting()
859 << " IsFailed: " << service->IsFailed()
860 << " connectable: " << service->connectable()
861 << " auto_connect: " << service->auto_connect()
862 << " favorite: " << service->favorite()
863 << " priority: " << service->priority()
864 << " security_level: " << service->security_level()
865 << " strength: " << service->strength()
866 << " UniqueName: " << service->UniqueName()
mukesh agrawalbf14e942012-03-02 14:36:34 -0800867 << " sorted: " << compare_reason;
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000868 }
869 }
870
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800871 // Perform auto-connect.
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000872 for (vector<ServiceRefPtr>::iterator it = services_.begin();
873 it != services_.end(); ++it) {
874 if ((*it)->auto_connect()) {
mukesh agrawal592516d2012-01-12 14:01:00 -0800875 LOG(INFO) << "Requesting autoconnect to service "
876 << (*it)->friendly_name() << ".";
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000877 (*it)->AutoConnect();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800878 }
879 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700880}
881
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800882string Manager::CalculateState(Error */*error*/) {
Gary Morain028545d2012-04-07 14:55:52 -0700883 // |services_| is sorted such that connected services are first.
884 if (!services_.empty() &&
885 services_.front()->IsConnected()) {
886 return flimflam::kStateOnline;
887 }
Chris Masoneb925cc82011-06-22 15:39:57 -0700888 return flimflam::kStateOffline;
889}
890
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800891vector<string> Manager::AvailableTechnologies(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -0800892 set<string> unique_technologies;
893 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
894 it != devices_.end(); ++it) {
895 unique_technologies.insert(
896 Technology::NameFromIdentifier((*it)->technology()));
897 }
898 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -0700899}
900
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800901vector<string> Manager::ConnectedTechnologies(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -0800902 set<string> unique_technologies;
903 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
904 it != devices_.end(); ++it) {
905 if ((*it)->IsConnected())
906 unique_technologies.insert(
907 Technology::NameFromIdentifier((*it)->technology()));
908 }
909 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -0700910}
911
Gaurav Shah435de2c2011-11-17 19:01:07 -0800912string Manager::DefaultTechnology(Error *error) {
913 return (!services_.empty() && services_[0]->IsConnected()) ?
914 services_[0]->GetTechnologyString(error) : "";
Chris Masoneb925cc82011-06-22 15:39:57 -0700915}
916
Eric Shienbrood9a245532012-03-07 14:20:39 -0500917vector<string> Manager::EnabledTechnologies(Error */*error*/) {
918 set<string> unique_technologies;
919 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
920 it != devices_.end(); ++it) {
921 if ((*it)->enabled())
922 unique_technologies.insert(
923 Technology::NameFromIdentifier((*it)->technology()));
924 }
925 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -0700926}
927
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800928vector<string> Manager::EnumerateDevices(Error */*error*/) {
Chris Masone3c3f6a12011-07-01 10:01:41 -0700929 vector<string> device_rpc_ids;
930 for (vector<DeviceRefPtr>::const_iterator it = devices_.begin();
931 it != devices_.end();
932 ++it) {
933 device_rpc_ids.push_back((*it)->GetRpcIdentifier());
934 }
935 return device_rpc_ids;
936}
937
Paul Stewart1b253142012-01-26 14:05:52 -0800938vector<string> Manager::EnumerateProfiles(Error */*error*/) {
939 vector<string> profile_rpc_ids;
940 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
941 it != profiles_.end();
942 ++it) {
943 profile_rpc_ids.push_back((*it)->GetRpcIdentifier());
944 }
945 return profile_rpc_ids;
946}
947
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800948vector<string> Manager::EnumerateAvailableServices(Error */*error*/) {
Chris Masone3c3f6a12011-07-01 10:01:41 -0700949 vector<string> service_rpc_ids;
950 for (vector<ServiceRefPtr>::const_iterator it = services_.begin();
951 it != services_.end();
952 ++it) {
953 service_rpc_ids.push_back((*it)->GetRpcIdentifier());
954 }
955 return service_rpc_ids;
956}
957
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800958vector<string> Manager::EnumerateWatchedServices(Error *error) {
Chris Masone6791a432011-07-12 13:23:19 -0700959 // TODO(cmasone): Filter this list for services in appropriate states.
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800960 return EnumerateAvailableServices(error);
Chris Masone3c3f6a12011-07-01 10:01:41 -0700961}
962
Paul Stewart1b253142012-01-26 14:05:52 -0800963string Manager::GetActiveProfileRpcIdentifier(Error */*error*/) {
964 return ActiveProfile()->GetRpcIdentifier();
Chris Masone7aa5f902011-07-11 11:13:35 -0700965}
966
mukesh agrawal32399322011-09-01 10:53:43 -0700967// called via RPC (e.g., from ManagerDBusAdaptor)
Darin Petkovb65c2452012-02-23 15:17:06 +0100968ServiceRefPtr Manager::GetService(const KeyValueStore &args, Error *error) {
Paul Stewart13ed2252012-03-21 12:52:46 -0700969 if (args.ContainsString(flimflam::kGuidProperty)) {
970 ServiceRefPtr service =
971 GetServiceWithGUID(args.GetString(flimflam::kGuidProperty), NULL);
972 if (service) {
Paul Stewartcb59fed2012-03-21 21:14:46 -0700973 service->Configure(args, error);
Paul Stewart13ed2252012-03-21 12:52:46 -0700974 return service;
975 }
976 }
977
Darin Petkovb65c2452012-02-23 15:17:06 +0100978 if (!args.ContainsString(flimflam::kTypeProperty)) {
Paul Stewart7f61e522012-03-22 11:13:45 -0700979 Error::PopulateAndLog(error, Error::kInvalidArguments, kErrorTypeRequired);
Darin Petkovb65c2452012-02-23 15:17:06 +0100980 return NULL;
981 }
982
983 string type = args.GetString(flimflam::kTypeProperty);
984 if (type == flimflam::kTypeWifi) {
985 return GetWifiService(args, error);
986 }
987 if (type == flimflam::kTypeVPN) {
Darin Petkov33af05c2012-02-28 10:10:30 +0100988 return vpn_provider_.GetService(args, error);
Darin Petkovb65c2452012-02-23 15:17:06 +0100989 }
990 error->Populate(Error::kNotSupported, kErrorUnsupportedServiceType);
991 return NULL;
992}
993
mukesh agrawal7a4e4002011-09-06 11:26:05 -0700994WiFiServiceRefPtr Manager::GetWifiService(const KeyValueStore &args,
995 Error *error) {
Paul Stewarta41e38d2011-11-11 07:47:29 -0800996 vector<DeviceRefPtr> wifi_devices;
Paul Stewart22aa71b2011-09-16 12:15:11 -0700997 FilterByTechnology(Technology::kWifi, &wifi_devices);
mukesh agrawal7a4e4002011-09-06 11:26:05 -0700998 if (wifi_devices.empty()) {
Darin Petkovb65c2452012-02-23 15:17:06 +0100999 error->Populate(Error::kInvalidArguments, kErrorNoDevice);
mukesh agrawal7a4e4002011-09-06 11:26:05 -07001000 return NULL;
1001 } else {
1002 WiFi *wifi = dynamic_cast<WiFi *>(wifi_devices.front().get());
1003 CHECK(wifi);
1004 return wifi->GetService(args, error);
1005 }
1006}
1007
Paul Stewart7f61e522012-03-22 11:13:45 -07001008// called via RPC (e.g., from ManagerDBusAdaptor)
1009void Manager::ConfigureService(const KeyValueStore &args, Error *error) {
1010 ProfileRefPtr profile = ActiveProfile();
1011 bool profile_specified = args.ContainsString(flimflam::kProfileProperty);
1012 if (profile_specified) {
1013 string profile_rpcid = args.GetString(flimflam::kProfileProperty);
1014 profile = LookupProfileByRpcIdentifier(profile_rpcid);
1015 if (!profile) {
1016 Error::PopulateAndLog(error, Error::kInvalidArguments,
1017 "Invalid profile name " + profile_rpcid);
1018 return;
1019 }
1020 }
1021
1022 ServiceRefPtr service = GetService(args, error);
1023 if (error->IsFailure() || !service) {
1024 LOG(ERROR) << "GetService failed; returning upstream error.";
1025 return;
1026 }
1027
1028 // Overwrte the profile data with the resulting configured service.
1029 if (!profile->UpdateService(service)) {
1030 Error::PopulateAndLog(error, Error::kInternalError,
1031 "Unable to save service to profile");
1032 return;
1033 }
1034
1035 if (HasService(service)) {
1036 // If the service has been registered (it may not be -- as is the case
1037 // with invisible WiFi networks), we can now transfer the service between
1038 // profiles.
1039 if (service->profile() == ephemeral_profile_ ||
1040 (profile_specified && service->profile() != profile)) {
1041 VLOG(2) << "Moving service to profile "
1042 << profile->GetFriendlyName();
1043 if (!MoveServiceToProfile(service, profile)) {
1044 Error::PopulateAndLog(error, Error::kInternalError,
1045 "Unable to move service to profile");
1046 }
1047 }
1048 }
1049}
1050
Paul Stewartc681fa02012-03-02 19:40:04 -08001051void Manager::RecheckPortal(Error */*error*/) {
1052 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1053 it != devices_.end(); ++it) {
1054 if ((*it)->RequestPortalDetection()) {
1055 // Only start Portal Detection on the device with the default connection.
1056 // We will get a "true" return value when we've found that device, and
1057 // can end our loop early as a result.
1058 break;
1059 }
1060 }
1061}
1062
mukesh agrawal7a4e4002011-09-06 11:26:05 -07001063// called via RPC (e.g., from ManagerDBusAdaptor)
Paul Stewart22aa71b2011-09-16 12:15:11 -07001064void Manager::RequestScan(const string &technology, Error *error) {
mukesh agrawal32399322011-09-01 10:53:43 -07001065 if (technology == flimflam::kTypeWifi || technology == "") {
1066 vector<DeviceRefPtr> wifi_devices;
Paul Stewartfdd16072011-09-16 12:41:35 -07001067 FilterByTechnology(Technology::kWifi, &wifi_devices);
mukesh agrawal32399322011-09-01 10:53:43 -07001068
1069 for (vector<DeviceRefPtr>::iterator it = wifi_devices.begin();
1070 it != wifi_devices.end();
1071 ++it) {
Darin Petkovc0865312011-09-16 15:31:20 -07001072 (*it)->Scan(error);
mukesh agrawal32399322011-09-01 10:53:43 -07001073 }
1074 } else {
1075 // TODO(quiche): support scanning for other technologies?
Paul Stewartbe005172011-11-02 18:10:29 -07001076 Error::PopulateAndLog(error, Error::kInvalidArguments,
1077 "Unrecognized technology " + technology);
mukesh agrawal32399322011-09-01 10:53:43 -07001078 }
1079}
1080
Paul Stewart22aa71b2011-09-16 12:15:11 -07001081string Manager::GetTechnologyOrder() {
1082 vector<string> technology_names;
1083 for (vector<Technology::Identifier>::iterator it = technology_order_.begin();
1084 it != technology_order_.end();
1085 ++it) {
1086 technology_names.push_back(Technology::NameFromIdentifier(*it));
1087 }
1088
1089 return JoinString(technology_names, ',');
1090}
1091
1092void Manager::SetTechnologyOrder(const string &order, Error *error) {
1093 vector<Technology::Identifier> new_order;
mukesh agrawal84de5d22012-02-17 19:29:15 -08001094 VLOG(2) << "Setting technology order to " << order;
Paul Stewart20088d82012-02-16 06:58:55 -08001095 if (!Technology::GetTechnologyVectorFromString(order, &new_order, error)) {
1096 return;
Paul Stewart22aa71b2011-09-16 12:15:11 -07001097 }
1098
1099 technology_order_ = new_order;
1100 SortServices();
1101}
1102
Paul Stewart75897df2011-04-27 09:05:53 -07001103} // namespace shill