blob: e26dffefa519d8b25fd657e505162ca10f19df63 [file] [log] [blame]
Paul Stewart75897df2011-04-27 09:05:53 -07001// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
2// 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)
58 : run_path_(FilePath(run_directory)),
59 storage_path_(FilePath(storage_directory)),
60 user_storage_format_(user_storage_format),
Paul Stewarte6132022011-08-16 09:11:02 -070061 adaptor_(control_interface->CreateManagerAdaptor(this)),
Paul Stewartb50f0b92011-05-16 16:31:42 -070062 device_info_(control_interface, dispatcher, this),
Darin Petkov887f2982011-07-14 16:10:17 -070063 modem_info_(control_interface, dispatcher, this, glib),
Chris Masone6791a432011-07-12 13:23:19 -070064 running_(false),
Paul Stewart5dc40aa2011-10-28 19:43:43 -070065 connect_profiles_to_rpc_(true),
Chris Masone9d779932011-08-25 16:33:41 -070066 ephemeral_profile_(new EphemeralProfile(control_interface, this)),
Chris Masone2ae797d2011-08-23 20:41:00 -070067 control_interface_(control_interface),
68 glib_(glib) {
Chris Masone7aa5f902011-07-11 11:13:35 -070069 HelpRegisterDerivedString(flimflam::kActiveProfileProperty,
70 &Manager::GetActiveProfileName,
71 NULL);
Chris Masone27c4aa52011-07-02 13:10:14 -070072 HelpRegisterDerivedStrings(flimflam::kAvailableTechnologiesProperty,
73 &Manager::AvailableTechnologies,
74 NULL);
Chris Masone88cbd5f2011-07-03 14:30:04 -070075 store_.RegisterString(flimflam::kCheckPortalListProperty,
76 &props_.check_portal_list);
Chris Masone27c4aa52011-07-02 13:10:14 -070077 HelpRegisterDerivedStrings(flimflam::kConnectedTechnologiesProperty,
78 &Manager::ConnectedTechnologies,
79 NULL);
Chris Masone88cbd5f2011-07-03 14:30:04 -070080 store_.RegisterString(flimflam::kCountryProperty, &props_.country);
Chris Masone27c4aa52011-07-02 13:10:14 -070081 HelpRegisterDerivedString(flimflam::kDefaultTechnologyProperty,
82 &Manager::DefaultTechnology,
83 NULL);
Chris Masone27c4aa52011-07-02 13:10:14 -070084 HelpRegisterDerivedStrings(flimflam::kDevicesProperty,
85 &Manager::EnumerateDevices,
86 NULL);
Chris Masone88cbd5f2011-07-03 14:30:04 -070087 HelpRegisterDerivedStrings(flimflam::kEnabledTechnologiesProperty,
88 &Manager::EnabledTechnologies,
89 NULL);
90 store_.RegisterBool(flimflam::kOfflineModeProperty, &props_.offline_mode);
91 store_.RegisterString(flimflam::kPortalURLProperty, &props_.portal_url);
92 HelpRegisterDerivedString(flimflam::kStateProperty,
93 &Manager::CalculateState,
94 NULL);
Chris Masone27c4aa52011-07-02 13:10:14 -070095 HelpRegisterDerivedStrings(flimflam::kServicesProperty,
96 &Manager::EnumerateAvailableServices,
97 NULL);
98 HelpRegisterDerivedStrings(flimflam::kServiceWatchListProperty,
99 &Manager::EnumerateWatchedServices,
100 NULL);
Chris Masone3c3f6a12011-07-01 10:01:41 -0700101
Chris Masone4d42df82011-07-02 17:09:39 -0700102 // TODO(cmasone): Wire these up once we actually put in profile support.
Chris Masoneb925cc82011-06-22 15:39:57 -0700103 // known_properties_.push_back(flimflam::kProfilesProperty);
Chris Masoneb07006b2011-05-14 16:10:04 -0700104 VLOG(2) << "Manager initialized.";
Paul Stewart75897df2011-04-27 09:05:53 -0700105}
106
Chris Masone6791a432011-07-12 13:23:19 -0700107Manager::~Manager() {
Chris Masone9d779932011-08-25 16:33:41 -0700108 profiles_.clear();
Chris Masone6791a432011-07-12 13:23:19 -0700109}
Paul Stewart75897df2011-04-27 09:05:53 -0700110
mukesh agrawal8f317b62011-07-15 11:53:23 -0700111void Manager::AddDeviceToBlackList(const string &device_name) {
112 device_info_.AddDeviceToBlackList(device_name);
113}
114
Paul Stewart75897df2011-04-27 09:05:53 -0700115void Manager::Start() {
Paul Stewart0af98bf2011-05-10 17:38:08 -0700116 LOG(INFO) << "Manager started.";
Paul Stewarte6132022011-08-16 09:11:02 -0700117
Chris Masone2ae797d2011-08-23 20:41:00 -0700118 CHECK(file_util::CreateDirectory(run_path_)) << run_path_.value();
Paul Stewarte6132022011-08-16 09:11:02 -0700119 Resolver::GetInstance()->set_path(run_path_.Append("resolv.conf"));
Chris Masone2ae797d2011-08-23 20:41:00 -0700120
Gaurav Shah71354762011-11-28 19:22:49 -0800121 InitializeProfiles();
Paul Stewart75897df2011-04-27 09:05:53 -0700122 running_ = true;
Chris Masone413a3192011-05-09 17:10:05 -0700123 adaptor_->UpdateRunning();
Paul Stewart0af98bf2011-05-10 17:38:08 -0700124 device_info_.Start();
Darin Petkov887f2982011-07-14 16:10:17 -0700125 modem_info_.Start();
Paul Stewart75897df2011-04-27 09:05:53 -0700126}
127
128void Manager::Stop() {
129 running_ = false;
Chris Masone9d779932011-08-25 16:33:41 -0700130 // Persist profile, device, service information to disk.
131 vector<ProfileRefPtr>::iterator it;
132 for (it = profiles_.begin(); it != profiles_.end(); ++it) {
Chris Masone6515aab2011-10-12 16:19:09 -0700133 (*it)->Save();
Chris Masone9d779932011-08-25 16:33:41 -0700134 }
Chris Masone9d779932011-08-25 16:33:41 -0700135
Thieu Le1271d682011-11-02 22:48:19 +0000136 vector<ServiceRefPtr>::iterator services_it;
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000137 Error e;
Thieu Le1271d682011-11-02 22:48:19 +0000138 for (services_it = services_.begin(); services_it != services_.end();
139 ++services_it) {
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000140 (*services_it)->Disconnect(&e);
Thieu Le1271d682011-11-02 22:48:19 +0000141 }
142
Chris Masone413a3192011-05-09 17:10:05 -0700143 adaptor_->UpdateRunning();
Darin Petkov887f2982011-07-14 16:10:17 -0700144 modem_info_.Stop();
145 device_info_.Stop();
Paul Stewart75897df2011-04-27 09:05:53 -0700146}
147
Gaurav Shah71354762011-11-28 19:22:49 -0800148void Manager::InitializeProfiles() {
149 DCHECK(profiles_.empty());
150 // The default profile must go first on the stack.
151 CHECK(file_util::CreateDirectory(storage_path_)) << storage_path_.value();
152 profiles_.push_back(new DefaultProfile(control_interface_,
153 this,
154 storage_path_,
155 props_));
156 CHECK(profiles_[0]->InitStorage(glib_, Profile::kCreateOrOpenExisting, NULL));
157 Error error;
158 for (vector<string>::iterator it = startup_profiles_.begin();
159 it != startup_profiles_.end(); ++it)
160 PushProfile(*it, &error);
161}
162
Paul Stewarta41e38d2011-11-11 07:47:29 -0800163void Manager::CreateProfile(const string &name, Error *error) {
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700164 Profile::Identifier ident;
165 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700166 Error::PopulateAndLog(error, Error::kInvalidArguments,
167 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700168 return;
169 }
170 ProfileRefPtr profile(new Profile(control_interface_,
171 this,
172 ident,
173 user_storage_format_,
174 false));
175 if (!profile->InitStorage(glib_, Profile::kCreateNew, error)) {
176 return;
177 }
178
179 // Save profile data out, and then let the scoped pointer fall out of scope.
180 if (!profile->Save()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700181 Error::PopulateAndLog(error, Error::kInternalError,
182 "Profile name " + name + " could not be saved");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700183 return;
184 }
185}
186
187void Manager::PushProfile(const string &name, Error *error) {
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700188 Profile::Identifier ident;
189 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700190 Error::PopulateAndLog(error, Error::kInvalidArguments,
191 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700192 return;
193 }
194
195 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
196 it != profiles_.end();
197 ++it) {
198 if ((*it)->MatchesIdentifier(ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700199 Error::PopulateAndLog(error, Error::kAlreadyExists,
200 "Profile name " + name + " is already on stack");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700201 return;
202 }
203 }
204
205 if (ident.user.empty()) {
206 // The manager will have only one machine-wide profile, and this is the
207 // DefaultProfile. This means no other profiles can be loaded that do
208 // not have a user component.
209 // TODO(pstew): This is all well and good, but WiFi autotests try to
210 // creating a default profile (by a name other than "default") in order
211 // to avoid leaving permanent side effects to devices under test. This
212 // whole thing will need to be reworked in order to allow that to happen,
213 // or the autotests (or their expectations) will need to change.
Paul Stewartbe005172011-11-02 18:10:29 -0700214 Error::PopulateAndLog(error, Error::kInvalidArguments,
215 "Cannot load non-default global profile " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700216 return;
217 }
218
219 ProfileRefPtr profile(new Profile(control_interface_,
220 this,
221 ident,
222 user_storage_format_,
223 connect_profiles_to_rpc_));
224 if (!profile->InitStorage(glib_, Profile::kOpenExisting, error)) {
225 return;
226 }
227
Paul Stewarta849a3d2011-11-03 05:54:09 -0700228 profiles_.push_back(profile);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700229
230 // Offer each registered Service the opportunity to join this new Profile.
Paul Stewarta41e38d2011-11-11 07:47:29 -0800231 for (vector<ServiceRefPtr>::iterator it = services_.begin();
232 it != services_.end(); ++it) {
Paul Stewartbba6a5b2011-11-02 18:45:59 -0700233 profile->ConfigureService(*it);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700234 }
235
Paul Stewarta41e38d2011-11-11 07:47:29 -0800236 // Shop the Profile contents around to Devices which can create
237 // non-visible services.
238 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
239 it != devices_.end(); ++it) {
240 profile->ConfigureDevice(*it);
241 }
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800242
243 SortServices();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700244}
245
246void Manager::PopProfileInternal() {
247 CHECK(!profiles_.empty());
248 ProfileRefPtr active_profile = profiles_.back();
249 profiles_.pop_back();
250 vector<ServiceRefPtr>::iterator s_it;
251 for (s_it = services_.begin(); s_it != services_.end(); ++s_it) {
252 if ((*s_it)->profile().get() == active_profile.get()) {
253 vector<ProfileRefPtr>::reverse_iterator p_it;
254 for (p_it = profiles_.rbegin(); p_it != profiles_.rend(); ++p_it) {
Paul Stewartbba6a5b2011-11-02 18:45:59 -0700255 if ((*p_it)->ConfigureService(*s_it)) {
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700256 break;
257 }
258 }
259 if (p_it == profiles_.rend()) {
260 ephemeral_profile_->AdoptService(*s_it);
Paul Stewarta41e38d2011-11-11 07:47:29 -0800261 (*s_it)->Unload();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700262 }
263 }
264 }
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800265 SortServices();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700266}
267
Paul Stewarta41e38d2011-11-11 07:47:29 -0800268void Manager::PopProfile(const string &name, Error *error) {
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700269 Profile::Identifier ident;
270 if (profiles_.empty()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700271 Error::PopulateAndLog(error, Error::kNotFound, "Profile stack is empty");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700272 return;
273 }
274 ProfileRefPtr active_profile = profiles_.back();
275 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700276 Error::PopulateAndLog(error, Error::kInvalidArguments,
277 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700278 return;
279 }
280 if (!active_profile->MatchesIdentifier(ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700281 Error::PopulateAndLog(error, Error::kNotSupported,
282 name + " is not the active profile");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700283 return;
284 }
285 PopProfileInternal();
286}
287
288void Manager::PopAnyProfile(Error *error) {
289 Profile::Identifier ident;
290 if (profiles_.empty()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700291 Error::PopulateAndLog(error, Error::kNotFound, "Profile stack is empty");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700292 return;
293 }
294 PopProfileInternal();
295}
296
Chris Masone7aa5f902011-07-11 11:13:35 -0700297const ProfileRefPtr &Manager::ActiveProfile() {
Chris Masoneb9c00592011-10-06 13:10:39 -0700298 DCHECK_NE(profiles_.size(), 0);
Chris Masone7aa5f902011-07-11 11:13:35 -0700299 return profiles_.back();
300}
301
Chris Masone6515aab2011-10-12 16:19:09 -0700302bool Manager::MoveServiceToProfile(const ServiceRefPtr &to_move,
303 const ProfileRefPtr &destination) {
304 const ProfileRefPtr from = to_move->profile();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800305 VLOG(2) << "Moving service "
306 << to_move->UniqueName()
307 << " to profile "
308 << destination->GetFriendlyName()
309 << " from "
310 << from->GetFriendlyName();
Chris Masone6515aab2011-10-12 16:19:09 -0700311 return destination->AdoptService(to_move) &&
312 from->AbandonService(to_move);
Chris Masone6791a432011-07-12 13:23:19 -0700313}
314
Chris Masone2b105542011-06-22 10:58:09 -0700315void Manager::RegisterDevice(const DeviceRefPtr &to_manage) {
Chris Masonec1e50412011-06-07 13:04:53 -0700316 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700317 for (it = devices_.begin(); it != devices_.end(); ++it) {
Chris Masonec1e50412011-06-07 13:04:53 -0700318 if (to_manage.get() == it->get())
Chris Masone9be4a9d2011-05-16 15:44:09 -0700319 return;
320 }
Chris Masonec1e50412011-06-07 13:04:53 -0700321 devices_.push_back(to_manage);
Paul Stewartf1ce5d22011-05-19 13:10:20 -0700322
Paul Stewarta41e38d2011-11-11 07:47:29 -0800323 // We are applying device properties from the DefaultProfile, and adding
324 // the union of hidden services in all loaded profiles to the device.
Chris Masone6515aab2011-10-12 16:19:09 -0700325 for (vector<ProfileRefPtr>::iterator it = profiles_.begin();
326 it != profiles_.end();
327 ++it) {
Paul Stewarta41e38d2011-11-11 07:47:29 -0800328 // Load device configuration, if any exists, as well as hidden services.
329 (*it)->ConfigureDevice(to_manage);
330
331 // Currently the only profile for which "Save" is implemented is the
332 // DefaultProfile. It iterates over all Devices and stores their state.
333 // We perform the Save now in case the device we have just registered
334 // is new and needs to be added to the stored DefaultProfile.
Chris Masone6515aab2011-10-12 16:19:09 -0700335 (*it)->Save();
336 }
Paul Stewarta41e38d2011-11-11 07:47:29 -0800337
338 // In normal usage, running_ will always be true when we are here, however
339 // unit tests sometimes do things in otherwise invalid states.
340 if (running_ && to_manage->powered())
341 to_manage->Start();
Gaurav Shah435de2c2011-11-17 19:01:07 -0800342
343 Error error;
344 adaptor_->EmitStringsChanged(flimflam::kAvailableTechnologiesProperty,
345 AvailableTechnologies(&error));
346 adaptor_->EmitStringsChanged(flimflam::kEnabledTechnologiesProperty,
347 EnabledTechnologies(&error));
Chris Masone9be4a9d2011-05-16 15:44:09 -0700348}
349
mukesh agrawal5029c6c2011-08-25 11:12:40 -0700350void Manager::DeregisterDevice(const DeviceRefPtr &to_forget) {
Chris Masonec1e50412011-06-07 13:04:53 -0700351 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700352 for (it = devices_.begin(); it != devices_.end(); ++it) {
Chris Masonec1e50412011-06-07 13:04:53 -0700353 if (to_forget.get() == it->get()) {
mukesh agrawal5029c6c2011-08-25 11:12:40 -0700354 VLOG(2) << "Deregistered device: " << to_forget->UniqueName();
355 to_forget->Stop();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700356 devices_.erase(it);
Gaurav Shah435de2c2011-11-17 19:01:07 -0800357 Error error;
358 adaptor_->EmitStringsChanged(flimflam::kAvailableTechnologiesProperty,
359 AvailableTechnologies(&error));
360 adaptor_->EmitStringsChanged(flimflam::kEnabledTechnologiesProperty,
361 EnabledTechnologies(&error));
Chris Masone9be4a9d2011-05-16 15:44:09 -0700362 return;
363 }
364 }
mukesh agrawal5029c6c2011-08-25 11:12:40 -0700365 VLOG(2) << __func__ << " unknown device: " << to_forget->UniqueName();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700366}
367
mukesh agrawal4eb4d782011-12-05 17:34:37 +0000368bool Manager::HasService(const ServiceRefPtr &service) {
369 vector<ServiceRefPtr>::iterator it;
370 for (it = services_.begin(); it != services_.end(); ++it) {
371 if ((*it)->UniqueName() == service->UniqueName())
372 return true;
373 }
374 return false;
375}
376
Chris Masone2b105542011-06-22 10:58:09 -0700377void Manager::RegisterService(const ServiceRefPtr &to_manage) {
Gaurav Shahc6d6c722011-11-17 18:59:39 -0800378 VLOG(2) << "In " << __func__ << "(): Registering service "
379 << to_manage->UniqueName();
mukesh agrawald835b202011-10-07 15:26:47 -0700380
Paul Stewartbba6a5b2011-11-02 18:45:59 -0700381 bool configured = false;
Paul Stewarta41e38d2011-11-11 07:47:29 -0800382 for (vector<ProfileRefPtr>::reverse_iterator it = profiles_.rbegin();
383 !configured && it != profiles_.rend();
Chris Masone157aa0c2011-10-03 09:24:31 -0700384 ++it) {
Paul Stewartbba6a5b2011-11-02 18:45:59 -0700385 configured = (*it)->ConfigureService(to_manage);
Chris Masone157aa0c2011-10-03 09:24:31 -0700386 }
Chris Masone6791a432011-07-12 13:23:19 -0700387
388 // If not found, add it to the ephemeral profile
Paul Stewartbba6a5b2011-11-02 18:45:59 -0700389 if (!configured)
Chris Masone6515aab2011-10-12 16:19:09 -0700390 ephemeral_profile_->AdoptService(to_manage);
Chris Masone6791a432011-07-12 13:23:19 -0700391
392 // Now add to OUR list.
Chris Masonec1e50412011-06-07 13:04:53 -0700393 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700394 for (it = services_.begin(); it != services_.end(); ++it) {
mukesh agrawald835b202011-10-07 15:26:47 -0700395 CHECK(to_manage->UniqueName() != (*it)->UniqueName());
Chris Masone9be4a9d2011-05-16 15:44:09 -0700396 }
Chris Masonec1e50412011-06-07 13:04:53 -0700397 services_.push_back(to_manage);
Paul Stewart22aa71b2011-09-16 12:15:11 -0700398 SortServices();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700399}
400
Chris Masone6515aab2011-10-12 16:19:09 -0700401void Manager::DeregisterService(const ServiceRefPtr &to_forget) {
Chris Masonec1e50412011-06-07 13:04:53 -0700402 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700403 for (it = services_.begin(); it != services_.end(); ++it) {
Chris Masone6791a432011-07-12 13:23:19 -0700404 if (to_forget->UniqueName() == (*it)->UniqueName()) {
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800405 DCHECK(!(*it)->connection());
Chris Masone9be4a9d2011-05-16 15:44:09 -0700406 services_.erase(it);
Paul Stewart22aa71b2011-09-16 12:15:11 -0700407 SortServices();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700408 return;
409 }
410 }
411}
412
mukesh agrawal00917ce2011-11-22 23:56:55 +0000413void Manager::UpdateService(const ServiceRefPtr &to_update) {
414 CHECK(to_update);
Paul Stewart03dba0b2011-08-22 16:32:45 -0700415 LOG(INFO) << "Service " << to_update->UniqueName() << " updated;"
Gaurav Shahc6d6c722011-11-17 18:59:39 -0800416 << " state: " << Service::ConnectStateToString(to_update->state())
417 << " failure: "
418 << Service::ConnectFailureToString(to_update->failure());
mukesh agrawal00917ce2011-11-22 23:56:55 +0000419 LOG(INFO) << "IsConnected(): " << to_update->IsConnected();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800420 if (to_update->IsConnected()) {
mukesh agrawal00917ce2011-11-22 23:56:55 +0000421 to_update->MakeFavorite();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800422 if (to_update->profile().get() == ephemeral_profile_.get()) {
423 if (profiles_.empty()) {
424 LOG(ERROR) << "Cannot assign profile to service: no profiles exist!";
425 } else {
426 MoveServiceToProfile(to_update, profiles_.back());
427 }
428 }
429 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700430 SortServices();
Paul Stewart03dba0b2011-08-22 16:32:45 -0700431}
432
Paul Stewartfdd16072011-09-16 12:41:35 -0700433void Manager::FilterByTechnology(Technology::Identifier tech,
Chris Masonec1e50412011-06-07 13:04:53 -0700434 vector<DeviceRefPtr> *found) {
Chris Masone9be4a9d2011-05-16 15:44:09 -0700435 CHECK(found);
Chris Masonec1e50412011-06-07 13:04:53 -0700436 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700437 for (it = devices_.begin(); it != devices_.end(); ++it) {
438 if ((*it)->TechnologyIs(tech))
439 found->push_back(*it);
440 }
441}
442
Paul Stewart22aa71b2011-09-16 12:15:11 -0700443ServiceRefPtr Manager::FindService(const string& name) {
Chris Masonec1e50412011-06-07 13:04:53 -0700444 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700445 for (it = services_.begin(); it != services_.end(); ++it) {
Chris Masone6791a432011-07-12 13:23:19 -0700446 if (name == (*it)->UniqueName())
Chris Masonee0dea762011-06-09 09:06:03 -0700447 return *it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700448 }
Chris Masonee0dea762011-06-09 09:06:03 -0700449 return NULL;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700450}
451
mukesh agrawalffa3d042011-10-06 15:26:10 -0700452void Manager::HelpRegisterDerivedString(
453 const string &name,
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800454 string(Manager::*get)(Error *),
mukesh agrawalffa3d042011-10-06 15:26:10 -0700455 void(Manager::*set)(const string&, Error *)) {
Chris Masone27c4aa52011-07-02 13:10:14 -0700456 store_.RegisterDerivedString(
457 name,
458 StringAccessor(new CustomAccessor<Manager, string>(this, get, set)));
Chris Masoneb925cc82011-06-22 15:39:57 -0700459}
460
mukesh agrawalffa3d042011-10-06 15:26:10 -0700461void Manager::HelpRegisterDerivedStrings(
462 const string &name,
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800463 Strings(Manager::*get)(Error *),
mukesh agrawalffa3d042011-10-06 15:26:10 -0700464 void(Manager::*set)(const Strings &, Error *)) {
Chris Masone27c4aa52011-07-02 13:10:14 -0700465 store_.RegisterDerivedStrings(
466 name,
467 StringsAccessor(new CustomAccessor<Manager, Strings>(this, get, set)));
Chris Masoneb925cc82011-06-22 15:39:57 -0700468}
469
Paul Stewart22aa71b2011-09-16 12:15:11 -0700470void Manager::SortServices() {
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800471 VLOG(4) << "In " << __func__;
472 ConnectionRefPtr default_connection;
473 if (!services_.empty()) {
474 // Keep track of the connection that was last considered default.
475 default_connection = services_[0]->connection();
476 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700477 sort(services_.begin(), services_.end(), ServiceSorter(technology_order_));
Paul Stewarta41e38d2011-11-11 07:47:29 -0800478
479 vector<string> service_paths;
480 vector<ServiceRefPtr>::iterator it;
481 for (it = services_.begin(); it != services_.end(); ++it) {
482 if ((*it)->IsVisible()) {
483 service_paths.push_back((*it)->GetRpcIdentifier());
484 }
485 }
486 adaptor_->EmitRpcIdentifierArrayChanged(flimflam::kServicesProperty,
487 service_paths);
Gaurav Shah435de2c2011-11-17 19:01:07 -0800488
489 Error error;
490 adaptor_->EmitStringsChanged(flimflam::kConnectedTechnologiesProperty,
491 ConnectedTechnologies(&error));
492 adaptor_->EmitStringChanged(flimflam::kDefaultTechnologyProperty,
493 DefaultTechnology(&error));
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800494
495 if (!services_.empty()) {
496 if (default_connection.get() &&
497 (services_[0]->connection().get() != default_connection.get())) {
498 default_connection->SetIsDefault(false);
499 }
500 if (services_[0]->connection().get()) {
501 services_[0]->connection()->SetIsDefault(true);
502 }
503 }
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800504
505 // Perform auto-connect.
506 for (it = services_.begin(); it != services_.end(); ++it) {
507 if ((*it)->auto_connect() && (*it)->IsAutoConnectable()) {
508 Error error;
509 (*it)->Connect(&error);
510 // We intentionally ignore the error returned by Connect() here since it
511 // should not prevent us from trying to connect a different service.
512 }
513 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700514}
515
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800516string Manager::CalculateState(Error */*error*/) {
Chris Masoneb925cc82011-06-22 15:39:57 -0700517 return flimflam::kStateOffline;
518}
519
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800520vector<string> Manager::AvailableTechnologies(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -0800521 set<string> unique_technologies;
522 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
523 it != devices_.end(); ++it) {
524 unique_technologies.insert(
525 Technology::NameFromIdentifier((*it)->technology()));
526 }
527 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -0700528}
529
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800530vector<string> Manager::ConnectedTechnologies(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -0800531 set<string> unique_technologies;
532 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
533 it != devices_.end(); ++it) {
534 if ((*it)->IsConnected())
535 unique_technologies.insert(
536 Technology::NameFromIdentifier((*it)->technology()));
537 }
538 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -0700539}
540
Gaurav Shah435de2c2011-11-17 19:01:07 -0800541string Manager::DefaultTechnology(Error *error) {
542 return (!services_.empty() && services_[0]->IsConnected()) ?
543 services_[0]->GetTechnologyString(error) : "";
Chris Masoneb925cc82011-06-22 15:39:57 -0700544}
545
Gaurav Shah435de2c2011-11-17 19:01:07 -0800546vector<string> Manager::EnabledTechnologies(Error *error) {
547 // TODO(gauravsh): This must be wired up to the RPC interface to handle
548 // enabled/disabled devices as set by the user. crosbug.com/23319
549 return AvailableTechnologies(error);
Chris Masoneb925cc82011-06-22 15:39:57 -0700550}
551
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800552vector<string> Manager::EnumerateDevices(Error */*error*/) {
Chris Masone3c3f6a12011-07-01 10:01:41 -0700553 vector<string> device_rpc_ids;
554 for (vector<DeviceRefPtr>::const_iterator it = devices_.begin();
555 it != devices_.end();
556 ++it) {
557 device_rpc_ids.push_back((*it)->GetRpcIdentifier());
558 }
559 return device_rpc_ids;
560}
561
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800562vector<string> Manager::EnumerateAvailableServices(Error */*error*/) {
Chris Masone3c3f6a12011-07-01 10:01:41 -0700563 vector<string> service_rpc_ids;
564 for (vector<ServiceRefPtr>::const_iterator it = services_.begin();
565 it != services_.end();
566 ++it) {
567 service_rpc_ids.push_back((*it)->GetRpcIdentifier());
568 }
569 return service_rpc_ids;
570}
571
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800572vector<string> Manager::EnumerateWatchedServices(Error *error) {
Chris Masone6791a432011-07-12 13:23:19 -0700573 // TODO(cmasone): Filter this list for services in appropriate states.
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800574 return EnumerateAvailableServices(error);
Chris Masone3c3f6a12011-07-01 10:01:41 -0700575}
576
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800577string Manager::GetActiveProfileName(Error */*error*/) {
Chris Masone7df0c672011-07-15 10:24:54 -0700578 return ActiveProfile()->GetFriendlyName();
Chris Masone7aa5f902011-07-11 11:13:35 -0700579}
580
mukesh agrawal32399322011-09-01 10:53:43 -0700581// called via RPC (e.g., from ManagerDBusAdaptor)
mukesh agrawal7a4e4002011-09-06 11:26:05 -0700582WiFiServiceRefPtr Manager::GetWifiService(const KeyValueStore &args,
583 Error *error) {
Paul Stewarta41e38d2011-11-11 07:47:29 -0800584 vector<DeviceRefPtr> wifi_devices;
Paul Stewart22aa71b2011-09-16 12:15:11 -0700585 FilterByTechnology(Technology::kWifi, &wifi_devices);
mukesh agrawal7a4e4002011-09-06 11:26:05 -0700586 if (wifi_devices.empty()) {
587 error->Populate(Error::kInvalidArguments, kManagerErrorNoDevice);
588 return NULL;
589 } else {
590 WiFi *wifi = dynamic_cast<WiFi *>(wifi_devices.front().get());
591 CHECK(wifi);
592 return wifi->GetService(args, error);
593 }
594}
595
596// called via RPC (e.g., from ManagerDBusAdaptor)
Paul Stewart22aa71b2011-09-16 12:15:11 -0700597void Manager::RequestScan(const string &technology, Error *error) {
mukesh agrawal32399322011-09-01 10:53:43 -0700598 if (technology == flimflam::kTypeWifi || technology == "") {
599 vector<DeviceRefPtr> wifi_devices;
Paul Stewartfdd16072011-09-16 12:41:35 -0700600 FilterByTechnology(Technology::kWifi, &wifi_devices);
mukesh agrawal32399322011-09-01 10:53:43 -0700601
602 for (vector<DeviceRefPtr>::iterator it = wifi_devices.begin();
603 it != wifi_devices.end();
604 ++it) {
Darin Petkovc0865312011-09-16 15:31:20 -0700605 (*it)->Scan(error);
mukesh agrawal32399322011-09-01 10:53:43 -0700606 }
607 } else {
608 // TODO(quiche): support scanning for other technologies?
Paul Stewartbe005172011-11-02 18:10:29 -0700609 Error::PopulateAndLog(error, Error::kInvalidArguments,
610 "Unrecognized technology " + technology);
mukesh agrawal32399322011-09-01 10:53:43 -0700611 }
612}
613
Paul Stewart22aa71b2011-09-16 12:15:11 -0700614string Manager::GetTechnologyOrder() {
615 vector<string> technology_names;
616 for (vector<Technology::Identifier>::iterator it = technology_order_.begin();
617 it != technology_order_.end();
618 ++it) {
619 technology_names.push_back(Technology::NameFromIdentifier(*it));
620 }
621
622 return JoinString(technology_names, ',');
623}
624
625void Manager::SetTechnologyOrder(const string &order, Error *error) {
626 vector<Technology::Identifier> new_order;
627 map<Technology::Identifier, bool> seen;
628
629 vector<string> order_parts;
630 base::SplitString(order, ',', &order_parts);
631
632 for (vector<string>::iterator it = order_parts.begin();
633 it != order_parts.end();
634 ++it) {
635 Technology::Identifier identifier = Technology::IdentifierFromName(*it);
636
637 if (identifier == Technology::kUnknown) {
Paul Stewartbe005172011-11-02 18:10:29 -0700638 Error::PopulateAndLog(error, Error::kInvalidArguments,
639 *it + " is an unknown technology name");
Paul Stewart22aa71b2011-09-16 12:15:11 -0700640 return;
641 }
642
643 if (ContainsKey(seen, identifier)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700644 Error::PopulateAndLog(error, Error::kInvalidArguments,
645 *it + " is duplicated in the list");
Paul Stewart22aa71b2011-09-16 12:15:11 -0700646 return;
647 }
648 seen[identifier] = true;
649 new_order.push_back(identifier);
650 }
651
652 technology_order_ = new_order;
653 SortServices();
654}
655
Paul Stewart75897df2011-04-27 09:05:53 -0700656} // namespace shill