blob: 07e4a11216e1fc03e8e7fa2e2940d349c89f9e0f [file] [log] [blame]
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Paul Stewart75897df2011-04-27 09:05:53 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Chris Masone8fe2c7e2011-06-09 15:51:19 -07005#include "shill/manager.h"
6
Paul Stewart75897df2011-04-27 09:05:53 -07007#include <time.h>
Paul Stewart75897df2011-04-27 09:05:53 -07008#include <stdio.h>
Chris Masoneee929b72011-05-10 10:02:18 -07009
Paul Stewart22aa71b2011-09-16 12:15:11 -070010#include <algorithm>
Jason Glasgowdf7c5532012-05-14 14:41:45 -040011#include <set>
Paul Stewart75897df2011-04-27 09:05:53 -070012#include <string>
Chris Masone52cd19b2011-06-29 17:23:04 -070013#include <vector>
Paul Stewart75897df2011-04-27 09:05:53 -070014
Eric Shienbrood3e20a232012-02-16 11:35:56 -050015#include <base/bind.h>
Paul Stewarte6132022011-08-16 09:11:02 -070016#include <base/file_util.h>
Chris 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"
Darin Petkov002c58e2012-06-19 02:56:05 +020026#include "shill/dbus_manager.h"
Chris Masone7aa5f902011-07-11 11:13:35 -070027#include "shill/default_profile.h"
Chris Masone9be4a9d2011-05-16 15:44:09 -070028#include "shill/device.h"
29#include "shill/device_info.h"
Chris Masone6791a432011-07-12 13:23:19 -070030#include "shill/ephemeral_profile.h"
Chris Masone8fe2c7e2011-06-09 15:51:19 -070031#include "shill/error.h"
Paul Stewart26b327e2011-10-19 11:38:09 -070032#include "shill/event_dispatcher.h"
Gary Moraina9fb3252012-05-31 12:05:31 -070033#include "shill/hook_table.h"
Chris Masone9d779932011-08-25 16:33:41 -070034#include "shill/key_file_store.h"
Christopher Wileyb691efd2012-08-09 13:51:51 -070035#include "shill/logging.h"
Thieu Lea20cbc22012-01-09 22:01:43 +000036#include "shill/metrics.h"
Chris Masone7aa5f902011-07-11 11:13:35 -070037#include "shill/profile.h"
Chris Masoneb925cc82011-06-22 15:39:57 -070038#include "shill/property_accessor.h"
Gary Morainac1bdb42012-02-16 17:42:29 -080039#include "shill/proxy_factory.h"
Paul Stewarte6132022011-08-16 09:11:02 -070040#include "shill/resolver.h"
Chris Masone9be4a9d2011-05-16 15:44:09 -070041#include "shill/service.h"
Thieu Lea20cbc22012-01-09 22:01:43 +000042#include "shill/service_sorter.h"
Darin Petkov33af05c2012-02-28 10:10:30 +010043#include "shill/vpn_service.h"
mukesh agrawal7a4e4002011-09-06 11:26:05 -070044#include "shill/wifi.h"
45#include "shill/wifi_service.h"
Darin Petkovd1cd7972012-05-22 15:26:15 +020046#include "shill/wimax_service.h"
Paul Stewart75897df2011-04-27 09:05:53 -070047
Eric Shienbrood3e20a232012-02-16 11:35:56 -050048using base::Bind;
49using base::StringPrintf;
50using base::Unretained;
Darin Petkova5e07ef2012-07-09 14:27:57 +020051using std::map;
Gaurav Shah435de2c2011-11-17 19:01:07 -080052using std::set;
Paul Stewart75897df2011-04-27 09:05:53 -070053using std::string;
Chris Masone9be4a9d2011-05-16 15:44:09 -070054using std::vector;
Paul Stewart75897df2011-04-27 09:05:53 -070055
56namespace shill {
Paul Stewarte6132022011-08-16 09:11:02 -070057
Darin Petkovb65c2452012-02-23 15:17:06 +010058// statics
59const char Manager::kErrorNoDevice[] = "no wifi devices available";
60const char Manager::kErrorTypeRequired[] = "must specify service type";
61const char Manager::kErrorUnsupportedServiceType[] =
62 "service type is unsupported";
mukesh agrawal7a4e4002011-09-06 11:26:05 -070063
Paul Stewart75897df2011-04-27 09:05:53 -070064Manager::Manager(ControlInterface *control_interface,
Darin Petkov887f2982011-07-14 16:10:17 -070065 EventDispatcher *dispatcher,
Thieu Le3426c8f2012-01-11 17:35:11 -080066 Metrics *metrics,
Chris Masone2ae797d2011-08-23 20:41:00 -070067 GLib *glib,
68 const string &run_directory,
69 const string &storage_directory,
70 const string &user_storage_format)
mukesh agrawal8a3188d2011-12-01 20:56:44 +000071 : dispatcher_(dispatcher),
mukesh agrawal8a3188d2011-12-01 20:56:44 +000072 run_path_(FilePath(run_directory)),
73 storage_path_(FilePath(storage_directory)),
74 user_storage_format_(user_storage_format),
75 adaptor_(control_interface->CreateManagerAdaptor(this)),
Thieu Le3426c8f2012-01-11 17:35:11 -080076 device_info_(control_interface, dispatcher, metrics, this),
77 modem_info_(control_interface, dispatcher, metrics, this, glib),
Darin Petkov33af05c2012-02-28 10:10:30 +010078 vpn_provider_(control_interface, dispatcher, metrics, this),
Darin Petkovb72b62e2012-05-15 16:55:36 +020079 wimax_provider_(control_interface, dispatcher, metrics, this),
mukesh agrawal8a3188d2011-12-01 20:56:44 +000080 running_(false),
81 connect_profiles_to_rpc_(true),
82 ephemeral_profile_(new EphemeralProfile(control_interface, this)),
83 control_interface_(control_interface),
Thieu Le3426c8f2012-01-11 17:35:11 -080084 metrics_(metrics),
Paul Stewart10e9e4e2012-04-26 19:46:28 -070085 glib_(glib),
Gary Moraina9fb3252012-05-31 12:05:31 -070086 use_startup_portal_list_(false),
Darin Petkova5e07ef2012-07-09 14:27:57 +020087 termination_actions_(dispatcher),
88 default_service_callback_tag_(0) {
Chris Masone7aa5f902011-07-11 11:13:35 -070089 HelpRegisterDerivedString(flimflam::kActiveProfileProperty,
Paul Stewart1b253142012-01-26 14:05:52 -080090 &Manager::GetActiveProfileRpcIdentifier,
Chris Masone7aa5f902011-07-11 11:13:35 -070091 NULL);
Paul Stewartd408fdf2012-05-07 17:15:57 -070092 store_.RegisterBool(flimflam::kArpGatewayProperty, &props_.arp_gateway);
Chris Masone27c4aa52011-07-02 13:10:14 -070093 HelpRegisterDerivedStrings(flimflam::kAvailableTechnologiesProperty,
94 &Manager::AvailableTechnologies,
95 NULL);
Paul Stewart10e9e4e2012-04-26 19:46:28 -070096 HelpRegisterDerivedString(flimflam::kCheckPortalListProperty,
97 &Manager::GetCheckPortalList,
98 &Manager::SetCheckPortalList);
Chris Masone27c4aa52011-07-02 13:10:14 -070099 HelpRegisterDerivedStrings(flimflam::kConnectedTechnologiesProperty,
100 &Manager::ConnectedTechnologies,
101 NULL);
Chris Masone88cbd5f2011-07-03 14:30:04 -0700102 store_.RegisterString(flimflam::kCountryProperty, &props_.country);
Chris Masone27c4aa52011-07-02 13:10:14 -0700103 HelpRegisterDerivedString(flimflam::kDefaultTechnologyProperty,
104 &Manager::DefaultTechnology,
105 NULL);
Paul Stewart49739c02012-08-08 17:24:03 -0700106 HelpRegisterConstDerivedRpcIdentifier(
107 shill::kDefaultServiceProperty,
108 &Manager::GetDefaultServiceRpcIdentifier);
Paul Stewartcb3eb892012-06-07 14:24:46 -0700109 HelpRegisterConstDerivedRpcIdentifiers(flimflam::kDevicesProperty,
110 &Manager::EnumerateDevices);
Chris Masone88cbd5f2011-07-03 14:30:04 -0700111 HelpRegisterDerivedStrings(flimflam::kEnabledTechnologiesProperty,
112 &Manager::EnabledTechnologies,
113 NULL);
Paul Stewart036dba02012-08-07 12:34:41 -0700114 store_.RegisterString(shill::kLinkMonitorTechnologiesProperty,
115 &props_.link_monitor_technologies);
Chris Masone88cbd5f2011-07-03 14:30:04 -0700116 store_.RegisterBool(flimflam::kOfflineModeProperty, &props_.offline_mode);
117 store_.RegisterString(flimflam::kPortalURLProperty, &props_.portal_url);
Paul Stewartc681fa02012-03-02 19:40:04 -0800118 store_.RegisterInt32(kPortalCheckIntervalProperty,
119 &props_.portal_check_interval_seconds);
Paul Stewartcb3eb892012-06-07 14:24:46 -0700120 HelpRegisterConstDerivedRpcIdentifiers(flimflam::kProfilesProperty,
121 &Manager::EnumerateProfiles);
Paul Stewartc681fa02012-03-02 19:40:04 -0800122 store_.RegisterString(kHostNameProperty, &props_.host_name);
Chris Masone88cbd5f2011-07-03 14:30:04 -0700123 HelpRegisterDerivedString(flimflam::kStateProperty,
124 &Manager::CalculateState,
125 NULL);
mukesh agrawal2366eed2012-03-20 18:21:50 -0700126 HelpRegisterConstDerivedRpcIdentifiers(flimflam::kServicesProperty,
127 &Manager::EnumerateAvailableServices);
Paul Stewartcb3eb892012-06-07 14:24:46 -0700128 HelpRegisterConstDerivedRpcIdentifiers(flimflam::kServiceWatchListProperty,
129 &Manager::EnumerateWatchedServices);
Paul Stewartbf667612012-06-29 14:49:54 -0700130 store_.RegisterString(shill::kShortDNSTimeoutTechnologiesProperty,
131 &props_.short_dns_timeout_technologies);
Chris Masone3c3f6a12011-07-01 10:01:41 -0700132
mukesh agrawal84de5d22012-02-17 19:29:15 -0800133 // Set default technology order "by hand", to avoid invoking side
134 // effects of SetTechnologyOrder.
135 technology_order_.push_back(
Darin Petkov2f903b32012-04-18 12:56:43 +0200136 Technology::IdentifierFromName(flimflam::kTypeVPN));
137 technology_order_.push_back(
mukesh agrawal84de5d22012-02-17 19:29:15 -0800138 Technology::IdentifierFromName(flimflam::kTypeEthernet));
139 technology_order_.push_back(
Darin Petkove08d9192012-05-21 12:21:15 +0200140 Technology::IdentifierFromName(flimflam::kTypeWimax));
141 technology_order_.push_back(
mukesh agrawal84de5d22012-02-17 19:29:15 -0800142 Technology::IdentifierFromName(flimflam::kTypeWifi));
143 technology_order_.push_back(
144 Technology::IdentifierFromName(flimflam::kTypeCellular));
145
Ben Chanfad4a0b2012-04-18 15:49:59 -0700146 SLOG(Manager, 2) << "Manager initialized.";
Paul Stewart75897df2011-04-27 09:05:53 -0700147}
148
Darin Petkove7c6ad32012-06-29 10:22:09 +0200149Manager::~Manager() {}
Paul Stewart75897df2011-04-27 09:05:53 -0700150
mukesh agrawal8f317b62011-07-15 11:53:23 -0700151void Manager::AddDeviceToBlackList(const string &device_name) {
152 device_info_.AddDeviceToBlackList(device_name);
153}
154
Paul Stewart75897df2011-04-27 09:05:53 -0700155void Manager::Start() {
Paul Stewart0af98bf2011-05-10 17:38:08 -0700156 LOG(INFO) << "Manager started.";
Paul Stewarte6132022011-08-16 09:11:02 -0700157
Darin Petkov002c58e2012-06-19 02:56:05 +0200158 dbus_manager_.reset(new DBusManager());
159 dbus_manager_->Start();
160
Gary Morainac1bdb42012-02-16 17:42:29 -0800161 power_manager_.reset(new PowerManager(ProxyFactory::GetInstance()));
Darin Petkovca621542012-07-25 14:25:56 +0200162 power_manager_->AddStateChangeCallback(
163 "manager",
164 Bind(&Manager::OnPowerStateChanged, AsWeakPtr()));
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500165 // TODO(ers): weak ptr for metrics_?
166 PowerManager::PowerStateCallback cb =
167 Bind(&Metrics::NotifyPowerStateChange, Unretained(metrics_));
Thieu Leb84ba342012-03-02 15:15:19 -0800168 power_manager_->AddStateChangeCallback(Metrics::kMetricPowerManagerKey, cb);
169
Chris Masone2ae797d2011-08-23 20:41:00 -0700170 CHECK(file_util::CreateDirectory(run_path_)) << run_path_.value();
Paul Stewarte6132022011-08-16 09:11:02 -0700171 Resolver::GetInstance()->set_path(run_path_.Append("resolv.conf"));
Chris Masone2ae797d2011-08-23 20:41:00 -0700172
Gaurav Shah71354762011-11-28 19:22:49 -0800173 InitializeProfiles();
Paul Stewart75897df2011-04-27 09:05:53 -0700174 running_ = true;
Chris Masone413a3192011-05-09 17:10:05 -0700175 adaptor_->UpdateRunning();
Paul Stewart0af98bf2011-05-10 17:38:08 -0700176 device_info_.Start();
Darin Petkov887f2982011-07-14 16:10:17 -0700177 modem_info_.Start();
Darin Petkov33af05c2012-02-28 10:10:30 +0100178 vpn_provider_.Start();
Darin Petkov9893d9c2012-05-17 15:27:31 -0700179 wimax_provider_.Start();
Paul Stewart75897df2011-04-27 09:05:53 -0700180}
181
182void Manager::Stop() {
183 running_ = false;
Paul Stewart212d60f2012-07-12 10:59:13 -0700184 // Persist device information to disk;
185 vector<DeviceRefPtr>::iterator devices_it;
186 for (devices_it = devices_.begin(); devices_it != devices_.end();
187 ++devices_it) {
188 UpdateDevice(*devices_it);
189 }
190
191 // Persist profile, service information to disk.
192 vector<ProfileRefPtr>::iterator profiles_it;
193 for (profiles_it = profiles_.begin(); profiles_it != profiles_.end();
194 ++profiles_it) {
Paul Stewartd0a3b812012-03-28 22:48:22 -0700195 // Since this happens in a loop, the current manager state is stored to
196 // all default profiles in the stack. This is acceptable because the
197 // only time multiple default profiles are loaded are during autotests.
Paul Stewart212d60f2012-07-12 10:59:13 -0700198 (*profiles_it)->Save();
Chris Masone9d779932011-08-25 16:33:41 -0700199 }
Chris Masone9d779932011-08-25 16:33:41 -0700200
Thieu Le1271d682011-11-02 22:48:19 +0000201 vector<ServiceRefPtr>::iterator services_it;
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000202 Error e;
Thieu Le1271d682011-11-02 22:48:19 +0000203 for (services_it = services_.begin(); services_it != services_.end();
204 ++services_it) {
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000205 (*services_it)->Disconnect(&e);
Thieu Le1271d682011-11-02 22:48:19 +0000206 }
207
Chris Masone413a3192011-05-09 17:10:05 -0700208 adaptor_->UpdateRunning();
Darin Petkovb72b62e2012-05-15 16:55:36 +0200209 wimax_provider_.Stop();
Darin Petkov33af05c2012-02-28 10:10:30 +0100210 vpn_provider_.Stop();
Darin Petkov887f2982011-07-14 16:10:17 -0700211 modem_info_.Stop();
212 device_info_.Stop();
Paul Stewartdfa46052012-06-26 09:44:14 -0700213 sort_services_task_.Cancel();
Darin Petkovca621542012-07-25 14:25:56 +0200214 power_manager_.reset();
Darin Petkov002c58e2012-06-19 02:56:05 +0200215 dbus_manager_.reset();
Paul Stewart75897df2011-04-27 09:05:53 -0700216}
217
Gaurav Shah71354762011-11-28 19:22:49 -0800218void Manager::InitializeProfiles() {
219 DCHECK(profiles_.empty());
220 // The default profile must go first on the stack.
221 CHECK(file_util::CreateDirectory(storage_path_)) << storage_path_.value();
Paul Stewart870523b2012-01-11 17:00:42 -0800222 scoped_refptr<DefaultProfile>
223 default_profile(new DefaultProfile(control_interface_,
Gaurav Shah71354762011-11-28 19:22:49 -0800224 this,
225 storage_path_,
Paul Stewartd0a3b812012-03-28 22:48:22 -0700226 DefaultProfile::kDefaultId,
Gaurav Shah71354762011-11-28 19:22:49 -0800227 props_));
Paul Stewart870523b2012-01-11 17:00:42 -0800228 CHECK(default_profile->InitStorage(glib_, Profile::kCreateOrOpenExisting,
229 NULL));
230 CHECK(default_profile->LoadManagerProperties(&props_));
231 profiles_.push_back(default_profile.release());
Gaurav Shah71354762011-11-28 19:22:49 -0800232 Error error;
Paul Stewart19c871d2011-12-15 16:10:13 -0800233 string path;
Gaurav Shah71354762011-11-28 19:22:49 -0800234 for (vector<string>::iterator it = startup_profiles_.begin();
235 it != startup_profiles_.end(); ++it)
Paul Stewart19c871d2011-12-15 16:10:13 -0800236 PushProfile(*it, &path, &error);
Gaurav Shah71354762011-11-28 19:22:49 -0800237}
238
Paul Stewart19c871d2011-12-15 16:10:13 -0800239void Manager::CreateProfile(const string &name, string *path, Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700240 SLOG(Manager, 2) << __func__ << " " << name;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700241 Profile::Identifier ident;
242 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700243 Error::PopulateAndLog(error, Error::kInvalidArguments,
244 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700245 return;
246 }
Paul Stewartd0a3b812012-03-28 22:48:22 -0700247
Paul Stewartfc9a1da2012-06-27 15:54:52 -0700248 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
249 it != profiles_.end();
250 ++it) {
251 if ((*it)->MatchesIdentifier(ident)) {
252 Error::PopulateAndLog(error, Error::kAlreadyExists,
253 "Profile name " + name + " is already on stack");
254 *path = (*it)->GetRpcIdentifier();
255 return;
256 }
257 }
258
Paul Stewartd0a3b812012-03-28 22:48:22 -0700259 ProfileRefPtr profile;
260 if (ident.user.empty()) {
261 profile = new DefaultProfile(control_interface_,
262 this,
263 storage_path_,
264 ident.identifier,
265 props_);
266 } else {
267 profile = new Profile(control_interface_,
268 this,
269 ident,
270 user_storage_format_,
Gary Morainb672d352012-04-25 09:19:06 -0700271 true);
Paul Stewartd0a3b812012-03-28 22:48:22 -0700272 }
273
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700274 if (!profile->InitStorage(glib_, Profile::kCreateNew, error)) {
Paul Stewart19c871d2011-12-15 16:10:13 -0800275 // |error| will have been populated by InitStorage().
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700276 return;
277 }
278
279 // Save profile data out, and then let the scoped pointer fall out of scope.
280 if (!profile->Save()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700281 Error::PopulateAndLog(error, Error::kInternalError,
282 "Profile name " + name + " could not be saved");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700283 return;
284 }
Paul Stewart19c871d2011-12-15 16:10:13 -0800285
286 *path = profile->GetRpcIdentifier();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700287}
288
Paul Stewart19c871d2011-12-15 16:10:13 -0800289void Manager::PushProfile(const string &name, string *path, Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700290 SLOG(Manager, 2) << __func__ << " " << name;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700291 Profile::Identifier ident;
292 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700293 Error::PopulateAndLog(error, Error::kInvalidArguments,
294 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700295 return;
296 }
297
298 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
299 it != profiles_.end();
300 ++it) {
301 if ((*it)->MatchesIdentifier(ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700302 Error::PopulateAndLog(error, Error::kAlreadyExists,
303 "Profile name " + name + " is already on stack");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700304 return;
305 }
306 }
307
Paul Stewartd0a3b812012-03-28 22:48:22 -0700308 ProfileRefPtr profile;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700309 if (ident.user.empty()) {
Paul Stewartd0a3b812012-03-28 22:48:22 -0700310 // Allow a machine-wide-profile to be pushed on the stack only if the
311 // profile stack is empty, or if the topmost profile on the stack is
312 // also a machine-wide (non-user) profile.
313 if (!profiles_.empty() && !profiles_.back()->GetUser().empty()) {
314 Error::PopulateAndLog(error, Error::kInvalidArguments,
315 "Cannot load non-default global profile " + name +
316 " on top of a user profile");
317 return;
318 }
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700319
Paul Stewartd0a3b812012-03-28 22:48:22 -0700320 scoped_refptr<DefaultProfile>
321 default_profile(new DefaultProfile(control_interface_,
322 this,
323 storage_path_,
324 ident.identifier,
325 props_));
326 if (!default_profile->InitStorage(glib_, Profile::kOpenExisting, error)) {
327 // |error| will have been populated by InitStorage().
328 return;
329 }
330
331 if (!default_profile->LoadManagerProperties(&props_)) {
332 Error::PopulateAndLog(error, Error::kInvalidArguments,
333 "Could not load Manager properties from profile " +
334 name);
335 return;
336 }
337 profile = default_profile;
338 } else {
339 profile = new Profile(control_interface_,
340 this,
341 ident,
342 user_storage_format_,
343 connect_profiles_to_rpc_);
344 if (!profile->InitStorage(glib_, Profile::kOpenExisting, error)) {
345 // |error| will have been populated by InitStorage().
346 return;
347 }
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700348 }
349
Paul Stewarta849a3d2011-11-03 05:54:09 -0700350 profiles_.push_back(profile);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700351
352 // Offer each registered Service the opportunity to join this new Profile.
Paul Stewarta41e38d2011-11-11 07:47:29 -0800353 for (vector<ServiceRefPtr>::iterator it = services_.begin();
354 it != services_.end(); ++it) {
Paul Stewartbba6a5b2011-11-02 18:45:59 -0700355 profile->ConfigureService(*it);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700356 }
357
Paul Stewarta41e38d2011-11-11 07:47:29 -0800358 // Shop the Profile contents around to Devices which can create
359 // non-visible services.
360 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
361 it != devices_.end(); ++it) {
362 profile->ConfigureDevice(*it);
363 }
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800364
Darin Petkovc63dcf02012-05-24 11:51:43 +0200365 // Offer the Profile contents to the service/device providers which will
366 // create new services if necessary.
Paul Stewart66815332012-04-09 18:09:36 -0700367 vpn_provider_.CreateServicesFromProfile(profile);
Darin Petkovc63dcf02012-05-24 11:51:43 +0200368 wimax_provider_.CreateServicesFromProfile(profile);
Paul Stewart66815332012-04-09 18:09:36 -0700369
Paul Stewart19c871d2011-12-15 16:10:13 -0800370 *path = profile->GetRpcIdentifier();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800371 SortServices();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700372}
373
374void Manager::PopProfileInternal() {
375 CHECK(!profiles_.empty());
376 ProfileRefPtr active_profile = profiles_.back();
377 profiles_.pop_back();
Paul Stewart75225512012-01-26 22:51:33 -0800378 vector<ServiceRefPtr>::iterator it;
Paul Stewart65512e12012-03-26 18:01:08 -0700379 for (it = services_.begin(); it != services_.end();) {
380 if ((*it)->profile().get() != active_profile.get() ||
381 MatchProfileWithService(*it) ||
382 !UnloadService(&it)) {
383 LOG(ERROR) << "Skipping unload of service";
384 ++it;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700385 }
386 }
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800387 SortServices();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700388}
389
Paul Stewarta41e38d2011-11-11 07:47:29 -0800390void Manager::PopProfile(const string &name, Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700391 SLOG(Manager, 2) << __func__ << " " << name;
Christopher Wiley3e7635e2012-08-15 09:46:17 -0700392 // This signal is sent when a user logs out of a session. Regardless of
393 // whether we find their profile to remove, lets clear the network related
394 // logs.
395 MemoryLog::GetInstance()->Clear();
396 LOG(INFO) << "Cleared the memory log on logout event.";
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700397 Profile::Identifier ident;
398 if (profiles_.empty()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700399 Error::PopulateAndLog(error, Error::kNotFound, "Profile stack is empty");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700400 return;
401 }
402 ProfileRefPtr active_profile = profiles_.back();
403 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700404 Error::PopulateAndLog(error, Error::kInvalidArguments,
405 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700406 return;
407 }
408 if (!active_profile->MatchesIdentifier(ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700409 Error::PopulateAndLog(error, Error::kNotSupported,
410 name + " is not the active profile");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700411 return;
412 }
413 PopProfileInternal();
414}
415
416void Manager::PopAnyProfile(Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700417 SLOG(Manager, 2) << __func__;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700418 Profile::Identifier ident;
419 if (profiles_.empty()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700420 Error::PopulateAndLog(error, Error::kNotFound, "Profile stack is empty");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700421 return;
422 }
423 PopProfileInternal();
424}
425
Paul Stewarte73d05c2012-03-29 16:26:05 -0700426void Manager::RemoveProfile(const string &name, Error *error) {
427 Profile::Identifier ident;
428 if (!Profile::ParseIdentifier(name, &ident)) {
429 Error::PopulateAndLog(error, Error::kInvalidArguments,
430 "Invalid profile name " + name);
431 return;
432 }
433
434 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
435 it != profiles_.end();
436 ++it) {
437 if ((*it)->MatchesIdentifier(ident)) {
438 Error::PopulateAndLog(error, Error::kInvalidArguments,
439 "Cannot remove profile name " + name +
440 " since it is on stack");
441 return;
442 }
443 }
444
445 ProfileRefPtr profile;
446 if (ident.user.empty()) {
447 profile = new DefaultProfile(control_interface_,
448 this,
449 storage_path_,
450 ident.identifier,
451 props_);
452 } else {
453 profile = new Profile(control_interface_,
454 this,
455 ident,
456 user_storage_format_,
457 false);
458 }
459
460
461 // |error| will have been populated if RemoveStorage fails.
462 profile->RemoveStorage(glib_, error);
463
464 return;
465}
466
Paul Stewart75225512012-01-26 22:51:33 -0800467bool Manager::HandleProfileEntryDeletion(const ProfileRefPtr &profile,
468 const std::string &entry_name) {
469 bool moved_services = false;
470 for (vector<ServiceRefPtr>::iterator it = services_.begin();
Paul Stewart65512e12012-03-26 18:01:08 -0700471 it != services_.end();) {
Paul Stewart75225512012-01-26 22:51:33 -0800472 if ((*it)->profile().get() == profile.get() &&
473 (*it)->GetStorageIdentifier() == entry_name) {
474 profile->AbandonService(*it);
Paul Stewart65512e12012-03-26 18:01:08 -0700475 if (MatchProfileWithService(*it) ||
476 !UnloadService(&it)) {
477 ++it;
Paul Stewart75225512012-01-26 22:51:33 -0800478 }
479 moved_services = true;
Paul Stewart65512e12012-03-26 18:01:08 -0700480 } else {
481 ++it;
Paul Stewart75225512012-01-26 22:51:33 -0800482 }
483 }
484 return moved_services;
485}
486
Paul Stewart0756db92012-01-27 08:34:47 -0800487ServiceRefPtr Manager::GetServiceWithStorageIdentifier(
488 const ProfileRefPtr &profile, const std::string &entry_name, Error *error) {
489 for (vector<ServiceRefPtr>::iterator it = services_.begin();
490 it != services_.end(); ++it) {
491 if ((*it)->profile().get() == profile.get() &&
492 (*it)->GetStorageIdentifier() == entry_name) {
493 return *it;
494 }
495 }
496
497 Error::PopulateAndLog(error, Error::kNotFound,
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500498 StringPrintf("Entry %s is not registered in the manager",
499 entry_name.c_str()));
Paul Stewart0756db92012-01-27 08:34:47 -0800500 return NULL;
501}
502
Paul Stewart13ed2252012-03-21 12:52:46 -0700503ServiceRefPtr Manager::GetServiceWithGUID(
504 const std::string &guid, Error *error) {
505 for (vector<ServiceRefPtr>::iterator it = services_.begin();
506 it != services_.end(); ++it) {
507 if ((*it)->guid() == guid) {
508 return *it;
509 }
510 }
511
512 Error::PopulateAndLog(error, Error::kNotFound,
513 StringPrintf("Service wth GUID %s is not registered in the manager",
514 guid.c_str()));
515 return NULL;
516}
517
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700518ServiceRefPtr Manager::GetDefaultService() const {
519 if (services_.empty() || !services_[0]->connection().get()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700520 SLOG(Manager, 2) << "In " << __func__ << ": No default connection exists.";
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700521 return NULL;
522 }
523 return services_[0];
524}
525
Paul Stewart49739c02012-08-08 17:24:03 -0700526RpcIdentifier Manager::GetDefaultServiceRpcIdentifier(Error */*error*/) {
527 ServiceRefPtr default_service = GetDefaultService();
528 return default_service ? default_service->GetRpcIdentifier() : "/";
529}
530
Paul Stewart036dba02012-08-07 12:34:41 -0700531bool Manager::IsTechnologyInList(const string &technology_list,
532 Technology::Identifier tech) const {
Paul Stewart20088d82012-02-16 06:58:55 -0800533 Error error;
Paul Stewart036dba02012-08-07 12:34:41 -0700534 vector<Technology::Identifier> technologies;
535 return Technology::GetTechnologyVectorFromString(technology_list,
536 &technologies,
Paul Stewart20088d82012-02-16 06:58:55 -0800537 &error) &&
Paul Stewart036dba02012-08-07 12:34:41 -0700538 std::find(technologies.begin(), technologies.end(), tech) !=
539 technologies.end();
540}
541
542bool Manager::IsPortalDetectionEnabled(Technology::Identifier tech) {
543 return IsTechnologyInList(GetCheckPortalList(NULL), tech);
Paul Stewart20088d82012-02-16 06:58:55 -0800544}
545
Paul Stewart10e9e4e2012-04-26 19:46:28 -0700546void Manager::SetStartupPortalList(const string &portal_list) {
547 startup_portal_list_ = portal_list;
548 use_startup_portal_list_ = true;
549}
550
Paul Stewart10ccbb32012-04-26 15:59:30 -0700551bool Manager::IsServiceEphemeral(const ServiceConstRefPtr &service) const {
552 return service->profile() == ephemeral_profile_;
553}
554
Paul Stewartbf667612012-06-29 14:49:54 -0700555bool Manager::IsTechnologyShortDNSTimeoutEnabled(
Paul Stewart036dba02012-08-07 12:34:41 -0700556 Technology::Identifier technology) const {
557 return IsTechnologyInList(props_.short_dns_timeout_technologies, technology);
558}
559
560bool Manager::IsTechnologyLinkMonitorEnabled(
561 Technology::Identifier technology) const {
562 return IsTechnologyInList(props_.link_monitor_technologies, technology);
Paul Stewartbf667612012-06-29 14:49:54 -0700563}
564
Paul Stewart1b253142012-01-26 14:05:52 -0800565const ProfileRefPtr &Manager::ActiveProfile() const {
Eric Shienbroodc74cf9c2012-03-02 15:00:35 -0500566 DCHECK_NE(profiles_.size(), 0U);
Chris Masone7aa5f902011-07-11 11:13:35 -0700567 return profiles_.back();
568}
569
Paul Stewart1b253142012-01-26 14:05:52 -0800570bool Manager::IsActiveProfile(const ProfileRefPtr &profile) const {
571 return (profiles_.size() > 0 &&
572 ActiveProfile().get() == profile.get());
573}
574
Chris Masone6515aab2011-10-12 16:19:09 -0700575bool Manager::MoveServiceToProfile(const ServiceRefPtr &to_move,
576 const ProfileRefPtr &destination) {
577 const ProfileRefPtr from = to_move->profile();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700578 SLOG(Manager, 2) << "Moving service "
579 << to_move->UniqueName()
580 << " to profile "
581 << destination->GetFriendlyName()
582 << " from "
583 << from->GetFriendlyName();
Chris Masone6515aab2011-10-12 16:19:09 -0700584 return destination->AdoptService(to_move) &&
585 from->AbandonService(to_move);
Chris Masone6791a432011-07-12 13:23:19 -0700586}
587
Paul Stewart7f61e522012-03-22 11:13:45 -0700588ProfileRefPtr Manager::LookupProfileByRpcIdentifier(
589 const string &profile_rpcid) {
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800590 for (vector<ProfileRefPtr>::iterator it = profiles_.begin();
591 it != profiles_.end();
592 ++it) {
593 if (profile_rpcid == (*it)->GetRpcIdentifier()) {
Paul Stewart7f61e522012-03-22 11:13:45 -0700594 return *it;
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800595 }
596 }
Paul Stewart7f61e522012-03-22 11:13:45 -0700597 return NULL;
598}
599
600void Manager::SetProfileForService(const ServiceRefPtr &to_set,
601 const string &profile_rpcid,
602 Error *error) {
603 ProfileRefPtr profile = LookupProfileByRpcIdentifier(profile_rpcid);
604 if (!profile) {
605 Error::PopulateAndLog(error, Error::kInvalidArguments,
606 StringPrintf("Unknown Profile %s requested for "
607 "Service", profile_rpcid.c_str()));
608 return;
609 }
610
Paul Stewart649f3a42012-04-24 23:22:16 -0700611 if (!to_set->profile()) {
612 // We are being asked to set the profile property of a service that
613 // has never been registered. Now is a good time to register it.
614 RegisterService(to_set);
615 }
616
Paul Stewart7f61e522012-03-22 11:13:45 -0700617 if (to_set->profile().get() == profile.get()) {
618 Error::PopulateAndLog(error, Error::kInvalidArguments,
619 "Service is already connected to this profile");
620 } else if (!MoveServiceToProfile(to_set, profile)) {
621 Error::PopulateAndLog(error, Error::kInternalError,
622 "Unable to move service to profile");
623 }
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800624}
625
Eric Shienbrood9a245532012-03-07 14:20:39 -0500626void Manager::EnableTechnology(const std::string &technology_name,
627 Error *error,
628 const ResultCallback &callback) {
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400629 CHECK(error != NULL);
630 DCHECK(error->IsOngoing());
Eric Shienbrood9a245532012-03-07 14:20:39 -0500631 Technology::Identifier id = Technology::IdentifierFromName(technology_name);
632 if (id == Technology::kUnknown) {
633 error->Populate(Error::kInvalidArguments, "Unknown technology");
634 return;
635 }
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400636 bool deferred = false;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500637 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
638 it != devices_.end(); ++it) {
639 DeviceRefPtr device = *it;
Joshua Krollda798622012-06-05 12:30:48 -0700640 if (device->technology() == id && !device->enabled()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500641 device->SetEnabledPersistent(true, error, callback);
642 // Continue with other devices even if one fails
643 // TODO(ers): Decide whether an error should be returned
644 // for the overall EnableTechnology operation if some
645 // devices succeed and some fail.
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400646 if (error->IsOngoing())
647 deferred = true;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500648 }
649 }
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400650 // If no device has deferred work, then clear the error to
651 // communicate to the caller that all work is done.
652 if (!deferred)
653 error->Reset();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500654}
655
656void Manager::DisableTechnology(const std::string &technology_name,
657 Error *error,
658 const ResultCallback &callback) {
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400659 CHECK(error != NULL);
660 DCHECK(error->IsOngoing());
Eric Shienbrood9a245532012-03-07 14:20:39 -0500661 Technology::Identifier id = Technology::IdentifierFromName(technology_name);
662 if (id == Technology::kUnknown) {
663 error->Populate(Error::kInvalidArguments, "Unknown technology");
664 return;
665 }
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400666 bool deferred = false;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500667 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
668 it != devices_.end(); ++it) {
669 DeviceRefPtr device = *it;
Joshua Krollda798622012-06-05 12:30:48 -0700670 if (device->technology() == id && device->enabled()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500671 device->SetEnabledPersistent(false, error, callback);
672 // Continue with other devices even if one fails
673 // TODO(ers): Decide whether an error should be returned
674 // for the overall DisableTechnology operation if some
675 // devices succeed and some fail.
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400676 if (error->IsOngoing())
677 deferred = true;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500678 }
679 }
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400680 // If no device has deferred work, then clear the error to
681 // communicate to the caller that all work is done.
682 if (!deferred)
683 error->Reset();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500684}
685
686void Manager::UpdateEnabledTechnologies() {
687 Error error;
688 adaptor_->EmitStringsChanged(flimflam::kEnabledTechnologiesProperty,
689 EnabledTechnologies(&error));
690}
691
Chris Masone2b105542011-06-22 10:58:09 -0700692void Manager::RegisterDevice(const DeviceRefPtr &to_manage) {
Darin Petkove7c6ad32012-06-29 10:22:09 +0200693 LOG(INFO) << "Device " << to_manage->FriendlyName() << " registered.";
694 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
695 it != devices_.end(); ++it) {
Chris Masonec1e50412011-06-07 13:04:53 -0700696 if (to_manage.get() == it->get())
Chris Masone9be4a9d2011-05-16 15:44:09 -0700697 return;
698 }
Chris Masonec1e50412011-06-07 13:04:53 -0700699 devices_.push_back(to_manage);
Paul Stewartf1ce5d22011-05-19 13:10:20 -0700700
Darin Petkove7c6ad32012-06-29 10:22:09 +0200701 // We are applying device properties from the DefaultProfile, and adding the
702 // union of hidden services in all loaded profiles to the device.
Chris Masone6515aab2011-10-12 16:19:09 -0700703 for (vector<ProfileRefPtr>::iterator it = profiles_.begin();
Darin Petkove7c6ad32012-06-29 10:22:09 +0200704 it != profiles_.end(); ++it) {
Paul Stewarta41e38d2011-11-11 07:47:29 -0800705 // Load device configuration, if any exists, as well as hidden services.
706 (*it)->ConfigureDevice(to_manage);
Chris Masone6515aab2011-10-12 16:19:09 -0700707 }
Paul Stewarta41e38d2011-11-11 07:47:29 -0800708
Darin Petkove7c6ad32012-06-29 10:22:09 +0200709 // If |to_manage| is new, it needs to be persisted.
710 UpdateDevice(to_manage);
711
Paul Stewarta41e38d2011-11-11 07:47:29 -0800712 // In normal usage, running_ will always be true when we are here, however
713 // unit tests sometimes do things in otherwise invalid states.
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400714 if (running_ && (to_manage->enabled_persistent() ||
715 to_manage->IsUnderlyingDeviceEnabled()))
Eric Shienbrood9a245532012-03-07 14:20:39 -0500716 to_manage->SetEnabled(true);
Gaurav Shah435de2c2011-11-17 19:01:07 -0800717
Eric Shienbrood8839a892012-03-29 10:33:48 -0400718 EmitDeviceProperties();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700719}
720
mukesh agrawal5029c6c2011-08-25 11:12:40 -0700721void Manager::DeregisterDevice(const DeviceRefPtr &to_forget) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700722 SLOG(Manager, 2) << __func__ << "(" << to_forget->FriendlyName() << ")";
Chris Masonec1e50412011-06-07 13:04:53 -0700723 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700724 for (it = devices_.begin(); it != devices_.end(); ++it) {
Chris Masonec1e50412011-06-07 13:04:53 -0700725 if (to_forget.get() == it->get()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700726 SLOG(Manager, 2) << "Deregistered device: " << to_forget->UniqueName();
Paul Stewart212d60f2012-07-12 10:59:13 -0700727 UpdateDevice(to_forget);
Eric Shienbrood9a245532012-03-07 14:20:39 -0500728 to_forget->SetEnabled(false);
Chris Masone9be4a9d2011-05-16 15:44:09 -0700729 devices_.erase(it);
Eric Shienbrood8839a892012-03-29 10:33:48 -0400730 EmitDeviceProperties();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700731 return;
732 }
733 }
Ben Chanfad4a0b2012-04-18 15:49:59 -0700734 SLOG(Manager, 2) << __func__ << " unknown device: "
735 << to_forget->UniqueName();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700736}
737
Eric Shienbrood8839a892012-03-29 10:33:48 -0400738void Manager::EmitDeviceProperties() {
739 vector<DeviceRefPtr>::iterator it;
740 vector<string> device_paths;
741 for (it = devices_.begin(); it != devices_.end(); ++it) {
742 device_paths.push_back((*it)->GetRpcIdentifier());
743 }
744 adaptor_->EmitRpcIdentifierArrayChanged(flimflam::kDevicesProperty,
745 device_paths);
746 Error error;
747 adaptor_->EmitStringsChanged(flimflam::kAvailableTechnologiesProperty,
748 AvailableTechnologies(&error));
749 adaptor_->EmitStringsChanged(flimflam::kEnabledTechnologiesProperty,
750 EnabledTechnologies(&error));
751}
752
mukesh agrawal4eb4d782011-12-05 17:34:37 +0000753bool Manager::HasService(const ServiceRefPtr &service) {
754 vector<ServiceRefPtr>::iterator it;
755 for (it = services_.begin(); it != services_.end(); ++it) {
756 if ((*it)->UniqueName() == service->UniqueName())
757 return true;
758 }
759 return false;
760}
761
Chris Masone2b105542011-06-22 10:58:09 -0700762void Manager::RegisterService(const ServiceRefPtr &to_manage) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700763 SLOG(Manager, 2) << "In " << __func__ << "(): Registering service "
764 << to_manage->UniqueName();
mukesh agrawald835b202011-10-07 15:26:47 -0700765
Paul Stewart75225512012-01-26 22:51:33 -0800766 MatchProfileWithService(to_manage);
Chris Masone6791a432011-07-12 13:23:19 -0700767
768 // Now add to OUR list.
Chris Masonec1e50412011-06-07 13:04:53 -0700769 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700770 for (it = services_.begin(); it != services_.end(); ++it) {
mukesh agrawald835b202011-10-07 15:26:47 -0700771 CHECK(to_manage->UniqueName() != (*it)->UniqueName());
Chris Masone9be4a9d2011-05-16 15:44:09 -0700772 }
Chris Masonec1e50412011-06-07 13:04:53 -0700773 services_.push_back(to_manage);
Paul Stewart22aa71b2011-09-16 12:15:11 -0700774 SortServices();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700775}
776
Chris Masone6515aab2011-10-12 16:19:09 -0700777void Manager::DeregisterService(const ServiceRefPtr &to_forget) {
Chris Masonec1e50412011-06-07 13:04:53 -0700778 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700779 for (it = services_.begin(); it != services_.end(); ++it) {
Chris Masone6791a432011-07-12 13:23:19 -0700780 if (to_forget->UniqueName() == (*it)->UniqueName()) {
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800781 DCHECK(!(*it)->connection());
Paul Stewartfc9a1da2012-06-27 15:54:52 -0700782 (*it)->Unload();
783 (*it)->set_profile(NULL);
Chris Masone9be4a9d2011-05-16 15:44:09 -0700784 services_.erase(it);
Paul Stewart22aa71b2011-09-16 12:15:11 -0700785 SortServices();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700786 return;
787 }
788 }
789}
790
Paul Stewart65512e12012-03-26 18:01:08 -0700791bool Manager::UnloadService(vector<ServiceRefPtr>::iterator *service_iterator) {
792 if (!(**service_iterator)->Unload()) {
793 return false;
794 }
795
796 DCHECK(!(**service_iterator)->connection());
Paul Stewartfc9a1da2012-06-27 15:54:52 -0700797 (**service_iterator)->set_profile(NULL);
Paul Stewart65512e12012-03-26 18:01:08 -0700798 *service_iterator = services_.erase(*service_iterator);
799
800 return true;
801}
802
mukesh agrawal00917ce2011-11-22 23:56:55 +0000803void Manager::UpdateService(const ServiceRefPtr &to_update) {
804 CHECK(to_update);
Paul Stewart03dba0b2011-08-22 16:32:45 -0700805 LOG(INFO) << "Service " << to_update->UniqueName() << " updated;"
Gaurav Shahc6d6c722011-11-17 18:59:39 -0800806 << " state: " << Service::ConnectStateToString(to_update->state())
807 << " failure: "
808 << Service::ConnectFailureToString(to_update->failure());
Ben Chanfad4a0b2012-04-18 15:49:59 -0700809 SLOG(Manager, 2) << "IsConnected(): " << to_update->IsConnected();
810 SLOG(Manager, 2) << "IsConnecting(): " << to_update->IsConnecting();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800811 if (to_update->IsConnected()) {
mukesh agrawal00917ce2011-11-22 23:56:55 +0000812 to_update->MakeFavorite();
Gary Moraind93615e2012-04-27 11:50:03 -0700813 // Persists the updated favorite setting in the profile.
814 SaveServiceToProfile(to_update);
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800815 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700816 SortServices();
Paul Stewart03dba0b2011-08-22 16:32:45 -0700817}
818
Darin Petkove7c6ad32012-06-29 10:22:09 +0200819void Manager::UpdateDevice(const DeviceRefPtr &to_update) {
820 LOG(INFO) << "Device " << to_update->link_name() << " updated: "
821 << (to_update->enabled_persistent() ? "enabled" : "disabled");
822 // Saves the device to the topmost profile that accepts it. Normally, this
823 // would be the only DefaultProfile at the bottom of the stack except in
824 // autotests that push a second test-only DefaultProfile.
825 for (vector<ProfileRefPtr>::reverse_iterator rit = profiles_.rbegin();
826 rit != profiles_.rend(); ++rit) {
827 if ((*rit)->UpdateDevice(to_update)) {
828 return;
829 }
830 }
831}
832
Gary Moraind93615e2012-04-27 11:50:03 -0700833void Manager::SaveServiceToProfile(const ServiceRefPtr &to_update) {
834 if (IsServiceEphemeral(to_update)) {
835 if (profiles_.empty()) {
836 LOG(ERROR) << "Cannot assign profile to service: no profiles exist!";
837 } else {
838 MoveServiceToProfile(to_update, profiles_.back());
839 }
840 } else {
841 to_update->profile()->UpdateService(to_update);
842 }
843}
844
Gary Moraina9fb3252012-05-31 12:05:31 -0700845void Manager::AddTerminationAction(const std::string &name,
846 const base::Closure &start) {
847 termination_actions_.Add(name, start);
848}
849
850void Manager::TerminationActionComplete(const std::string &name) {
851 termination_actions_.ActionComplete(name);
852}
853
854void Manager::RemoveTerminationAction(const std::string &name) {
855 termination_actions_.Remove(name);
856}
857
858void Manager::RunTerminationActions(
859 int timeout_ms, const base::Callback<void(const Error &)> &done) {
860 termination_actions_.Run(timeout_ms, done);
861}
862
Darin Petkova5e07ef2012-07-09 14:27:57 +0200863int Manager::RegisterDefaultServiceCallback(const ServiceCallback &callback) {
864 default_service_callbacks_[++default_service_callback_tag_] = callback;
865 return default_service_callback_tag_;
866}
867
868void Manager::DeregisterDefaultServiceCallback(int tag) {
869 default_service_callbacks_.erase(tag);
870}
871
872void Manager::NotifyDefaultServiceChanged(const ServiceRefPtr &service) {
873 for (map<int, ServiceCallback>::const_iterator it =
874 default_service_callbacks_.begin();
875 it != default_service_callbacks_.end(); ++it) {
876 it->second.Run(service);
877 }
878 metrics_->NotifyDefaultServiceChanged(service);
Paul Stewart49739c02012-08-08 17:24:03 -0700879 EmitDefaultService();
880}
881
882void Manager::EmitDefaultService() {
883 RpcIdentifier rpc_identifier = GetDefaultServiceRpcIdentifier(NULL);
884 if (rpc_identifier != default_service_rpc_identifier_) {
885 adaptor_->EmitRpcIdentifierChanged(shill::kDefaultServiceProperty,
886 rpc_identifier);
887 default_service_rpc_identifier_ = rpc_identifier;
888 }
Darin Petkova5e07ef2012-07-09 14:27:57 +0200889}
890
Darin Petkovca621542012-07-25 14:25:56 +0200891void Manager::OnPowerStateChanged(
892 PowerManagerProxyDelegate::SuspendState power_state) {
893 if (power_state == PowerManagerProxyDelegate::kOn) {
894 SortServices();
mukesh agrawal784566d2012-08-08 18:32:58 -0700895 vector<DeviceRefPtr>::iterator it;
896 for (it = devices_.begin(); it != devices_.end(); ++it) {
897 (*it)->OnAfterResume();
898 }
899 } else if (power_state == PowerManagerProxyDelegate::kMem) {
900 vector<DeviceRefPtr>::iterator it;
901 for (it = devices_.begin(); it != devices_.end(); ++it) {
902 (*it)->OnBeforeSuspend();
903 }
Darin Petkovca621542012-07-25 14:25:56 +0200904 }
905}
906
Paul Stewartfdd16072011-09-16 12:41:35 -0700907void Manager::FilterByTechnology(Technology::Identifier tech,
Chris Masonec1e50412011-06-07 13:04:53 -0700908 vector<DeviceRefPtr> *found) {
Chris Masone9be4a9d2011-05-16 15:44:09 -0700909 CHECK(found);
Chris Masonec1e50412011-06-07 13:04:53 -0700910 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700911 for (it = devices_.begin(); it != devices_.end(); ++it) {
Joshua Krollda798622012-06-05 12:30:48 -0700912 if ((*it)->technology() == tech)
Chris Masone9be4a9d2011-05-16 15:44:09 -0700913 found->push_back(*it);
914 }
915}
916
Paul Stewart22aa71b2011-09-16 12:15:11 -0700917ServiceRefPtr Manager::FindService(const string& name) {
Chris Masonec1e50412011-06-07 13:04:53 -0700918 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700919 for (it = services_.begin(); it != services_.end(); ++it) {
Chris Masone6791a432011-07-12 13:23:19 -0700920 if (name == (*it)->UniqueName())
Chris Masonee0dea762011-06-09 09:06:03 -0700921 return *it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700922 }
Chris Masonee0dea762011-06-09 09:06:03 -0700923 return NULL;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700924}
925
Paul Stewart49739c02012-08-08 17:24:03 -0700926void Manager::HelpRegisterConstDerivedRpcIdentifier(
927 const string &name,
928 RpcIdentifier(Manager::*get)(Error *error)) {
929 store_.RegisterDerivedRpcIdentifier(
930 name,
931 RpcIdentifierAccessor(
932 new CustomAccessor<Manager, RpcIdentifier>(this, get, NULL)));
933}
934
mukesh agrawal2366eed2012-03-20 18:21:50 -0700935void Manager::HelpRegisterConstDerivedRpcIdentifiers(
936 const string &name,
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400937 RpcIdentifiers(Manager::*get)(Error *error)) {
mukesh agrawal2366eed2012-03-20 18:21:50 -0700938 store_.RegisterDerivedRpcIdentifiers(
939 name,
940 RpcIdentifiersAccessor(
941 new CustomAccessor<Manager, RpcIdentifiers>(this, get, NULL)));
942}
943
mukesh agrawalffa3d042011-10-06 15:26:10 -0700944void Manager::HelpRegisterDerivedString(
945 const string &name,
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800946 string(Manager::*get)(Error *),
mukesh agrawalffa3d042011-10-06 15:26:10 -0700947 void(Manager::*set)(const string&, Error *)) {
Chris Masone27c4aa52011-07-02 13:10:14 -0700948 store_.RegisterDerivedString(
949 name,
950 StringAccessor(new CustomAccessor<Manager, string>(this, get, set)));
Chris Masoneb925cc82011-06-22 15:39:57 -0700951}
952
mukesh agrawalffa3d042011-10-06 15:26:10 -0700953void Manager::HelpRegisterDerivedStrings(
954 const string &name,
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800955 Strings(Manager::*get)(Error *),
mukesh agrawalffa3d042011-10-06 15:26:10 -0700956 void(Manager::*set)(const Strings &, Error *)) {
Chris Masone27c4aa52011-07-02 13:10:14 -0700957 store_.RegisterDerivedStrings(
958 name,
959 StringsAccessor(new CustomAccessor<Manager, Strings>(this, get, set)));
Chris Masoneb925cc82011-06-22 15:39:57 -0700960}
961
Paul Stewart22aa71b2011-09-16 12:15:11 -0700962void Manager::SortServices() {
Paul Stewartdfa46052012-06-26 09:44:14 -0700963 // We might be called in the middle of a series of events that
964 // may result in multiple calls to Manager::SortServices, or within
965 // an outer loop that may also be traversing the services_ list.
966 // Defer this work to the event loop.
967 if (sort_services_task_.IsCancelled()) {
968 sort_services_task_.Reset(Bind(&Manager::SortServicesTask, AsWeakPtr()));
969 dispatcher_->PostTask(sort_services_task_.callback());
970 }
971}
972
973void Manager::SortServicesTask() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700974 SLOG(Manager, 4) << "In " << __func__;
Paul Stewartdfa46052012-06-26 09:44:14 -0700975 sort_services_task_.Cancel();
Thieu Lea20cbc22012-01-09 22:01:43 +0000976 ServiceRefPtr default_service;
977
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800978 if (!services_.empty()) {
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700979 // Keep track of the service that is the candidate for the default
980 // service. We have not yet tested to see if this service has a
981 // connection.
Thieu Lea20cbc22012-01-09 22:01:43 +0000982 default_service = services_[0];
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800983 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700984 sort(services_.begin(), services_.end(), ServiceSorter(technology_order_));
Paul Stewarta41e38d2011-11-11 07:47:29 -0800985
986 vector<string> service_paths;
987 vector<ServiceRefPtr>::iterator it;
988 for (it = services_.begin(); it != services_.end(); ++it) {
989 if ((*it)->IsVisible()) {
990 service_paths.push_back((*it)->GetRpcIdentifier());
991 }
992 }
993 adaptor_->EmitRpcIdentifierArrayChanged(flimflam::kServicesProperty,
994 service_paths);
Gaurav Shah435de2c2011-11-17 19:01:07 -0800995
996 Error error;
997 adaptor_->EmitStringsChanged(flimflam::kConnectedTechnologiesProperty,
998 ConnectedTechnologies(&error));
999 adaptor_->EmitStringChanged(flimflam::kDefaultTechnologyProperty,
1000 DefaultTechnology(&error));
Paul Stewartc1dec4d2011-12-08 15:25:28 -08001001
1002 if (!services_.empty()) {
Thieu Lea20cbc22012-01-09 22:01:43 +00001003 ConnectionRefPtr default_connection = default_service->connection();
Darin Petkova5e07ef2012-07-09 14:27:57 +02001004 if (default_connection &&
1005 services_[0]->connection() != default_connection) {
Paul Stewartc1dec4d2011-12-08 15:25:28 -08001006 default_connection->SetIsDefault(false);
1007 }
Darin Petkova5e07ef2012-07-09 14:27:57 +02001008 if (services_[0]->connection()) {
Paul Stewartc1dec4d2011-12-08 15:25:28 -08001009 services_[0]->connection()->SetIsDefault(true);
Thieu Lea20cbc22012-01-09 22:01:43 +00001010 default_service = services_[0];
Paul Stewarte2bad7c2012-03-14 08:55:33 -07001011 } else {
1012 default_service = NULL;
Paul Stewartc1dec4d2011-12-08 15:25:28 -08001013 }
1014 }
Darin Petkova5e07ef2012-07-09 14:27:57 +02001015 NotifyDefaultServiceChanged(default_service);
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001016 AutoConnect();
1017}
1018
Paul Stewart75225512012-01-26 22:51:33 -08001019bool Manager::MatchProfileWithService(const ServiceRefPtr &service) {
1020 vector<ProfileRefPtr>::reverse_iterator it;
1021 for (it = profiles_.rbegin(); it != profiles_.rend(); ++it) {
1022 if ((*it)->ConfigureService(service)) {
1023 break;
1024 }
1025 }
1026 if (it == profiles_.rend()) {
1027 ephemeral_profile_->AdoptService(service);
1028 return false;
1029 }
1030 return true;
1031}
1032
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001033void Manager::AutoConnect() {
Darin Petkovca621542012-07-25 14:25:56 +02001034 if (power_manager_.get() &&
1035 power_manager_->power_state() != PowerManagerProxyDelegate::kOn &&
1036 power_manager_->power_state() != PowerManagerProxyDelegate::kUnknown) {
1037 LOG(INFO) << "Auto-connect suppressed -- power state is not 'on'.";
1038 return;
1039 }
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001040 if (services_.empty()) {
Darin Petkovca621542012-07-25 14:25:56 +02001041 LOG(INFO) << "Auto-connect suppressed -- no services.";
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001042 return;
1043 }
1044
Ben Chanfad4a0b2012-04-18 15:49:59 -07001045 if (SLOG_IS_ON(Manager, 4)) {
1046 SLOG(Manager, 4) << "Sorted service list: ";
mukesh agrawalddc378f2012-02-17 18:26:20 -08001047 for (size_t i = 0; i < services_.size(); ++i) {
1048 ServiceRefPtr service = services_[i];
1049 const char *compare_reason = NULL;
1050 if (i + 1 < services_.size()) {
1051 Service::Compare(
1052 service, services_[i+1], technology_order_, &compare_reason);
1053 } else {
mukesh agrawalbf14e942012-03-02 14:36:34 -08001054 compare_reason = "last";
mukesh agrawalddc378f2012-02-17 18:26:20 -08001055 }
Ben Chanfad4a0b2012-04-18 15:49:59 -07001056 SLOG(Manager, 4) << "Service " << service->friendly_name()
1057 << " IsConnected: " << service->IsConnected()
1058 << " IsConnecting: " << service->IsConnecting()
1059 << " IsFailed: " << service->IsFailed()
1060 << " connectable: " << service->connectable()
1061 << " auto_connect: " << service->auto_connect()
1062 << " favorite: " << service->favorite()
1063 << " priority: " << service->priority()
1064 << " security_level: " << service->security_level()
1065 << " strength: " << service->strength()
1066 << " UniqueName: " << service->UniqueName()
1067 << " sorted: " << compare_reason;
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001068 }
1069 }
1070
Paul Stewart3d9bcf52011-12-12 15:02:22 -08001071 // Perform auto-connect.
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001072 for (vector<ServiceRefPtr>::iterator it = services_.begin();
1073 it != services_.end(); ++it) {
1074 if ((*it)->auto_connect()) {
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001075 (*it)->AutoConnect();
Paul Stewart3d9bcf52011-12-12 15:02:22 -08001076 }
1077 }
Paul Stewart22aa71b2011-09-16 12:15:11 -07001078}
1079
Gaurav Shah1b7a6162011-11-09 11:41:01 -08001080string Manager::CalculateState(Error */*error*/) {
Gary Morain028545d2012-04-07 14:55:52 -07001081 // |services_| is sorted such that connected services are first.
1082 if (!services_.empty() &&
1083 services_.front()->IsConnected()) {
1084 return flimflam::kStateOnline;
1085 }
Chris Masoneb925cc82011-06-22 15:39:57 -07001086 return flimflam::kStateOffline;
1087}
1088
Gaurav Shah1b7a6162011-11-09 11:41:01 -08001089vector<string> Manager::AvailableTechnologies(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -08001090 set<string> unique_technologies;
1091 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1092 it != devices_.end(); ++it) {
1093 unique_technologies.insert(
1094 Technology::NameFromIdentifier((*it)->technology()));
1095 }
1096 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -07001097}
1098
Gaurav Shah1b7a6162011-11-09 11:41:01 -08001099vector<string> Manager::ConnectedTechnologies(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -08001100 set<string> unique_technologies;
1101 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1102 it != devices_.end(); ++it) {
1103 if ((*it)->IsConnected())
1104 unique_technologies.insert(
1105 Technology::NameFromIdentifier((*it)->technology()));
1106 }
1107 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -07001108}
1109
Darin Petkov58f0b6d2012-06-12 12:52:30 +02001110string Manager::DefaultTechnology(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -08001111 return (!services_.empty() && services_[0]->IsConnected()) ?
Darin Petkov58f0b6d2012-06-12 12:52:30 +02001112 services_[0]->GetTechnologyString() : "";
Chris Masoneb925cc82011-06-22 15:39:57 -07001113}
1114
Eric Shienbrood9a245532012-03-07 14:20:39 -05001115vector<string> Manager::EnabledTechnologies(Error */*error*/) {
1116 set<string> unique_technologies;
1117 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1118 it != devices_.end(); ++it) {
1119 if ((*it)->enabled())
1120 unique_technologies.insert(
1121 Technology::NameFromIdentifier((*it)->technology()));
1122 }
1123 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -07001124}
1125
Paul Stewartcb3eb892012-06-07 14:24:46 -07001126RpcIdentifiers Manager::EnumerateDevices(Error */*error*/) {
1127 RpcIdentifiers device_rpc_ids;
Chris Masone3c3f6a12011-07-01 10:01:41 -07001128 for (vector<DeviceRefPtr>::const_iterator it = devices_.begin();
1129 it != devices_.end();
1130 ++it) {
1131 device_rpc_ids.push_back((*it)->GetRpcIdentifier());
1132 }
1133 return device_rpc_ids;
1134}
1135
Paul Stewartcb3eb892012-06-07 14:24:46 -07001136RpcIdentifiers Manager::EnumerateProfiles(Error */*error*/) {
1137 RpcIdentifiers profile_rpc_ids;
Paul Stewart1b253142012-01-26 14:05:52 -08001138 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
1139 it != profiles_.end();
1140 ++it) {
1141 profile_rpc_ids.push_back((*it)->GetRpcIdentifier());
1142 }
1143 return profile_rpc_ids;
1144}
1145
Gaurav Shah1b7a6162011-11-09 11:41:01 -08001146vector<string> Manager::EnumerateAvailableServices(Error */*error*/) {
Chris Masone3c3f6a12011-07-01 10:01:41 -07001147 vector<string> service_rpc_ids;
1148 for (vector<ServiceRefPtr>::const_iterator it = services_.begin();
1149 it != services_.end();
1150 ++it) {
1151 service_rpc_ids.push_back((*it)->GetRpcIdentifier());
1152 }
1153 return service_rpc_ids;
1154}
1155
Paul Stewartcb3eb892012-06-07 14:24:46 -07001156RpcIdentifiers Manager::EnumerateWatchedServices(Error *error) {
Chris Masone6791a432011-07-12 13:23:19 -07001157 // TODO(cmasone): Filter this list for services in appropriate states.
Gaurav Shah1b7a6162011-11-09 11:41:01 -08001158 return EnumerateAvailableServices(error);
Chris Masone3c3f6a12011-07-01 10:01:41 -07001159}
1160
Paul Stewart1b253142012-01-26 14:05:52 -08001161string Manager::GetActiveProfileRpcIdentifier(Error */*error*/) {
1162 return ActiveProfile()->GetRpcIdentifier();
Chris Masone7aa5f902011-07-11 11:13:35 -07001163}
1164
Paul Stewart10e9e4e2012-04-26 19:46:28 -07001165string Manager::GetCheckPortalList(Error */*error*/) {
Jason Glasgowdf7c5532012-05-14 14:41:45 -04001166 return use_startup_portal_list_ ? startup_portal_list_ :
1167 props_.check_portal_list;
Paul Stewart10e9e4e2012-04-26 19:46:28 -07001168}
1169
1170void Manager::SetCheckPortalList(const string &portal_list, Error *error) {
1171 props_.check_portal_list = portal_list;
1172 use_startup_portal_list_ = false;
1173}
1174
mukesh agrawal32399322011-09-01 10:53:43 -07001175// called via RPC (e.g., from ManagerDBusAdaptor)
Darin Petkovb65c2452012-02-23 15:17:06 +01001176ServiceRefPtr Manager::GetService(const KeyValueStore &args, Error *error) {
Paul Stewart7f5ad572012-06-04 15:18:54 -07001177 if (args.ContainsString(flimflam::kTypeProperty) &&
1178 args.GetString(flimflam::kTypeProperty) == flimflam::kTypeVPN) {
1179 // GetService on a VPN service should actually perform ConfigureService.
1180 // TODO(pstew): Remove this hack and change Chrome to use ConfigureService
1181 // instead, when we no longer need to support flimflam. crosbug.com/31523
1182 return ConfigureService(args, error);
1183 }
1184 return GetServiceInner(args, error);
1185}
1186
1187ServiceRefPtr Manager::GetServiceInner(const KeyValueStore &args,
1188 Error *error) {
Paul Stewart13ed2252012-03-21 12:52:46 -07001189 if (args.ContainsString(flimflam::kGuidProperty)) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001190 SLOG(Manager, 2) << __func__ << ": searching by GUID";
Paul Stewart13ed2252012-03-21 12:52:46 -07001191 ServiceRefPtr service =
1192 GetServiceWithGUID(args.GetString(flimflam::kGuidProperty), NULL);
1193 if (service) {
Paul Stewartcb59fed2012-03-21 21:14:46 -07001194 service->Configure(args, error);
Paul Stewart13ed2252012-03-21 12:52:46 -07001195 return service;
1196 }
1197 }
1198
Darin Petkovb65c2452012-02-23 15:17:06 +01001199 if (!args.ContainsString(flimflam::kTypeProperty)) {
Paul Stewart7f61e522012-03-22 11:13:45 -07001200 Error::PopulateAndLog(error, Error::kInvalidArguments, kErrorTypeRequired);
Darin Petkovb65c2452012-02-23 15:17:06 +01001201 return NULL;
1202 }
1203
1204 string type = args.GetString(flimflam::kTypeProperty);
Darin Petkovd1cd7972012-05-22 15:26:15 +02001205 if (type == flimflam::kTypeVPN) {
1206 SLOG(Manager, 2) << __func__ << ": getting VPN Service";
1207 return vpn_provider_.GetService(args, error);
1208 }
Darin Petkovb65c2452012-02-23 15:17:06 +01001209 if (type == flimflam::kTypeWifi) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001210 SLOG(Manager, 2) << __func__ << ": getting WiFi Service";
Darin Petkovb65c2452012-02-23 15:17:06 +01001211 return GetWifiService(args, error);
1212 }
Darin Petkovd1cd7972012-05-22 15:26:15 +02001213 if (type == flimflam::kTypeWimax) {
1214 SLOG(Manager, 2) << __func__ << ": getting WiMAX Service";
1215 return wimax_provider_.GetService(args, error);
Darin Petkovb65c2452012-02-23 15:17:06 +01001216 }
mukesh agrawal06175d72012-04-23 16:46:01 -07001217 Error::PopulateAndLog(error, Error::kNotSupported,
1218 kErrorUnsupportedServiceType);
Darin Petkovb65c2452012-02-23 15:17:06 +01001219 return NULL;
1220}
1221
mukesh agrawal7a4e4002011-09-06 11:26:05 -07001222WiFiServiceRefPtr Manager::GetWifiService(const KeyValueStore &args,
1223 Error *error) {
Paul Stewarta41e38d2011-11-11 07:47:29 -08001224 vector<DeviceRefPtr> wifi_devices;
Paul Stewart22aa71b2011-09-16 12:15:11 -07001225 FilterByTechnology(Technology::kWifi, &wifi_devices);
mukesh agrawal7a4e4002011-09-06 11:26:05 -07001226 if (wifi_devices.empty()) {
mukesh agrawal06175d72012-04-23 16:46:01 -07001227 Error::PopulateAndLog(error, Error::kInvalidArguments, kErrorNoDevice);
mukesh agrawal7a4e4002011-09-06 11:26:05 -07001228 return NULL;
1229 } else {
1230 WiFi *wifi = dynamic_cast<WiFi *>(wifi_devices.front().get());
1231 CHECK(wifi);
1232 return wifi->GetService(args, error);
1233 }
1234}
1235
Paul Stewart7f61e522012-03-22 11:13:45 -07001236// called via RPC (e.g., from ManagerDBusAdaptor)
Paul Stewart7f5ad572012-06-04 15:18:54 -07001237ServiceRefPtr Manager::ConfigureService(const KeyValueStore &args,
1238 Error *error) {
Paul Stewart7f61e522012-03-22 11:13:45 -07001239 ProfileRefPtr profile = ActiveProfile();
1240 bool profile_specified = args.ContainsString(flimflam::kProfileProperty);
1241 if (profile_specified) {
1242 string profile_rpcid = args.GetString(flimflam::kProfileProperty);
1243 profile = LookupProfileByRpcIdentifier(profile_rpcid);
1244 if (!profile) {
1245 Error::PopulateAndLog(error, Error::kInvalidArguments,
1246 "Invalid profile name " + profile_rpcid);
Paul Stewart7f5ad572012-06-04 15:18:54 -07001247 return NULL;
Paul Stewart7f61e522012-03-22 11:13:45 -07001248 }
1249 }
1250
Paul Stewart7f5ad572012-06-04 15:18:54 -07001251 ServiceRefPtr service = GetServiceInner(args, error);
Paul Stewart7f61e522012-03-22 11:13:45 -07001252 if (error->IsFailure() || !service) {
1253 LOG(ERROR) << "GetService failed; returning upstream error.";
Paul Stewart7f5ad572012-06-04 15:18:54 -07001254 return NULL;
Paul Stewart7f61e522012-03-22 11:13:45 -07001255 }
1256
mukesh agrawal06175d72012-04-23 16:46:01 -07001257 // Overwrite the profile data with the resulting configured service.
Paul Stewart7f61e522012-03-22 11:13:45 -07001258 if (!profile->UpdateService(service)) {
1259 Error::PopulateAndLog(error, Error::kInternalError,
1260 "Unable to save service to profile");
Paul Stewart7f5ad572012-06-04 15:18:54 -07001261 return NULL;
Paul Stewart7f61e522012-03-22 11:13:45 -07001262 }
1263
1264 if (HasService(service)) {
1265 // If the service has been registered (it may not be -- as is the case
1266 // with invisible WiFi networks), we can now transfer the service between
1267 // profiles.
Paul Stewart10ccbb32012-04-26 15:59:30 -07001268 if (IsServiceEphemeral(service) ||
Paul Stewart7f61e522012-03-22 11:13:45 -07001269 (profile_specified && service->profile() != profile)) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001270 SLOG(Manager, 2) << "Moving service to profile "
1271 << profile->GetFriendlyName();
Paul Stewart7f61e522012-03-22 11:13:45 -07001272 if (!MoveServiceToProfile(service, profile)) {
1273 Error::PopulateAndLog(error, Error::kInternalError,
1274 "Unable to move service to profile");
1275 }
1276 }
1277 }
Paul Stewart4357f4e2012-04-26 17:39:26 -07001278
1279 // Notify the service that a profile has been configured for it.
1280 service->OnProfileConfigured();
Paul Stewart7f5ad572012-06-04 15:18:54 -07001281
1282 return service;
Paul Stewart7f61e522012-03-22 11:13:45 -07001283}
1284
Paul Stewartc681fa02012-03-02 19:40:04 -08001285void Manager::RecheckPortal(Error */*error*/) {
1286 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1287 it != devices_.end(); ++it) {
1288 if ((*it)->RequestPortalDetection()) {
1289 // Only start Portal Detection on the device with the default connection.
1290 // We will get a "true" return value when we've found that device, and
1291 // can end our loop early as a result.
1292 break;
1293 }
1294 }
1295}
1296
Paul Stewartd215af62012-04-24 23:25:50 -07001297void Manager::RecheckPortalOnService(const ServiceRefPtr &service) {
1298 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1299 it != devices_.end(); ++it) {
1300 if ((*it)->IsConnectedToService(service)) {
1301 // As opposed to RecheckPortal() above, we explicitly stop and then
1302 // restart portal detection, since the service to recheck was explicitly
1303 // specified.
1304 (*it)->RestartPortalDetection();
1305 break;
1306 }
1307 }
1308}
1309
mukesh agrawal7a4e4002011-09-06 11:26:05 -07001310// called via RPC (e.g., from ManagerDBusAdaptor)
Paul Stewart22aa71b2011-09-16 12:15:11 -07001311void Manager::RequestScan(const string &technology, Error *error) {
mukesh agrawal32399322011-09-01 10:53:43 -07001312 if (technology == flimflam::kTypeWifi || technology == "") {
1313 vector<DeviceRefPtr> wifi_devices;
Paul Stewartfdd16072011-09-16 12:41:35 -07001314 FilterByTechnology(Technology::kWifi, &wifi_devices);
mukesh agrawal32399322011-09-01 10:53:43 -07001315
1316 for (vector<DeviceRefPtr>::iterator it = wifi_devices.begin();
1317 it != wifi_devices.end();
1318 ++it) {
Darin Petkovc0865312011-09-16 15:31:20 -07001319 (*it)->Scan(error);
mukesh agrawal32399322011-09-01 10:53:43 -07001320 }
1321 } else {
1322 // TODO(quiche): support scanning for other technologies?
Paul Stewartbe005172011-11-02 18:10:29 -07001323 Error::PopulateAndLog(error, Error::kInvalidArguments,
1324 "Unrecognized technology " + technology);
mukesh agrawal32399322011-09-01 10:53:43 -07001325 }
1326}
1327
Paul Stewart22aa71b2011-09-16 12:15:11 -07001328string Manager::GetTechnologyOrder() {
1329 vector<string> technology_names;
1330 for (vector<Technology::Identifier>::iterator it = technology_order_.begin();
1331 it != technology_order_.end();
1332 ++it) {
1333 technology_names.push_back(Technology::NameFromIdentifier(*it));
1334 }
1335
1336 return JoinString(technology_names, ',');
1337}
1338
1339void Manager::SetTechnologyOrder(const string &order, Error *error) {
1340 vector<Technology::Identifier> new_order;
Ben Chanfad4a0b2012-04-18 15:49:59 -07001341 SLOG(Manager, 2) << "Setting technology order to " << order;
Paul Stewart20088d82012-02-16 06:58:55 -08001342 if (!Technology::GetTechnologyVectorFromString(order, &new_order, error)) {
1343 return;
Paul Stewart22aa71b2011-09-16 12:15:11 -07001344 }
1345
1346 technology_order_ = new_order;
1347 SortServices();
1348}
1349
Paul Stewart75897df2011-04-27 09:05:53 -07001350} // namespace shill