blob: 5511376811d95164c9045929a3c22e9cb5850a8b [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,
Chris Masone2ae797d2011-08-23 20:41:00 -070054 GLib *glib,
55 const string &run_directory,
56 const string &storage_directory,
57 const string &user_storage_format)
mukesh agrawal8a3188d2011-12-01 20:56:44 +000058 : dispatcher_(dispatcher),
59 task_factory_(this),
60 run_path_(FilePath(run_directory)),
61 storage_path_(FilePath(storage_directory)),
62 user_storage_format_(user_storage_format),
63 adaptor_(control_interface->CreateManagerAdaptor(this)),
64 device_info_(control_interface, dispatcher, this),
65 modem_info_(control_interface, dispatcher, this, glib),
66 running_(false),
67 connect_profiles_to_rpc_(true),
68 ephemeral_profile_(new EphemeralProfile(control_interface, this)),
69 control_interface_(control_interface),
70 glib_(glib) {
Chris Masone7aa5f902011-07-11 11:13:35 -070071 HelpRegisterDerivedString(flimflam::kActiveProfileProperty,
72 &Manager::GetActiveProfileName,
73 NULL);
Chris Masone27c4aa52011-07-02 13:10:14 -070074 HelpRegisterDerivedStrings(flimflam::kAvailableTechnologiesProperty,
75 &Manager::AvailableTechnologies,
76 NULL);
Chris Masone88cbd5f2011-07-03 14:30:04 -070077 store_.RegisterString(flimflam::kCheckPortalListProperty,
78 &props_.check_portal_list);
Chris Masone27c4aa52011-07-02 13:10:14 -070079 HelpRegisterDerivedStrings(flimflam::kConnectedTechnologiesProperty,
80 &Manager::ConnectedTechnologies,
81 NULL);
Chris Masone88cbd5f2011-07-03 14:30:04 -070082 store_.RegisterString(flimflam::kCountryProperty, &props_.country);
Chris Masone27c4aa52011-07-02 13:10:14 -070083 HelpRegisterDerivedString(flimflam::kDefaultTechnologyProperty,
84 &Manager::DefaultTechnology,
85 NULL);
Chris Masone27c4aa52011-07-02 13:10:14 -070086 HelpRegisterDerivedStrings(flimflam::kDevicesProperty,
87 &Manager::EnumerateDevices,
88 NULL);
Chris Masone88cbd5f2011-07-03 14:30:04 -070089 HelpRegisterDerivedStrings(flimflam::kEnabledTechnologiesProperty,
90 &Manager::EnabledTechnologies,
91 NULL);
92 store_.RegisterBool(flimflam::kOfflineModeProperty, &props_.offline_mode);
93 store_.RegisterString(flimflam::kPortalURLProperty, &props_.portal_url);
94 HelpRegisterDerivedString(flimflam::kStateProperty,
95 &Manager::CalculateState,
96 NULL);
Chris Masone27c4aa52011-07-02 13:10:14 -070097 HelpRegisterDerivedStrings(flimflam::kServicesProperty,
98 &Manager::EnumerateAvailableServices,
99 NULL);
100 HelpRegisterDerivedStrings(flimflam::kServiceWatchListProperty,
101 &Manager::EnumerateWatchedServices,
102 NULL);
Chris Masone3c3f6a12011-07-01 10:01:41 -0700103
Chris Masone4d42df82011-07-02 17:09:39 -0700104 // TODO(cmasone): Wire these up once we actually put in profile support.
Chris Masoneb925cc82011-06-22 15:39:57 -0700105 // known_properties_.push_back(flimflam::kProfilesProperty);
Chris Masoneb07006b2011-05-14 16:10:04 -0700106 VLOG(2) << "Manager initialized.";
Paul Stewart75897df2011-04-27 09:05:53 -0700107}
108
Chris Masone6791a432011-07-12 13:23:19 -0700109Manager::~Manager() {
Chris Masone9d779932011-08-25 16:33:41 -0700110 profiles_.clear();
Chris Masone6791a432011-07-12 13:23:19 -0700111}
Paul Stewart75897df2011-04-27 09:05:53 -0700112
mukesh agrawal8f317b62011-07-15 11:53:23 -0700113void Manager::AddDeviceToBlackList(const string &device_name) {
114 device_info_.AddDeviceToBlackList(device_name);
115}
116
Paul Stewart75897df2011-04-27 09:05:53 -0700117void Manager::Start() {
Paul Stewart0af98bf2011-05-10 17:38:08 -0700118 LOG(INFO) << "Manager started.";
Paul Stewarte6132022011-08-16 09:11:02 -0700119
Chris Masone2ae797d2011-08-23 20:41:00 -0700120 CHECK(file_util::CreateDirectory(run_path_)) << run_path_.value();
Paul Stewarte6132022011-08-16 09:11:02 -0700121 Resolver::GetInstance()->set_path(run_path_.Append("resolv.conf"));
Chris Masone2ae797d2011-08-23 20:41:00 -0700122
Gaurav Shah71354762011-11-28 19:22:49 -0800123 InitializeProfiles();
Paul Stewart75897df2011-04-27 09:05:53 -0700124 running_ = true;
Chris Masone413a3192011-05-09 17:10:05 -0700125 adaptor_->UpdateRunning();
Paul Stewart0af98bf2011-05-10 17:38:08 -0700126 device_info_.Start();
Darin Petkov887f2982011-07-14 16:10:17 -0700127 modem_info_.Start();
Paul Stewart75897df2011-04-27 09:05:53 -0700128}
129
130void Manager::Stop() {
131 running_ = false;
Chris Masone9d779932011-08-25 16:33:41 -0700132 // Persist profile, device, service information to disk.
133 vector<ProfileRefPtr>::iterator it;
134 for (it = profiles_.begin(); it != profiles_.end(); ++it) {
Chris Masone6515aab2011-10-12 16:19:09 -0700135 (*it)->Save();
Chris Masone9d779932011-08-25 16:33:41 -0700136 }
Chris Masone9d779932011-08-25 16:33:41 -0700137
Thieu Le1271d682011-11-02 22:48:19 +0000138 vector<ServiceRefPtr>::iterator services_it;
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000139 Error e;
Thieu Le1271d682011-11-02 22:48:19 +0000140 for (services_it = services_.begin(); services_it != services_.end();
141 ++services_it) {
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000142 (*services_it)->Disconnect(&e);
Thieu Le1271d682011-11-02 22:48:19 +0000143 }
144
Chris Masone413a3192011-05-09 17:10:05 -0700145 adaptor_->UpdateRunning();
Darin Petkov887f2982011-07-14 16:10:17 -0700146 modem_info_.Stop();
147 device_info_.Stop();
Paul Stewart75897df2011-04-27 09:05:53 -0700148}
149
Gaurav Shah71354762011-11-28 19:22:49 -0800150void Manager::InitializeProfiles() {
151 DCHECK(profiles_.empty());
152 // The default profile must go first on the stack.
153 CHECK(file_util::CreateDirectory(storage_path_)) << storage_path_.value();
154 profiles_.push_back(new DefaultProfile(control_interface_,
155 this,
156 storage_path_,
157 props_));
158 CHECK(profiles_[0]->InitStorage(glib_, Profile::kCreateOrOpenExisting, NULL));
159 Error error;
Paul Stewart19c871d2011-12-15 16:10:13 -0800160 string path;
Gaurav Shah71354762011-11-28 19:22:49 -0800161 for (vector<string>::iterator it = startup_profiles_.begin();
162 it != startup_profiles_.end(); ++it)
Paul Stewart19c871d2011-12-15 16:10:13 -0800163 PushProfile(*it, &path, &error);
Gaurav Shah71354762011-11-28 19:22:49 -0800164}
165
Paul Stewart19c871d2011-12-15 16:10:13 -0800166void Manager::CreateProfile(const string &name, string *path, Error *error) {
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700167 Profile::Identifier ident;
168 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700169 Error::PopulateAndLog(error, Error::kInvalidArguments,
170 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700171 return;
172 }
173 ProfileRefPtr profile(new Profile(control_interface_,
174 this,
175 ident,
176 user_storage_format_,
Paul Stewart19c871d2011-12-15 16:10:13 -0800177 connect_profiles_to_rpc_));
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700178 if (!profile->InitStorage(glib_, Profile::kCreateNew, error)) {
Paul Stewart19c871d2011-12-15 16:10:13 -0800179 // |error| will have been populated by InitStorage().
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700180 return;
181 }
182
183 // Save profile data out, and then let the scoped pointer fall out of scope.
184 if (!profile->Save()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700185 Error::PopulateAndLog(error, Error::kInternalError,
186 "Profile name " + name + " could not be saved");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700187 return;
188 }
Paul Stewart19c871d2011-12-15 16:10:13 -0800189
190 *path = profile->GetRpcIdentifier();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700191}
192
Paul Stewart19c871d2011-12-15 16:10:13 -0800193void Manager::PushProfile(const string &name, string *path, Error *error) {
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700194 Profile::Identifier ident;
195 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700196 Error::PopulateAndLog(error, Error::kInvalidArguments,
197 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700198 return;
199 }
200
201 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
202 it != profiles_.end();
203 ++it) {
204 if ((*it)->MatchesIdentifier(ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700205 Error::PopulateAndLog(error, Error::kAlreadyExists,
206 "Profile name " + name + " is already on stack");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700207 return;
208 }
209 }
210
211 if (ident.user.empty()) {
212 // The manager will have only one machine-wide profile, and this is the
213 // DefaultProfile. This means no other profiles can be loaded that do
214 // not have a user component.
215 // TODO(pstew): This is all well and good, but WiFi autotests try to
216 // creating a default profile (by a name other than "default") in order
217 // to avoid leaving permanent side effects to devices under test. This
218 // whole thing will need to be reworked in order to allow that to happen,
219 // or the autotests (or their expectations) will need to change.
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000220 // crosbug.com/24461
Paul Stewartbe005172011-11-02 18:10:29 -0700221 Error::PopulateAndLog(error, Error::kInvalidArguments,
222 "Cannot load non-default global profile " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700223 return;
224 }
225
226 ProfileRefPtr profile(new Profile(control_interface_,
227 this,
228 ident,
229 user_storage_format_,
230 connect_profiles_to_rpc_));
231 if (!profile->InitStorage(glib_, Profile::kOpenExisting, error)) {
Paul Stewart19c871d2011-12-15 16:10:13 -0800232 // |error| will have been populated by InitStorage().
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700233 return;
234 }
235
Paul Stewarta849a3d2011-11-03 05:54:09 -0700236 profiles_.push_back(profile);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700237
238 // Offer each registered Service the opportunity to join this new Profile.
Paul Stewarta41e38d2011-11-11 07:47:29 -0800239 for (vector<ServiceRefPtr>::iterator it = services_.begin();
240 it != services_.end(); ++it) {
Paul Stewartbba6a5b2011-11-02 18:45:59 -0700241 profile->ConfigureService(*it);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700242 }
243
Paul Stewarta41e38d2011-11-11 07:47:29 -0800244 // Shop the Profile contents around to Devices which can create
245 // non-visible services.
246 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
247 it != devices_.end(); ++it) {
248 profile->ConfigureDevice(*it);
249 }
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800250
Paul Stewart19c871d2011-12-15 16:10:13 -0800251 *path = profile->GetRpcIdentifier();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800252 SortServices();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700253}
254
255void Manager::PopProfileInternal() {
256 CHECK(!profiles_.empty());
257 ProfileRefPtr active_profile = profiles_.back();
258 profiles_.pop_back();
259 vector<ServiceRefPtr>::iterator s_it;
260 for (s_it = services_.begin(); s_it != services_.end(); ++s_it) {
261 if ((*s_it)->profile().get() == active_profile.get()) {
262 vector<ProfileRefPtr>::reverse_iterator p_it;
263 for (p_it = profiles_.rbegin(); p_it != profiles_.rend(); ++p_it) {
Paul Stewartbba6a5b2011-11-02 18:45:59 -0700264 if ((*p_it)->ConfigureService(*s_it)) {
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700265 break;
266 }
267 }
268 if (p_it == profiles_.rend()) {
269 ephemeral_profile_->AdoptService(*s_it);
Paul Stewarta41e38d2011-11-11 07:47:29 -0800270 (*s_it)->Unload();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700271 }
272 }
273 }
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800274 SortServices();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700275}
276
Paul Stewarta41e38d2011-11-11 07:47:29 -0800277void Manager::PopProfile(const string &name, Error *error) {
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700278 Profile::Identifier ident;
279 if (profiles_.empty()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700280 Error::PopulateAndLog(error, Error::kNotFound, "Profile stack is empty");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700281 return;
282 }
283 ProfileRefPtr active_profile = profiles_.back();
284 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700285 Error::PopulateAndLog(error, Error::kInvalidArguments,
286 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700287 return;
288 }
289 if (!active_profile->MatchesIdentifier(ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700290 Error::PopulateAndLog(error, Error::kNotSupported,
291 name + " is not the active profile");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700292 return;
293 }
294 PopProfileInternal();
295}
296
297void Manager::PopAnyProfile(Error *error) {
298 Profile::Identifier ident;
299 if (profiles_.empty()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700300 Error::PopulateAndLog(error, Error::kNotFound, "Profile stack is empty");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700301 return;
302 }
303 PopProfileInternal();
304}
305
Chris Masone7aa5f902011-07-11 11:13:35 -0700306const ProfileRefPtr &Manager::ActiveProfile() {
Chris Masoneb9c00592011-10-06 13:10:39 -0700307 DCHECK_NE(profiles_.size(), 0);
Chris Masone7aa5f902011-07-11 11:13:35 -0700308 return profiles_.back();
309}
310
Chris Masone6515aab2011-10-12 16:19:09 -0700311bool Manager::MoveServiceToProfile(const ServiceRefPtr &to_move,
312 const ProfileRefPtr &destination) {
313 const ProfileRefPtr from = to_move->profile();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800314 VLOG(2) << "Moving service "
315 << to_move->UniqueName()
316 << " to profile "
317 << destination->GetFriendlyName()
318 << " from "
319 << from->GetFriendlyName();
Chris Masone6515aab2011-10-12 16:19:09 -0700320 return destination->AdoptService(to_move) &&
321 from->AbandonService(to_move);
Chris Masone6791a432011-07-12 13:23:19 -0700322}
323
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800324void Manager::SetProfileForService(const ServiceRefPtr &to_set,
325 const string &profile_rpcid,
326 Error *error) {
327 for (vector<ProfileRefPtr>::iterator it = profiles_.begin();
328 it != profiles_.end();
329 ++it) {
330 if (profile_rpcid == (*it)->GetRpcIdentifier()) {
331 if (to_set->profile().get() == it->get()) {
332 Error::PopulateAndLog(error, Error::kInvalidArguments,
333 "Service is already connected to this profile");
334 } else if (!MoveServiceToProfile(to_set, *it)) {
335 Error::PopulateAndLog(error, Error::kInternalError,
336 "Unable to move service to profile");
337 }
338 return;
339 }
340 }
341 Error::PopulateAndLog(error, Error::kInvalidArguments,
342 "Unknown Profile requested for Service");
343}
344
Chris Masone2b105542011-06-22 10:58:09 -0700345void Manager::RegisterDevice(const DeviceRefPtr &to_manage) {
Chris Masonec1e50412011-06-07 13:04:53 -0700346 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700347 for (it = devices_.begin(); it != devices_.end(); ++it) {
Chris Masonec1e50412011-06-07 13:04:53 -0700348 if (to_manage.get() == it->get())
Chris Masone9be4a9d2011-05-16 15:44:09 -0700349 return;
350 }
Chris Masonec1e50412011-06-07 13:04:53 -0700351 devices_.push_back(to_manage);
Paul Stewartf1ce5d22011-05-19 13:10:20 -0700352
Paul Stewarta41e38d2011-11-11 07:47:29 -0800353 // We are applying device properties from the DefaultProfile, and adding
354 // the union of hidden services in all loaded profiles to the device.
Chris Masone6515aab2011-10-12 16:19:09 -0700355 for (vector<ProfileRefPtr>::iterator it = profiles_.begin();
356 it != profiles_.end();
357 ++it) {
Paul Stewarta41e38d2011-11-11 07:47:29 -0800358 // Load device configuration, if any exists, as well as hidden services.
359 (*it)->ConfigureDevice(to_manage);
360
361 // Currently the only profile for which "Save" is implemented is the
362 // DefaultProfile. It iterates over all Devices and stores their state.
363 // We perform the Save now in case the device we have just registered
364 // is new and needs to be added to the stored DefaultProfile.
Chris Masone6515aab2011-10-12 16:19:09 -0700365 (*it)->Save();
366 }
Paul Stewarta41e38d2011-11-11 07:47:29 -0800367
368 // In normal usage, running_ will always be true when we are here, however
369 // unit tests sometimes do things in otherwise invalid states.
370 if (running_ && to_manage->powered())
371 to_manage->Start();
Gaurav Shah435de2c2011-11-17 19:01:07 -0800372
373 Error error;
374 adaptor_->EmitStringsChanged(flimflam::kAvailableTechnologiesProperty,
375 AvailableTechnologies(&error));
376 adaptor_->EmitStringsChanged(flimflam::kEnabledTechnologiesProperty,
377 EnabledTechnologies(&error));
Chris Masone9be4a9d2011-05-16 15:44:09 -0700378}
379
mukesh agrawal5029c6c2011-08-25 11:12:40 -0700380void Manager::DeregisterDevice(const DeviceRefPtr &to_forget) {
Chris Masonec1e50412011-06-07 13:04:53 -0700381 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700382 for (it = devices_.begin(); it != devices_.end(); ++it) {
Chris Masonec1e50412011-06-07 13:04:53 -0700383 if (to_forget.get() == it->get()) {
mukesh agrawal5029c6c2011-08-25 11:12:40 -0700384 VLOG(2) << "Deregistered device: " << to_forget->UniqueName();
385 to_forget->Stop();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700386 devices_.erase(it);
Gaurav Shah435de2c2011-11-17 19:01:07 -0800387 Error error;
388 adaptor_->EmitStringsChanged(flimflam::kAvailableTechnologiesProperty,
389 AvailableTechnologies(&error));
390 adaptor_->EmitStringsChanged(flimflam::kEnabledTechnologiesProperty,
391 EnabledTechnologies(&error));
Chris Masone9be4a9d2011-05-16 15:44:09 -0700392 return;
393 }
394 }
mukesh agrawal5029c6c2011-08-25 11:12:40 -0700395 VLOG(2) << __func__ << " unknown device: " << to_forget->UniqueName();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700396}
397
mukesh agrawal4eb4d782011-12-05 17:34:37 +0000398bool Manager::HasService(const ServiceRefPtr &service) {
399 vector<ServiceRefPtr>::iterator it;
400 for (it = services_.begin(); it != services_.end(); ++it) {
401 if ((*it)->UniqueName() == service->UniqueName())
402 return true;
403 }
404 return false;
405}
406
Chris Masone2b105542011-06-22 10:58:09 -0700407void Manager::RegisterService(const ServiceRefPtr &to_manage) {
Gaurav Shahc6d6c722011-11-17 18:59:39 -0800408 VLOG(2) << "In " << __func__ << "(): Registering service "
409 << to_manage->UniqueName();
mukesh agrawald835b202011-10-07 15:26:47 -0700410
Paul Stewartbba6a5b2011-11-02 18:45:59 -0700411 bool configured = false;
Paul Stewarta41e38d2011-11-11 07:47:29 -0800412 for (vector<ProfileRefPtr>::reverse_iterator it = profiles_.rbegin();
413 !configured && it != profiles_.rend();
Chris Masone157aa0c2011-10-03 09:24:31 -0700414 ++it) {
Paul Stewartbba6a5b2011-11-02 18:45:59 -0700415 configured = (*it)->ConfigureService(to_manage);
Chris Masone157aa0c2011-10-03 09:24:31 -0700416 }
Chris Masone6791a432011-07-12 13:23:19 -0700417
418 // If not found, add it to the ephemeral profile
Paul Stewartbba6a5b2011-11-02 18:45:59 -0700419 if (!configured)
Chris Masone6515aab2011-10-12 16:19:09 -0700420 ephemeral_profile_->AdoptService(to_manage);
Chris Masone6791a432011-07-12 13:23:19 -0700421
422 // Now add to OUR list.
Chris Masonec1e50412011-06-07 13:04:53 -0700423 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700424 for (it = services_.begin(); it != services_.end(); ++it) {
mukesh agrawald835b202011-10-07 15:26:47 -0700425 CHECK(to_manage->UniqueName() != (*it)->UniqueName());
Chris Masone9be4a9d2011-05-16 15:44:09 -0700426 }
Chris Masonec1e50412011-06-07 13:04:53 -0700427 services_.push_back(to_manage);
Paul Stewart22aa71b2011-09-16 12:15:11 -0700428 SortServices();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700429}
430
Chris Masone6515aab2011-10-12 16:19:09 -0700431void Manager::DeregisterService(const ServiceRefPtr &to_forget) {
Chris Masonec1e50412011-06-07 13:04:53 -0700432 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700433 for (it = services_.begin(); it != services_.end(); ++it) {
Chris Masone6791a432011-07-12 13:23:19 -0700434 if (to_forget->UniqueName() == (*it)->UniqueName()) {
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800435 DCHECK(!(*it)->connection());
Chris Masone9be4a9d2011-05-16 15:44:09 -0700436 services_.erase(it);
Paul Stewart22aa71b2011-09-16 12:15:11 -0700437 SortServices();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700438 return;
439 }
440 }
441}
442
mukesh agrawal00917ce2011-11-22 23:56:55 +0000443void Manager::UpdateService(const ServiceRefPtr &to_update) {
444 CHECK(to_update);
Paul Stewart03dba0b2011-08-22 16:32:45 -0700445 LOG(INFO) << "Service " << to_update->UniqueName() << " updated;"
Gaurav Shahc6d6c722011-11-17 18:59:39 -0800446 << " state: " << Service::ConnectStateToString(to_update->state())
447 << " failure: "
448 << Service::ConnectFailureToString(to_update->failure());
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000449 VLOG(2) << "IsConnected(): " << to_update->IsConnected();
450 VLOG(2) << "IsConnecting(): " << to_update->IsConnecting();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800451 if (to_update->IsConnected()) {
mukesh agrawal00917ce2011-11-22 23:56:55 +0000452 to_update->MakeFavorite();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800453 if (to_update->profile().get() == ephemeral_profile_.get()) {
454 if (profiles_.empty()) {
455 LOG(ERROR) << "Cannot assign profile to service: no profiles exist!";
456 } else {
457 MoveServiceToProfile(to_update, profiles_.back());
458 }
459 }
460 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700461 SortServices();
Paul Stewart03dba0b2011-08-22 16:32:45 -0700462}
463
Paul Stewartfdd16072011-09-16 12:41:35 -0700464void Manager::FilterByTechnology(Technology::Identifier tech,
Chris Masonec1e50412011-06-07 13:04:53 -0700465 vector<DeviceRefPtr> *found) {
Chris Masone9be4a9d2011-05-16 15:44:09 -0700466 CHECK(found);
Chris Masonec1e50412011-06-07 13:04:53 -0700467 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700468 for (it = devices_.begin(); it != devices_.end(); ++it) {
469 if ((*it)->TechnologyIs(tech))
470 found->push_back(*it);
471 }
472}
473
Paul Stewart22aa71b2011-09-16 12:15:11 -0700474ServiceRefPtr Manager::FindService(const string& name) {
Chris Masonec1e50412011-06-07 13:04:53 -0700475 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700476 for (it = services_.begin(); it != services_.end(); ++it) {
Chris Masone6791a432011-07-12 13:23:19 -0700477 if (name == (*it)->UniqueName())
Chris Masonee0dea762011-06-09 09:06:03 -0700478 return *it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700479 }
Chris Masonee0dea762011-06-09 09:06:03 -0700480 return NULL;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700481}
482
mukesh agrawalffa3d042011-10-06 15:26:10 -0700483void Manager::HelpRegisterDerivedString(
484 const string &name,
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800485 string(Manager::*get)(Error *),
mukesh agrawalffa3d042011-10-06 15:26:10 -0700486 void(Manager::*set)(const string&, Error *)) {
Chris Masone27c4aa52011-07-02 13:10:14 -0700487 store_.RegisterDerivedString(
488 name,
489 StringAccessor(new CustomAccessor<Manager, string>(this, get, set)));
Chris Masoneb925cc82011-06-22 15:39:57 -0700490}
491
mukesh agrawalffa3d042011-10-06 15:26:10 -0700492void Manager::HelpRegisterDerivedStrings(
493 const string &name,
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800494 Strings(Manager::*get)(Error *),
mukesh agrawalffa3d042011-10-06 15:26:10 -0700495 void(Manager::*set)(const Strings &, Error *)) {
Chris Masone27c4aa52011-07-02 13:10:14 -0700496 store_.RegisterDerivedStrings(
497 name,
498 StringsAccessor(new CustomAccessor<Manager, Strings>(this, get, set)));
Chris Masoneb925cc82011-06-22 15:39:57 -0700499}
500
Paul Stewart22aa71b2011-09-16 12:15:11 -0700501void Manager::SortServices() {
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800502 VLOG(4) << "In " << __func__;
503 ConnectionRefPtr default_connection;
504 if (!services_.empty()) {
505 // Keep track of the connection that was last considered default.
506 default_connection = services_[0]->connection();
507 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700508 sort(services_.begin(), services_.end(), ServiceSorter(technology_order_));
Paul Stewarta41e38d2011-11-11 07:47:29 -0800509
510 vector<string> service_paths;
511 vector<ServiceRefPtr>::iterator it;
512 for (it = services_.begin(); it != services_.end(); ++it) {
513 if ((*it)->IsVisible()) {
514 service_paths.push_back((*it)->GetRpcIdentifier());
515 }
516 }
517 adaptor_->EmitRpcIdentifierArrayChanged(flimflam::kServicesProperty,
518 service_paths);
Gaurav Shah435de2c2011-11-17 19:01:07 -0800519
520 Error error;
521 adaptor_->EmitStringsChanged(flimflam::kConnectedTechnologiesProperty,
522 ConnectedTechnologies(&error));
523 adaptor_->EmitStringChanged(flimflam::kDefaultTechnologyProperty,
524 DefaultTechnology(&error));
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800525
526 if (!services_.empty()) {
527 if (default_connection.get() &&
528 (services_[0]->connection().get() != default_connection.get())) {
529 default_connection->SetIsDefault(false);
530 }
531 if (services_[0]->connection().get()) {
532 services_[0]->connection()->SetIsDefault(true);
533 }
534 }
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800535
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000536 AutoConnect();
537}
538
539void Manager::AutoConnect() {
540 // We might be called in the middle of another request (e.g., as a
541 // consequence of Service::SetState calling UpdateService). To avoid
542 // re-entrancy issues in dbus-c++, defer to the event loop.
543 dispatcher_->PostTask(
544 task_factory_.NewRunnableMethod(&Manager::AutoConnectTask));
545 return;
546}
547
548void Manager::AutoConnectTask() {
549 if (services_.empty()) {
550 LOG(INFO) << "No services.";
551 return;
552 }
553
554 if (VLOG_IS_ON(4)) {
555 for (vector<ServiceRefPtr>::const_iterator it = services_.begin();
556 it != services_.end(); ++it) {
557 VLOG(4) << "Sorted service list: ";
558 VLOG(4) << "Service " << (*it)->friendly_name()
559 << " IsConnected: " << (*it)->IsConnected()
560 << " IsConnecting: " << (*it)->IsConnecting()
561 << " IsFailed: " << (*it)->IsFailed()
562 << " connectable: " << (*it)->connectable()
563 << " auto_connect: " << (*it)->auto_connect()
564 << " favorite: " << (*it)->favorite()
565 << " priority: " << (*it)->priority()
566 << " security_level: " << (*it)->security_level()
567 << " strength: " << (*it)->strength()
568 << " UniqueName: " << (*it)->UniqueName();
569 }
570 }
571
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800572 // Perform auto-connect.
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000573 for (vector<ServiceRefPtr>::iterator it = services_.begin();
574 it != services_.end(); ++it) {
575 if ((*it)->auto_connect()) {
576 LOG(INFO) << "Initiating connect to " << (*it)->friendly_name() << ".";
577 (*it)->AutoConnect();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800578 }
579 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700580}
581
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800582string Manager::CalculateState(Error */*error*/) {
Chris Masoneb925cc82011-06-22 15:39:57 -0700583 return flimflam::kStateOffline;
584}
585
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800586vector<string> Manager::AvailableTechnologies(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -0800587 set<string> unique_technologies;
588 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
589 it != devices_.end(); ++it) {
590 unique_technologies.insert(
591 Technology::NameFromIdentifier((*it)->technology()));
592 }
593 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -0700594}
595
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800596vector<string> Manager::ConnectedTechnologies(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -0800597 set<string> unique_technologies;
598 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
599 it != devices_.end(); ++it) {
600 if ((*it)->IsConnected())
601 unique_technologies.insert(
602 Technology::NameFromIdentifier((*it)->technology()));
603 }
604 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -0700605}
606
Gaurav Shah435de2c2011-11-17 19:01:07 -0800607string Manager::DefaultTechnology(Error *error) {
608 return (!services_.empty() && services_[0]->IsConnected()) ?
609 services_[0]->GetTechnologyString(error) : "";
Chris Masoneb925cc82011-06-22 15:39:57 -0700610}
611
Gaurav Shah435de2c2011-11-17 19:01:07 -0800612vector<string> Manager::EnabledTechnologies(Error *error) {
613 // TODO(gauravsh): This must be wired up to the RPC interface to handle
614 // enabled/disabled devices as set by the user. crosbug.com/23319
615 return AvailableTechnologies(error);
Chris Masoneb925cc82011-06-22 15:39:57 -0700616}
617
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800618vector<string> Manager::EnumerateDevices(Error */*error*/) {
Chris Masone3c3f6a12011-07-01 10:01:41 -0700619 vector<string> device_rpc_ids;
620 for (vector<DeviceRefPtr>::const_iterator it = devices_.begin();
621 it != devices_.end();
622 ++it) {
623 device_rpc_ids.push_back((*it)->GetRpcIdentifier());
624 }
625 return device_rpc_ids;
626}
627
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800628vector<string> Manager::EnumerateAvailableServices(Error */*error*/) {
Chris Masone3c3f6a12011-07-01 10:01:41 -0700629 vector<string> service_rpc_ids;
630 for (vector<ServiceRefPtr>::const_iterator it = services_.begin();
631 it != services_.end();
632 ++it) {
633 service_rpc_ids.push_back((*it)->GetRpcIdentifier());
634 }
635 return service_rpc_ids;
636}
637
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800638vector<string> Manager::EnumerateWatchedServices(Error *error) {
Chris Masone6791a432011-07-12 13:23:19 -0700639 // TODO(cmasone): Filter this list for services in appropriate states.
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800640 return EnumerateAvailableServices(error);
Chris Masone3c3f6a12011-07-01 10:01:41 -0700641}
642
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800643string Manager::GetActiveProfileName(Error */*error*/) {
Chris Masone7df0c672011-07-15 10:24:54 -0700644 return ActiveProfile()->GetFriendlyName();
Chris Masone7aa5f902011-07-11 11:13:35 -0700645}
646
mukesh agrawal32399322011-09-01 10:53:43 -0700647// called via RPC (e.g., from ManagerDBusAdaptor)
mukesh agrawal7a4e4002011-09-06 11:26:05 -0700648WiFiServiceRefPtr Manager::GetWifiService(const KeyValueStore &args,
649 Error *error) {
Paul Stewarta41e38d2011-11-11 07:47:29 -0800650 vector<DeviceRefPtr> wifi_devices;
Paul Stewart22aa71b2011-09-16 12:15:11 -0700651 FilterByTechnology(Technology::kWifi, &wifi_devices);
mukesh agrawal7a4e4002011-09-06 11:26:05 -0700652 if (wifi_devices.empty()) {
653 error->Populate(Error::kInvalidArguments, kManagerErrorNoDevice);
654 return NULL;
655 } else {
656 WiFi *wifi = dynamic_cast<WiFi *>(wifi_devices.front().get());
657 CHECK(wifi);
658 return wifi->GetService(args, error);
659 }
660}
661
662// called via RPC (e.g., from ManagerDBusAdaptor)
Paul Stewart22aa71b2011-09-16 12:15:11 -0700663void Manager::RequestScan(const string &technology, Error *error) {
mukesh agrawal32399322011-09-01 10:53:43 -0700664 if (technology == flimflam::kTypeWifi || technology == "") {
665 vector<DeviceRefPtr> wifi_devices;
Paul Stewartfdd16072011-09-16 12:41:35 -0700666 FilterByTechnology(Technology::kWifi, &wifi_devices);
mukesh agrawal32399322011-09-01 10:53:43 -0700667
668 for (vector<DeviceRefPtr>::iterator it = wifi_devices.begin();
669 it != wifi_devices.end();
670 ++it) {
Darin Petkovc0865312011-09-16 15:31:20 -0700671 (*it)->Scan(error);
mukesh agrawal32399322011-09-01 10:53:43 -0700672 }
673 } else {
674 // TODO(quiche): support scanning for other technologies?
Paul Stewartbe005172011-11-02 18:10:29 -0700675 Error::PopulateAndLog(error, Error::kInvalidArguments,
676 "Unrecognized technology " + technology);
mukesh agrawal32399322011-09-01 10:53:43 -0700677 }
678}
679
Paul Stewart22aa71b2011-09-16 12:15:11 -0700680string Manager::GetTechnologyOrder() {
681 vector<string> technology_names;
682 for (vector<Technology::Identifier>::iterator it = technology_order_.begin();
683 it != technology_order_.end();
684 ++it) {
685 technology_names.push_back(Technology::NameFromIdentifier(*it));
686 }
687
688 return JoinString(technology_names, ',');
689}
690
691void Manager::SetTechnologyOrder(const string &order, Error *error) {
692 vector<Technology::Identifier> new_order;
693 map<Technology::Identifier, bool> seen;
694
695 vector<string> order_parts;
696 base::SplitString(order, ',', &order_parts);
697
698 for (vector<string>::iterator it = order_parts.begin();
699 it != order_parts.end();
700 ++it) {
701 Technology::Identifier identifier = Technology::IdentifierFromName(*it);
702
703 if (identifier == Technology::kUnknown) {
Paul Stewartbe005172011-11-02 18:10:29 -0700704 Error::PopulateAndLog(error, Error::kInvalidArguments,
705 *it + " is an unknown technology name");
Paul Stewart22aa71b2011-09-16 12:15:11 -0700706 return;
707 }
708
709 if (ContainsKey(seen, identifier)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700710 Error::PopulateAndLog(error, Error::kInvalidArguments,
711 *it + " is duplicated in the list");
Paul Stewart22aa71b2011-09-16 12:15:11 -0700712 return;
713 }
714 seen[identifier] = true;
715 new_order.push_back(identifier);
716 }
717
718 technology_order_ = new_order;
719 SortServices();
720}
721
Paul Stewart75897df2011-04-27 09:05:53 -0700722} // namespace shill