blob: c18d8c15b747ca6ceedf77db962301ed9bfffd84 [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>
mukesh agrawal7a4e4002011-09-06 11:26:05 -070011#include <map>
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
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>
Gaurav Shah435de2c2011-11-17 19:01:07 -080018#include <base/stl_util-inl.h>
Paul Stewart22aa71b2011-09-16 12:15:11 -070019#include <base/string_split.h>
20#include <base/string_util.h>
Chris Masone3bd3c8c2011-06-13 08:20:26 -070021#include <chromeos/dbus/service_constants.h>
Chris Masoneee929b72011-05-10 10:02:18 -070022
Chris Masoned0ceb8c2011-06-02 10:05:39 -070023#include "shill/adaptor_interfaces.h"
Paul Stewartc1dec4d2011-12-08 15:25:28 -080024#include "shill/connection.h"
Paul Stewart75897df2011-04-27 09:05:53 -070025#include "shill/control_interface.h"
Chris Masoned0ceb8c2011-06-02 10:05:39 -070026#include "shill/dbus_adaptor.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"
Chris Masone9d779932011-08-25 16:33:41 -070033#include "shill/key_file_store.h"
Paul Stewart22aa71b2011-09-16 12:15:11 -070034#include "shill/service_sorter.h"
Chris Masone7aa5f902011-07-11 11:13:35 -070035#include "shill/profile.h"
Chris Masoneb925cc82011-06-22 15:39:57 -070036#include "shill/property_accessor.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"
mukesh agrawal7a4e4002011-09-06 11:26:05 -070039#include "shill/wifi.h"
40#include "shill/wifi_service.h"
Paul Stewart75897df2011-04-27 09:05:53 -070041
Paul Stewart22aa71b2011-09-16 12:15:11 -070042using std::map;
Gaurav Shah435de2c2011-11-17 19:01:07 -080043using std::set;
Paul Stewart75897df2011-04-27 09:05:53 -070044using std::string;
Chris Masone9be4a9d2011-05-16 15:44:09 -070045using std::vector;
Paul Stewart75897df2011-04-27 09:05:53 -070046
47namespace shill {
Paul Stewarte6132022011-08-16 09:11:02 -070048
mukesh agrawal7a4e4002011-09-06 11:26:05 -070049// static
50const char Manager::kManagerErrorNoDevice[] = "no wifi devices available";
51
Paul Stewart75897df2011-04-27 09:05:53 -070052Manager::Manager(ControlInterface *control_interface,
Darin Petkov887f2982011-07-14 16:10:17 -070053 EventDispatcher *dispatcher,
Thieu Le3426c8f2012-01-11 17:35:11 -080054 Metrics *metrics,
Chris Masone2ae797d2011-08-23 20:41:00 -070055 GLib *glib,
56 const string &run_directory,
57 const string &storage_directory,
58 const string &user_storage_format)
mukesh agrawal8a3188d2011-12-01 20:56:44 +000059 : dispatcher_(dispatcher),
60 task_factory_(this),
61 run_path_(FilePath(run_directory)),
62 storage_path_(FilePath(storage_directory)),
63 user_storage_format_(user_storage_format),
64 adaptor_(control_interface->CreateManagerAdaptor(this)),
Thieu Le3426c8f2012-01-11 17:35:11 -080065 device_info_(control_interface, dispatcher, metrics, this),
66 modem_info_(control_interface, dispatcher, metrics, this, glib),
mukesh agrawal8a3188d2011-12-01 20:56:44 +000067 running_(false),
68 connect_profiles_to_rpc_(true),
69 ephemeral_profile_(new EphemeralProfile(control_interface, this)),
70 control_interface_(control_interface),
Thieu Le3426c8f2012-01-11 17:35:11 -080071 metrics_(metrics),
mukesh agrawal8a3188d2011-12-01 20:56:44 +000072 glib_(glib) {
Chris Masone7aa5f902011-07-11 11:13:35 -070073 HelpRegisterDerivedString(flimflam::kActiveProfileProperty,
74 &Manager::GetActiveProfileName,
75 NULL);
Chris Masone27c4aa52011-07-02 13:10:14 -070076 HelpRegisterDerivedStrings(flimflam::kAvailableTechnologiesProperty,
77 &Manager::AvailableTechnologies,
78 NULL);
Chris Masone88cbd5f2011-07-03 14:30:04 -070079 store_.RegisterString(flimflam::kCheckPortalListProperty,
80 &props_.check_portal_list);
Chris Masone27c4aa52011-07-02 13:10:14 -070081 HelpRegisterDerivedStrings(flimflam::kConnectedTechnologiesProperty,
82 &Manager::ConnectedTechnologies,
83 NULL);
Chris Masone88cbd5f2011-07-03 14:30:04 -070084 store_.RegisterString(flimflam::kCountryProperty, &props_.country);
Chris Masone27c4aa52011-07-02 13:10:14 -070085 HelpRegisterDerivedString(flimflam::kDefaultTechnologyProperty,
86 &Manager::DefaultTechnology,
87 NULL);
Chris Masone27c4aa52011-07-02 13:10:14 -070088 HelpRegisterDerivedStrings(flimflam::kDevicesProperty,
89 &Manager::EnumerateDevices,
90 NULL);
Chris Masone88cbd5f2011-07-03 14:30:04 -070091 HelpRegisterDerivedStrings(flimflam::kEnabledTechnologiesProperty,
92 &Manager::EnabledTechnologies,
93 NULL);
94 store_.RegisterBool(flimflam::kOfflineModeProperty, &props_.offline_mode);
95 store_.RegisterString(flimflam::kPortalURLProperty, &props_.portal_url);
96 HelpRegisterDerivedString(flimflam::kStateProperty,
97 &Manager::CalculateState,
98 NULL);
Chris Masone27c4aa52011-07-02 13:10:14 -070099 HelpRegisterDerivedStrings(flimflam::kServicesProperty,
100 &Manager::EnumerateAvailableServices,
101 NULL);
102 HelpRegisterDerivedStrings(flimflam::kServiceWatchListProperty,
103 &Manager::EnumerateWatchedServices,
104 NULL);
Chris Masone3c3f6a12011-07-01 10:01:41 -0700105
Chris Masone4d42df82011-07-02 17:09:39 -0700106 // TODO(cmasone): Wire these up once we actually put in profile support.
Chris Masoneb925cc82011-06-22 15:39:57 -0700107 // known_properties_.push_back(flimflam::kProfilesProperty);
Chris Masoneb07006b2011-05-14 16:10:04 -0700108 VLOG(2) << "Manager initialized.";
Paul Stewart75897df2011-04-27 09:05:53 -0700109}
110
Chris Masone6791a432011-07-12 13:23:19 -0700111Manager::~Manager() {
Chris Masone9d779932011-08-25 16:33:41 -0700112 profiles_.clear();
Chris Masone6791a432011-07-12 13:23:19 -0700113}
Paul Stewart75897df2011-04-27 09:05:53 -0700114
mukesh agrawal8f317b62011-07-15 11:53:23 -0700115void Manager::AddDeviceToBlackList(const string &device_name) {
116 device_info_.AddDeviceToBlackList(device_name);
117}
118
Paul Stewart75897df2011-04-27 09:05:53 -0700119void Manager::Start() {
Paul Stewart0af98bf2011-05-10 17:38:08 -0700120 LOG(INFO) << "Manager started.";
Paul Stewarte6132022011-08-16 09:11:02 -0700121
Chris Masone2ae797d2011-08-23 20:41:00 -0700122 CHECK(file_util::CreateDirectory(run_path_)) << run_path_.value();
Paul Stewarte6132022011-08-16 09:11:02 -0700123 Resolver::GetInstance()->set_path(run_path_.Append("resolv.conf"));
Chris Masone2ae797d2011-08-23 20:41:00 -0700124
Gaurav Shah71354762011-11-28 19:22:49 -0800125 InitializeProfiles();
Paul Stewart75897df2011-04-27 09:05:53 -0700126 running_ = true;
Chris Masone413a3192011-05-09 17:10:05 -0700127 adaptor_->UpdateRunning();
Paul Stewart0af98bf2011-05-10 17:38:08 -0700128 device_info_.Start();
Darin Petkov887f2982011-07-14 16:10:17 -0700129 modem_info_.Start();
Paul Stewart75897df2011-04-27 09:05:53 -0700130}
131
132void Manager::Stop() {
133 running_ = false;
Chris Masone9d779932011-08-25 16:33:41 -0700134 // Persist profile, device, service information to disk.
135 vector<ProfileRefPtr>::iterator it;
136 for (it = profiles_.begin(); it != profiles_.end(); ++it) {
Chris Masone6515aab2011-10-12 16:19:09 -0700137 (*it)->Save();
Chris Masone9d779932011-08-25 16:33:41 -0700138 }
Chris Masone9d779932011-08-25 16:33:41 -0700139
Thieu Le1271d682011-11-02 22:48:19 +0000140 vector<ServiceRefPtr>::iterator services_it;
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000141 Error e;
Thieu Le1271d682011-11-02 22:48:19 +0000142 for (services_it = services_.begin(); services_it != services_.end();
143 ++services_it) {
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000144 (*services_it)->Disconnect(&e);
Thieu Le1271d682011-11-02 22:48:19 +0000145 }
146
Chris Masone413a3192011-05-09 17:10:05 -0700147 adaptor_->UpdateRunning();
Darin Petkov887f2982011-07-14 16:10:17 -0700148 modem_info_.Stop();
149 device_info_.Stop();
Paul Stewart75897df2011-04-27 09:05:53 -0700150}
151
Gaurav Shah71354762011-11-28 19:22:49 -0800152void Manager::InitializeProfiles() {
153 DCHECK(profiles_.empty());
154 // The default profile must go first on the stack.
155 CHECK(file_util::CreateDirectory(storage_path_)) << storage_path_.value();
Paul Stewart870523b2012-01-11 17:00:42 -0800156 scoped_refptr<DefaultProfile>
157 default_profile(new DefaultProfile(control_interface_,
Gaurav Shah71354762011-11-28 19:22:49 -0800158 this,
159 storage_path_,
160 props_));
Paul Stewart870523b2012-01-11 17:00:42 -0800161 CHECK(default_profile->InitStorage(glib_, Profile::kCreateOrOpenExisting,
162 NULL));
163 CHECK(default_profile->LoadManagerProperties(&props_));
164 profiles_.push_back(default_profile.release());
Gaurav Shah71354762011-11-28 19:22:49 -0800165 Error error;
Paul Stewart19c871d2011-12-15 16:10:13 -0800166 string path;
Gaurav Shah71354762011-11-28 19:22:49 -0800167 for (vector<string>::iterator it = startup_profiles_.begin();
168 it != startup_profiles_.end(); ++it)
Paul Stewart19c871d2011-12-15 16:10:13 -0800169 PushProfile(*it, &path, &error);
Gaurav Shah71354762011-11-28 19:22:49 -0800170}
171
Paul Stewart19c871d2011-12-15 16:10:13 -0800172void Manager::CreateProfile(const string &name, string *path, Error *error) {
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700173 Profile::Identifier ident;
174 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700175 Error::PopulateAndLog(error, Error::kInvalidArguments,
176 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700177 return;
178 }
179 ProfileRefPtr profile(new Profile(control_interface_,
180 this,
181 ident,
182 user_storage_format_,
Paul Stewart19c871d2011-12-15 16:10:13 -0800183 connect_profiles_to_rpc_));
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700184 if (!profile->InitStorage(glib_, Profile::kCreateNew, error)) {
Paul Stewart19c871d2011-12-15 16:10:13 -0800185 // |error| will have been populated by InitStorage().
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700186 return;
187 }
188
189 // Save profile data out, and then let the scoped pointer fall out of scope.
190 if (!profile->Save()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700191 Error::PopulateAndLog(error, Error::kInternalError,
192 "Profile name " + name + " could not be saved");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700193 return;
194 }
Paul Stewart19c871d2011-12-15 16:10:13 -0800195
196 *path = profile->GetRpcIdentifier();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700197}
198
Paul Stewart19c871d2011-12-15 16:10:13 -0800199void Manager::PushProfile(const string &name, string *path, Error *error) {
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700200 Profile::Identifier ident;
201 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700202 Error::PopulateAndLog(error, Error::kInvalidArguments,
203 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700204 return;
205 }
206
207 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
208 it != profiles_.end();
209 ++it) {
210 if ((*it)->MatchesIdentifier(ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700211 Error::PopulateAndLog(error, Error::kAlreadyExists,
212 "Profile name " + name + " is already on stack");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700213 return;
214 }
215 }
216
217 if (ident.user.empty()) {
218 // The manager will have only one machine-wide profile, and this is the
219 // DefaultProfile. This means no other profiles can be loaded that do
220 // not have a user component.
221 // TODO(pstew): This is all well and good, but WiFi autotests try to
222 // creating a default profile (by a name other than "default") in order
223 // to avoid leaving permanent side effects to devices under test. This
224 // whole thing will need to be reworked in order to allow that to happen,
225 // or the autotests (or their expectations) will need to change.
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000226 // crosbug.com/24461
Paul Stewartbe005172011-11-02 18:10:29 -0700227 Error::PopulateAndLog(error, Error::kInvalidArguments,
228 "Cannot load non-default global profile " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700229 return;
230 }
231
232 ProfileRefPtr profile(new Profile(control_interface_,
233 this,
234 ident,
235 user_storage_format_,
236 connect_profiles_to_rpc_));
237 if (!profile->InitStorage(glib_, Profile::kOpenExisting, error)) {
Paul Stewart19c871d2011-12-15 16:10:13 -0800238 // |error| will have been populated by InitStorage().
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700239 return;
240 }
241
Paul Stewarta849a3d2011-11-03 05:54:09 -0700242 profiles_.push_back(profile);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700243
244 // Offer each registered Service the opportunity to join this new Profile.
Paul Stewarta41e38d2011-11-11 07:47:29 -0800245 for (vector<ServiceRefPtr>::iterator it = services_.begin();
246 it != services_.end(); ++it) {
Paul Stewartbba6a5b2011-11-02 18:45:59 -0700247 profile->ConfigureService(*it);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700248 }
249
Paul Stewarta41e38d2011-11-11 07:47:29 -0800250 // Shop the Profile contents around to Devices which can create
251 // non-visible services.
252 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
253 it != devices_.end(); ++it) {
254 profile->ConfigureDevice(*it);
255 }
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800256
Paul Stewart19c871d2011-12-15 16:10:13 -0800257 *path = profile->GetRpcIdentifier();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800258 SortServices();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700259}
260
261void Manager::PopProfileInternal() {
262 CHECK(!profiles_.empty());
263 ProfileRefPtr active_profile = profiles_.back();
264 profiles_.pop_back();
265 vector<ServiceRefPtr>::iterator s_it;
266 for (s_it = services_.begin(); s_it != services_.end(); ++s_it) {
267 if ((*s_it)->profile().get() == active_profile.get()) {
268 vector<ProfileRefPtr>::reverse_iterator p_it;
269 for (p_it = profiles_.rbegin(); p_it != profiles_.rend(); ++p_it) {
Paul Stewartbba6a5b2011-11-02 18:45:59 -0700270 if ((*p_it)->ConfigureService(*s_it)) {
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700271 break;
272 }
273 }
274 if (p_it == profiles_.rend()) {
275 ephemeral_profile_->AdoptService(*s_it);
Paul Stewarta41e38d2011-11-11 07:47:29 -0800276 (*s_it)->Unload();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700277 }
278 }
279 }
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800280 SortServices();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700281}
282
Paul Stewarta41e38d2011-11-11 07:47:29 -0800283void Manager::PopProfile(const string &name, Error *error) {
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700284 Profile::Identifier ident;
285 if (profiles_.empty()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700286 Error::PopulateAndLog(error, Error::kNotFound, "Profile stack is empty");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700287 return;
288 }
289 ProfileRefPtr active_profile = profiles_.back();
290 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700291 Error::PopulateAndLog(error, Error::kInvalidArguments,
292 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700293 return;
294 }
295 if (!active_profile->MatchesIdentifier(ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700296 Error::PopulateAndLog(error, Error::kNotSupported,
297 name + " is not the active profile");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700298 return;
299 }
300 PopProfileInternal();
301}
302
303void Manager::PopAnyProfile(Error *error) {
304 Profile::Identifier ident;
305 if (profiles_.empty()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700306 Error::PopulateAndLog(error, Error::kNotFound, "Profile stack is empty");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700307 return;
308 }
309 PopProfileInternal();
310}
311
Chris Masone7aa5f902011-07-11 11:13:35 -0700312const ProfileRefPtr &Manager::ActiveProfile() {
Chris Masoneb9c00592011-10-06 13:10:39 -0700313 DCHECK_NE(profiles_.size(), 0);
Chris Masone7aa5f902011-07-11 11:13:35 -0700314 return profiles_.back();
315}
316
Chris Masone6515aab2011-10-12 16:19:09 -0700317bool Manager::MoveServiceToProfile(const ServiceRefPtr &to_move,
318 const ProfileRefPtr &destination) {
319 const ProfileRefPtr from = to_move->profile();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800320 VLOG(2) << "Moving service "
321 << to_move->UniqueName()
322 << " to profile "
323 << destination->GetFriendlyName()
324 << " from "
325 << from->GetFriendlyName();
Chris Masone6515aab2011-10-12 16:19:09 -0700326 return destination->AdoptService(to_move) &&
327 from->AbandonService(to_move);
Chris Masone6791a432011-07-12 13:23:19 -0700328}
329
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800330void Manager::SetProfileForService(const ServiceRefPtr &to_set,
331 const string &profile_rpcid,
332 Error *error) {
333 for (vector<ProfileRefPtr>::iterator it = profiles_.begin();
334 it != profiles_.end();
335 ++it) {
336 if (profile_rpcid == (*it)->GetRpcIdentifier()) {
337 if (to_set->profile().get() == it->get()) {
338 Error::PopulateAndLog(error, Error::kInvalidArguments,
339 "Service is already connected to this profile");
340 } else if (!MoveServiceToProfile(to_set, *it)) {
341 Error::PopulateAndLog(error, Error::kInternalError,
342 "Unable to move service to profile");
343 }
344 return;
345 }
346 }
347 Error::PopulateAndLog(error, Error::kInvalidArguments,
348 "Unknown Profile requested for Service");
349}
350
Chris Masone2b105542011-06-22 10:58:09 -0700351void Manager::RegisterDevice(const DeviceRefPtr &to_manage) {
Chris Masonec1e50412011-06-07 13:04:53 -0700352 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700353 for (it = devices_.begin(); it != devices_.end(); ++it) {
Chris Masonec1e50412011-06-07 13:04:53 -0700354 if (to_manage.get() == it->get())
Chris Masone9be4a9d2011-05-16 15:44:09 -0700355 return;
356 }
Chris Masonec1e50412011-06-07 13:04:53 -0700357 devices_.push_back(to_manage);
Paul Stewartf1ce5d22011-05-19 13:10:20 -0700358
Paul Stewarta41e38d2011-11-11 07:47:29 -0800359 // We are applying device properties from the DefaultProfile, and adding
360 // the union of hidden services in all loaded profiles to the device.
Chris Masone6515aab2011-10-12 16:19:09 -0700361 for (vector<ProfileRefPtr>::iterator it = profiles_.begin();
362 it != profiles_.end();
363 ++it) {
Paul Stewarta41e38d2011-11-11 07:47:29 -0800364 // Load device configuration, if any exists, as well as hidden services.
365 (*it)->ConfigureDevice(to_manage);
366
367 // Currently the only profile for which "Save" is implemented is the
368 // DefaultProfile. It iterates over all Devices and stores their state.
369 // We perform the Save now in case the device we have just registered
370 // is new and needs to be added to the stored DefaultProfile.
Chris Masone6515aab2011-10-12 16:19:09 -0700371 (*it)->Save();
372 }
Paul Stewarta41e38d2011-11-11 07:47:29 -0800373
374 // In normal usage, running_ will always be true when we are here, however
375 // unit tests sometimes do things in otherwise invalid states.
376 if (running_ && to_manage->powered())
377 to_manage->Start();
Gaurav Shah435de2c2011-11-17 19:01:07 -0800378
379 Error error;
380 adaptor_->EmitStringsChanged(flimflam::kAvailableTechnologiesProperty,
381 AvailableTechnologies(&error));
382 adaptor_->EmitStringsChanged(flimflam::kEnabledTechnologiesProperty,
383 EnabledTechnologies(&error));
Chris Masone9be4a9d2011-05-16 15:44:09 -0700384}
385
mukesh agrawal5029c6c2011-08-25 11:12:40 -0700386void Manager::DeregisterDevice(const DeviceRefPtr &to_forget) {
Chris Masonec1e50412011-06-07 13:04:53 -0700387 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700388 for (it = devices_.begin(); it != devices_.end(); ++it) {
Chris Masonec1e50412011-06-07 13:04:53 -0700389 if (to_forget.get() == it->get()) {
mukesh agrawal5029c6c2011-08-25 11:12:40 -0700390 VLOG(2) << "Deregistered device: " << to_forget->UniqueName();
391 to_forget->Stop();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700392 devices_.erase(it);
Gaurav Shah435de2c2011-11-17 19:01:07 -0800393 Error error;
394 adaptor_->EmitStringsChanged(flimflam::kAvailableTechnologiesProperty,
395 AvailableTechnologies(&error));
396 adaptor_->EmitStringsChanged(flimflam::kEnabledTechnologiesProperty,
397 EnabledTechnologies(&error));
Chris Masone9be4a9d2011-05-16 15:44:09 -0700398 return;
399 }
400 }
mukesh agrawal5029c6c2011-08-25 11:12:40 -0700401 VLOG(2) << __func__ << " unknown device: " << to_forget->UniqueName();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700402}
403
mukesh agrawal4eb4d782011-12-05 17:34:37 +0000404bool Manager::HasService(const ServiceRefPtr &service) {
405 vector<ServiceRefPtr>::iterator it;
406 for (it = services_.begin(); it != services_.end(); ++it) {
407 if ((*it)->UniqueName() == service->UniqueName())
408 return true;
409 }
410 return false;
411}
412
Chris Masone2b105542011-06-22 10:58:09 -0700413void Manager::RegisterService(const ServiceRefPtr &to_manage) {
Gaurav Shahc6d6c722011-11-17 18:59:39 -0800414 VLOG(2) << "In " << __func__ << "(): Registering service "
415 << to_manage->UniqueName();
mukesh agrawald835b202011-10-07 15:26:47 -0700416
Paul Stewartbba6a5b2011-11-02 18:45:59 -0700417 bool configured = false;
Paul Stewarta41e38d2011-11-11 07:47:29 -0800418 for (vector<ProfileRefPtr>::reverse_iterator it = profiles_.rbegin();
419 !configured && it != profiles_.rend();
Chris Masone157aa0c2011-10-03 09:24:31 -0700420 ++it) {
Paul Stewartbba6a5b2011-11-02 18:45:59 -0700421 configured = (*it)->ConfigureService(to_manage);
Chris Masone157aa0c2011-10-03 09:24:31 -0700422 }
Chris Masone6791a432011-07-12 13:23:19 -0700423
424 // If not found, add it to the ephemeral profile
Paul Stewartbba6a5b2011-11-02 18:45:59 -0700425 if (!configured)
Chris Masone6515aab2011-10-12 16:19:09 -0700426 ephemeral_profile_->AdoptService(to_manage);
Chris Masone6791a432011-07-12 13:23:19 -0700427
428 // Now add to OUR list.
Chris Masonec1e50412011-06-07 13:04:53 -0700429 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700430 for (it = services_.begin(); it != services_.end(); ++it) {
mukesh agrawald835b202011-10-07 15:26:47 -0700431 CHECK(to_manage->UniqueName() != (*it)->UniqueName());
Chris Masone9be4a9d2011-05-16 15:44:09 -0700432 }
Chris Masonec1e50412011-06-07 13:04:53 -0700433 services_.push_back(to_manage);
Paul Stewart22aa71b2011-09-16 12:15:11 -0700434 SortServices();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700435}
436
Chris Masone6515aab2011-10-12 16:19:09 -0700437void Manager::DeregisterService(const ServiceRefPtr &to_forget) {
Chris Masonec1e50412011-06-07 13:04:53 -0700438 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700439 for (it = services_.begin(); it != services_.end(); ++it) {
Chris Masone6791a432011-07-12 13:23:19 -0700440 if (to_forget->UniqueName() == (*it)->UniqueName()) {
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800441 DCHECK(!(*it)->connection());
Chris Masone9be4a9d2011-05-16 15:44:09 -0700442 services_.erase(it);
Paul Stewart22aa71b2011-09-16 12:15:11 -0700443 SortServices();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700444 return;
445 }
446 }
447}
448
mukesh agrawal00917ce2011-11-22 23:56:55 +0000449void Manager::UpdateService(const ServiceRefPtr &to_update) {
450 CHECK(to_update);
Paul Stewart03dba0b2011-08-22 16:32:45 -0700451 LOG(INFO) << "Service " << to_update->UniqueName() << " updated;"
Gaurav Shahc6d6c722011-11-17 18:59:39 -0800452 << " state: " << Service::ConnectStateToString(to_update->state())
453 << " failure: "
454 << Service::ConnectFailureToString(to_update->failure());
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000455 VLOG(2) << "IsConnected(): " << to_update->IsConnected();
456 VLOG(2) << "IsConnecting(): " << to_update->IsConnecting();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800457 if (to_update->IsConnected()) {
mukesh agrawal00917ce2011-11-22 23:56:55 +0000458 to_update->MakeFavorite();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800459 if (to_update->profile().get() == ephemeral_profile_.get()) {
460 if (profiles_.empty()) {
461 LOG(ERROR) << "Cannot assign profile to service: no profiles exist!";
462 } else {
463 MoveServiceToProfile(to_update, profiles_.back());
464 }
465 }
466 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700467 SortServices();
Paul Stewart03dba0b2011-08-22 16:32:45 -0700468}
469
Paul Stewartfdd16072011-09-16 12:41:35 -0700470void Manager::FilterByTechnology(Technology::Identifier tech,
Chris Masonec1e50412011-06-07 13:04:53 -0700471 vector<DeviceRefPtr> *found) {
Chris Masone9be4a9d2011-05-16 15:44:09 -0700472 CHECK(found);
Chris Masonec1e50412011-06-07 13:04:53 -0700473 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700474 for (it = devices_.begin(); it != devices_.end(); ++it) {
475 if ((*it)->TechnologyIs(tech))
476 found->push_back(*it);
477 }
478}
479
Paul Stewart22aa71b2011-09-16 12:15:11 -0700480ServiceRefPtr Manager::FindService(const string& name) {
Chris Masonec1e50412011-06-07 13:04:53 -0700481 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700482 for (it = services_.begin(); it != services_.end(); ++it) {
Chris Masone6791a432011-07-12 13:23:19 -0700483 if (name == (*it)->UniqueName())
Chris Masonee0dea762011-06-09 09:06:03 -0700484 return *it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700485 }
Chris Masonee0dea762011-06-09 09:06:03 -0700486 return NULL;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700487}
488
mukesh agrawalffa3d042011-10-06 15:26:10 -0700489void Manager::HelpRegisterDerivedString(
490 const string &name,
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800491 string(Manager::*get)(Error *),
mukesh agrawalffa3d042011-10-06 15:26:10 -0700492 void(Manager::*set)(const string&, Error *)) {
Chris Masone27c4aa52011-07-02 13:10:14 -0700493 store_.RegisterDerivedString(
494 name,
495 StringAccessor(new CustomAccessor<Manager, string>(this, get, set)));
Chris Masoneb925cc82011-06-22 15:39:57 -0700496}
497
mukesh agrawalffa3d042011-10-06 15:26:10 -0700498void Manager::HelpRegisterDerivedStrings(
499 const string &name,
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800500 Strings(Manager::*get)(Error *),
mukesh agrawalffa3d042011-10-06 15:26:10 -0700501 void(Manager::*set)(const Strings &, Error *)) {
Chris Masone27c4aa52011-07-02 13:10:14 -0700502 store_.RegisterDerivedStrings(
503 name,
504 StringsAccessor(new CustomAccessor<Manager, Strings>(this, get, set)));
Chris Masoneb925cc82011-06-22 15:39:57 -0700505}
506
Paul Stewart22aa71b2011-09-16 12:15:11 -0700507void Manager::SortServices() {
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800508 VLOG(4) << "In " << __func__;
509 ConnectionRefPtr default_connection;
510 if (!services_.empty()) {
511 // Keep track of the connection that was last considered default.
512 default_connection = services_[0]->connection();
513 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700514 sort(services_.begin(), services_.end(), ServiceSorter(technology_order_));
Paul Stewarta41e38d2011-11-11 07:47:29 -0800515
516 vector<string> service_paths;
517 vector<ServiceRefPtr>::iterator it;
518 for (it = services_.begin(); it != services_.end(); ++it) {
519 if ((*it)->IsVisible()) {
520 service_paths.push_back((*it)->GetRpcIdentifier());
521 }
522 }
523 adaptor_->EmitRpcIdentifierArrayChanged(flimflam::kServicesProperty,
524 service_paths);
Gaurav Shah435de2c2011-11-17 19:01:07 -0800525
526 Error error;
527 adaptor_->EmitStringsChanged(flimflam::kConnectedTechnologiesProperty,
528 ConnectedTechnologies(&error));
529 adaptor_->EmitStringChanged(flimflam::kDefaultTechnologyProperty,
530 DefaultTechnology(&error));
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800531
532 if (!services_.empty()) {
533 if (default_connection.get() &&
534 (services_[0]->connection().get() != default_connection.get())) {
535 default_connection->SetIsDefault(false);
536 }
537 if (services_[0]->connection().get()) {
538 services_[0]->connection()->SetIsDefault(true);
539 }
540 }
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800541
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000542 AutoConnect();
543}
544
545void Manager::AutoConnect() {
546 // We might be called in the middle of another request (e.g., as a
547 // consequence of Service::SetState calling UpdateService). To avoid
548 // re-entrancy issues in dbus-c++, defer to the event loop.
549 dispatcher_->PostTask(
550 task_factory_.NewRunnableMethod(&Manager::AutoConnectTask));
551 return;
552}
553
554void Manager::AutoConnectTask() {
555 if (services_.empty()) {
556 LOG(INFO) << "No services.";
557 return;
558 }
559
560 if (VLOG_IS_ON(4)) {
mukesh agrawal592516d2012-01-12 14:01:00 -0800561 VLOG(4) << "Sorted service list: "; // XXX check log
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000562 for (vector<ServiceRefPtr>::const_iterator it = services_.begin();
563 it != services_.end(); ++it) {
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000564 VLOG(4) << "Service " << (*it)->friendly_name()
565 << " IsConnected: " << (*it)->IsConnected()
566 << " IsConnecting: " << (*it)->IsConnecting()
567 << " IsFailed: " << (*it)->IsFailed()
568 << " connectable: " << (*it)->connectable()
569 << " auto_connect: " << (*it)->auto_connect()
570 << " favorite: " << (*it)->favorite()
571 << " priority: " << (*it)->priority()
572 << " security_level: " << (*it)->security_level()
573 << " strength: " << (*it)->strength()
574 << " UniqueName: " << (*it)->UniqueName();
575 }
576 }
577
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800578 // Perform auto-connect.
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000579 for (vector<ServiceRefPtr>::iterator it = services_.begin();
580 it != services_.end(); ++it) {
581 if ((*it)->auto_connect()) {
mukesh agrawal592516d2012-01-12 14:01:00 -0800582 LOG(INFO) << "Requesting autoconnect to service "
583 << (*it)->friendly_name() << ".";
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000584 (*it)->AutoConnect();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800585 }
586 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700587}
588
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800589string Manager::CalculateState(Error */*error*/) {
Chris Masoneb925cc82011-06-22 15:39:57 -0700590 return flimflam::kStateOffline;
591}
592
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800593vector<string> Manager::AvailableTechnologies(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -0800594 set<string> unique_technologies;
595 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
596 it != devices_.end(); ++it) {
597 unique_technologies.insert(
598 Technology::NameFromIdentifier((*it)->technology()));
599 }
600 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -0700601}
602
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800603vector<string> Manager::ConnectedTechnologies(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -0800604 set<string> unique_technologies;
605 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
606 it != devices_.end(); ++it) {
607 if ((*it)->IsConnected())
608 unique_technologies.insert(
609 Technology::NameFromIdentifier((*it)->technology()));
610 }
611 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -0700612}
613
Gaurav Shah435de2c2011-11-17 19:01:07 -0800614string Manager::DefaultTechnology(Error *error) {
615 return (!services_.empty() && services_[0]->IsConnected()) ?
616 services_[0]->GetTechnologyString(error) : "";
Chris Masoneb925cc82011-06-22 15:39:57 -0700617}
618
Gaurav Shah435de2c2011-11-17 19:01:07 -0800619vector<string> Manager::EnabledTechnologies(Error *error) {
620 // TODO(gauravsh): This must be wired up to the RPC interface to handle
621 // enabled/disabled devices as set by the user. crosbug.com/23319
622 return AvailableTechnologies(error);
Chris Masoneb925cc82011-06-22 15:39:57 -0700623}
624
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800625vector<string> Manager::EnumerateDevices(Error */*error*/) {
Chris Masone3c3f6a12011-07-01 10:01:41 -0700626 vector<string> device_rpc_ids;
627 for (vector<DeviceRefPtr>::const_iterator it = devices_.begin();
628 it != devices_.end();
629 ++it) {
630 device_rpc_ids.push_back((*it)->GetRpcIdentifier());
631 }
632 return device_rpc_ids;
633}
634
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800635vector<string> Manager::EnumerateAvailableServices(Error */*error*/) {
Chris Masone3c3f6a12011-07-01 10:01:41 -0700636 vector<string> service_rpc_ids;
637 for (vector<ServiceRefPtr>::const_iterator it = services_.begin();
638 it != services_.end();
639 ++it) {
640 service_rpc_ids.push_back((*it)->GetRpcIdentifier());
641 }
642 return service_rpc_ids;
643}
644
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800645vector<string> Manager::EnumerateWatchedServices(Error *error) {
Chris Masone6791a432011-07-12 13:23:19 -0700646 // TODO(cmasone): Filter this list for services in appropriate states.
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800647 return EnumerateAvailableServices(error);
Chris Masone3c3f6a12011-07-01 10:01:41 -0700648}
649
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800650string Manager::GetActiveProfileName(Error */*error*/) {
Chris Masone7df0c672011-07-15 10:24:54 -0700651 return ActiveProfile()->GetFriendlyName();
Chris Masone7aa5f902011-07-11 11:13:35 -0700652}
653
mukesh agrawal32399322011-09-01 10:53:43 -0700654// called via RPC (e.g., from ManagerDBusAdaptor)
mukesh agrawal7a4e4002011-09-06 11:26:05 -0700655WiFiServiceRefPtr Manager::GetWifiService(const KeyValueStore &args,
656 Error *error) {
Paul Stewarta41e38d2011-11-11 07:47:29 -0800657 vector<DeviceRefPtr> wifi_devices;
Paul Stewart22aa71b2011-09-16 12:15:11 -0700658 FilterByTechnology(Technology::kWifi, &wifi_devices);
mukesh agrawal7a4e4002011-09-06 11:26:05 -0700659 if (wifi_devices.empty()) {
660 error->Populate(Error::kInvalidArguments, kManagerErrorNoDevice);
661 return NULL;
662 } else {
663 WiFi *wifi = dynamic_cast<WiFi *>(wifi_devices.front().get());
664 CHECK(wifi);
665 return wifi->GetService(args, error);
666 }
667}
668
669// called via RPC (e.g., from ManagerDBusAdaptor)
Paul Stewart22aa71b2011-09-16 12:15:11 -0700670void Manager::RequestScan(const string &technology, Error *error) {
mukesh agrawal32399322011-09-01 10:53:43 -0700671 if (technology == flimflam::kTypeWifi || technology == "") {
672 vector<DeviceRefPtr> wifi_devices;
Paul Stewartfdd16072011-09-16 12:41:35 -0700673 FilterByTechnology(Technology::kWifi, &wifi_devices);
mukesh agrawal32399322011-09-01 10:53:43 -0700674
675 for (vector<DeviceRefPtr>::iterator it = wifi_devices.begin();
676 it != wifi_devices.end();
677 ++it) {
Darin Petkovc0865312011-09-16 15:31:20 -0700678 (*it)->Scan(error);
mukesh agrawal32399322011-09-01 10:53:43 -0700679 }
680 } else {
681 // TODO(quiche): support scanning for other technologies?
Paul Stewartbe005172011-11-02 18:10:29 -0700682 Error::PopulateAndLog(error, Error::kInvalidArguments,
683 "Unrecognized technology " + technology);
mukesh agrawal32399322011-09-01 10:53:43 -0700684 }
685}
686
Paul Stewart22aa71b2011-09-16 12:15:11 -0700687string Manager::GetTechnologyOrder() {
688 vector<string> technology_names;
689 for (vector<Technology::Identifier>::iterator it = technology_order_.begin();
690 it != technology_order_.end();
691 ++it) {
692 technology_names.push_back(Technology::NameFromIdentifier(*it));
693 }
694
695 return JoinString(technology_names, ',');
696}
697
698void Manager::SetTechnologyOrder(const string &order, Error *error) {
699 vector<Technology::Identifier> new_order;
700 map<Technology::Identifier, bool> seen;
701
702 vector<string> order_parts;
703 base::SplitString(order, ',', &order_parts);
704
705 for (vector<string>::iterator it = order_parts.begin();
706 it != order_parts.end();
707 ++it) {
708 Technology::Identifier identifier = Technology::IdentifierFromName(*it);
709
710 if (identifier == Technology::kUnknown) {
Paul Stewartbe005172011-11-02 18:10:29 -0700711 Error::PopulateAndLog(error, Error::kInvalidArguments,
712 *it + " is an unknown technology name");
Paul Stewart22aa71b2011-09-16 12:15:11 -0700713 return;
714 }
715
716 if (ContainsKey(seen, identifier)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700717 Error::PopulateAndLog(error, Error::kInvalidArguments,
718 *it + " is duplicated in the list");
Paul Stewart22aa71b2011-09-16 12:15:11 -0700719 return;
720 }
721 seen[identifier] = true;
722 new_order.push_back(identifier);
723 }
724
725 technology_order_ = new_order;
726 SortServices();
727}
728
Paul Stewart75897df2011-04-27 09:05:53 -0700729} // namespace shill