blob: f3f33e84b1c818e90a843964c8fb63e354453e18 [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();
Paul Stewart870523b2012-01-11 17:00:42 -0800154 scoped_refptr<DefaultProfile>
155 default_profile(new DefaultProfile(control_interface_,
Gaurav Shah71354762011-11-28 19:22:49 -0800156 this,
157 storage_path_,
158 props_));
Paul Stewart870523b2012-01-11 17:00:42 -0800159 CHECK(default_profile->InitStorage(glib_, Profile::kCreateOrOpenExisting,
160 NULL));
161 CHECK(default_profile->LoadManagerProperties(&props_));
162 profiles_.push_back(default_profile.release());
Gaurav Shah71354762011-11-28 19:22:49 -0800163 Error error;
Paul Stewart19c871d2011-12-15 16:10:13 -0800164 string path;
Gaurav Shah71354762011-11-28 19:22:49 -0800165 for (vector<string>::iterator it = startup_profiles_.begin();
166 it != startup_profiles_.end(); ++it)
Paul Stewart19c871d2011-12-15 16:10:13 -0800167 PushProfile(*it, &path, &error);
Gaurav Shah71354762011-11-28 19:22:49 -0800168}
169
Paul Stewart19c871d2011-12-15 16:10:13 -0800170void Manager::CreateProfile(const string &name, string *path, Error *error) {
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700171 Profile::Identifier ident;
172 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700173 Error::PopulateAndLog(error, Error::kInvalidArguments,
174 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700175 return;
176 }
177 ProfileRefPtr profile(new Profile(control_interface_,
178 this,
179 ident,
180 user_storage_format_,
Paul Stewart19c871d2011-12-15 16:10:13 -0800181 connect_profiles_to_rpc_));
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700182 if (!profile->InitStorage(glib_, Profile::kCreateNew, error)) {
Paul Stewart19c871d2011-12-15 16:10:13 -0800183 // |error| will have been populated by InitStorage().
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700184 return;
185 }
186
187 // Save profile data out, and then let the scoped pointer fall out of scope.
188 if (!profile->Save()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700189 Error::PopulateAndLog(error, Error::kInternalError,
190 "Profile name " + name + " could not be saved");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700191 return;
192 }
Paul Stewart19c871d2011-12-15 16:10:13 -0800193
194 *path = profile->GetRpcIdentifier();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700195}
196
Paul Stewart19c871d2011-12-15 16:10:13 -0800197void Manager::PushProfile(const string &name, string *path, Error *error) {
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700198 Profile::Identifier ident;
199 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700200 Error::PopulateAndLog(error, Error::kInvalidArguments,
201 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700202 return;
203 }
204
205 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
206 it != profiles_.end();
207 ++it) {
208 if ((*it)->MatchesIdentifier(ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700209 Error::PopulateAndLog(error, Error::kAlreadyExists,
210 "Profile name " + name + " is already on stack");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700211 return;
212 }
213 }
214
215 if (ident.user.empty()) {
216 // The manager will have only one machine-wide profile, and this is the
217 // DefaultProfile. This means no other profiles can be loaded that do
218 // not have a user component.
219 // TODO(pstew): This is all well and good, but WiFi autotests try to
220 // creating a default profile (by a name other than "default") in order
221 // to avoid leaving permanent side effects to devices under test. This
222 // whole thing will need to be reworked in order to allow that to happen,
223 // or the autotests (or their expectations) will need to change.
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000224 // crosbug.com/24461
Paul Stewartbe005172011-11-02 18:10:29 -0700225 Error::PopulateAndLog(error, Error::kInvalidArguments,
226 "Cannot load non-default global profile " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700227 return;
228 }
229
230 ProfileRefPtr profile(new Profile(control_interface_,
231 this,
232 ident,
233 user_storage_format_,
234 connect_profiles_to_rpc_));
235 if (!profile->InitStorage(glib_, Profile::kOpenExisting, error)) {
Paul Stewart19c871d2011-12-15 16:10:13 -0800236 // |error| will have been populated by InitStorage().
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700237 return;
238 }
239
Paul Stewarta849a3d2011-11-03 05:54:09 -0700240 profiles_.push_back(profile);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700241
242 // Offer each registered Service the opportunity to join this new Profile.
Paul Stewarta41e38d2011-11-11 07:47:29 -0800243 for (vector<ServiceRefPtr>::iterator it = services_.begin();
244 it != services_.end(); ++it) {
Paul Stewartbba6a5b2011-11-02 18:45:59 -0700245 profile->ConfigureService(*it);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700246 }
247
Paul Stewarta41e38d2011-11-11 07:47:29 -0800248 // Shop the Profile contents around to Devices which can create
249 // non-visible services.
250 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
251 it != devices_.end(); ++it) {
252 profile->ConfigureDevice(*it);
253 }
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800254
Paul Stewart19c871d2011-12-15 16:10:13 -0800255 *path = profile->GetRpcIdentifier();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800256 SortServices();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700257}
258
259void Manager::PopProfileInternal() {
260 CHECK(!profiles_.empty());
261 ProfileRefPtr active_profile = profiles_.back();
262 profiles_.pop_back();
263 vector<ServiceRefPtr>::iterator s_it;
264 for (s_it = services_.begin(); s_it != services_.end(); ++s_it) {
265 if ((*s_it)->profile().get() == active_profile.get()) {
266 vector<ProfileRefPtr>::reverse_iterator p_it;
267 for (p_it = profiles_.rbegin(); p_it != profiles_.rend(); ++p_it) {
Paul Stewartbba6a5b2011-11-02 18:45:59 -0700268 if ((*p_it)->ConfigureService(*s_it)) {
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700269 break;
270 }
271 }
272 if (p_it == profiles_.rend()) {
273 ephemeral_profile_->AdoptService(*s_it);
Paul Stewarta41e38d2011-11-11 07:47:29 -0800274 (*s_it)->Unload();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700275 }
276 }
277 }
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800278 SortServices();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700279}
280
Paul Stewarta41e38d2011-11-11 07:47:29 -0800281void Manager::PopProfile(const string &name, Error *error) {
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700282 Profile::Identifier ident;
283 if (profiles_.empty()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700284 Error::PopulateAndLog(error, Error::kNotFound, "Profile stack is empty");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700285 return;
286 }
287 ProfileRefPtr active_profile = profiles_.back();
288 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700289 Error::PopulateAndLog(error, Error::kInvalidArguments,
290 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700291 return;
292 }
293 if (!active_profile->MatchesIdentifier(ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700294 Error::PopulateAndLog(error, Error::kNotSupported,
295 name + " is not the active profile");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700296 return;
297 }
298 PopProfileInternal();
299}
300
301void Manager::PopAnyProfile(Error *error) {
302 Profile::Identifier ident;
303 if (profiles_.empty()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700304 Error::PopulateAndLog(error, Error::kNotFound, "Profile stack is empty");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700305 return;
306 }
307 PopProfileInternal();
308}
309
Chris Masone7aa5f902011-07-11 11:13:35 -0700310const ProfileRefPtr &Manager::ActiveProfile() {
Chris Masoneb9c00592011-10-06 13:10:39 -0700311 DCHECK_NE(profiles_.size(), 0);
Chris Masone7aa5f902011-07-11 11:13:35 -0700312 return profiles_.back();
313}
314
Chris Masone6515aab2011-10-12 16:19:09 -0700315bool Manager::MoveServiceToProfile(const ServiceRefPtr &to_move,
316 const ProfileRefPtr &destination) {
317 const ProfileRefPtr from = to_move->profile();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800318 VLOG(2) << "Moving service "
319 << to_move->UniqueName()
320 << " to profile "
321 << destination->GetFriendlyName()
322 << " from "
323 << from->GetFriendlyName();
Chris Masone6515aab2011-10-12 16:19:09 -0700324 return destination->AdoptService(to_move) &&
325 from->AbandonService(to_move);
Chris Masone6791a432011-07-12 13:23:19 -0700326}
327
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800328void Manager::SetProfileForService(const ServiceRefPtr &to_set,
329 const string &profile_rpcid,
330 Error *error) {
331 for (vector<ProfileRefPtr>::iterator it = profiles_.begin();
332 it != profiles_.end();
333 ++it) {
334 if (profile_rpcid == (*it)->GetRpcIdentifier()) {
335 if (to_set->profile().get() == it->get()) {
336 Error::PopulateAndLog(error, Error::kInvalidArguments,
337 "Service is already connected to this profile");
338 } else if (!MoveServiceToProfile(to_set, *it)) {
339 Error::PopulateAndLog(error, Error::kInternalError,
340 "Unable to move service to profile");
341 }
342 return;
343 }
344 }
345 Error::PopulateAndLog(error, Error::kInvalidArguments,
346 "Unknown Profile requested for Service");
347}
348
Chris Masone2b105542011-06-22 10:58:09 -0700349void Manager::RegisterDevice(const DeviceRefPtr &to_manage) {
Chris Masonec1e50412011-06-07 13:04:53 -0700350 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700351 for (it = devices_.begin(); it != devices_.end(); ++it) {
Chris Masonec1e50412011-06-07 13:04:53 -0700352 if (to_manage.get() == it->get())
Chris Masone9be4a9d2011-05-16 15:44:09 -0700353 return;
354 }
Chris Masonec1e50412011-06-07 13:04:53 -0700355 devices_.push_back(to_manage);
Paul Stewartf1ce5d22011-05-19 13:10:20 -0700356
Paul Stewarta41e38d2011-11-11 07:47:29 -0800357 // We are applying device properties from the DefaultProfile, and adding
358 // the union of hidden services in all loaded profiles to the device.
Chris Masone6515aab2011-10-12 16:19:09 -0700359 for (vector<ProfileRefPtr>::iterator it = profiles_.begin();
360 it != profiles_.end();
361 ++it) {
Paul Stewarta41e38d2011-11-11 07:47:29 -0800362 // Load device configuration, if any exists, as well as hidden services.
363 (*it)->ConfigureDevice(to_manage);
364
365 // Currently the only profile for which "Save" is implemented is the
366 // DefaultProfile. It iterates over all Devices and stores their state.
367 // We perform the Save now in case the device we have just registered
368 // is new and needs to be added to the stored DefaultProfile.
Chris Masone6515aab2011-10-12 16:19:09 -0700369 (*it)->Save();
370 }
Paul Stewarta41e38d2011-11-11 07:47:29 -0800371
372 // In normal usage, running_ will always be true when we are here, however
373 // unit tests sometimes do things in otherwise invalid states.
374 if (running_ && to_manage->powered())
375 to_manage->Start();
Gaurav Shah435de2c2011-11-17 19:01:07 -0800376
377 Error error;
378 adaptor_->EmitStringsChanged(flimflam::kAvailableTechnologiesProperty,
379 AvailableTechnologies(&error));
380 adaptor_->EmitStringsChanged(flimflam::kEnabledTechnologiesProperty,
381 EnabledTechnologies(&error));
Chris Masone9be4a9d2011-05-16 15:44:09 -0700382}
383
mukesh agrawal5029c6c2011-08-25 11:12:40 -0700384void Manager::DeregisterDevice(const DeviceRefPtr &to_forget) {
Chris Masonec1e50412011-06-07 13:04:53 -0700385 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700386 for (it = devices_.begin(); it != devices_.end(); ++it) {
Chris Masonec1e50412011-06-07 13:04:53 -0700387 if (to_forget.get() == it->get()) {
mukesh agrawal5029c6c2011-08-25 11:12:40 -0700388 VLOG(2) << "Deregistered device: " << to_forget->UniqueName();
389 to_forget->Stop();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700390 devices_.erase(it);
Gaurav Shah435de2c2011-11-17 19:01:07 -0800391 Error error;
392 adaptor_->EmitStringsChanged(flimflam::kAvailableTechnologiesProperty,
393 AvailableTechnologies(&error));
394 adaptor_->EmitStringsChanged(flimflam::kEnabledTechnologiesProperty,
395 EnabledTechnologies(&error));
Chris Masone9be4a9d2011-05-16 15:44:09 -0700396 return;
397 }
398 }
mukesh agrawal5029c6c2011-08-25 11:12:40 -0700399 VLOG(2) << __func__ << " unknown device: " << to_forget->UniqueName();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700400}
401
mukesh agrawal4eb4d782011-12-05 17:34:37 +0000402bool Manager::HasService(const ServiceRefPtr &service) {
403 vector<ServiceRefPtr>::iterator it;
404 for (it = services_.begin(); it != services_.end(); ++it) {
405 if ((*it)->UniqueName() == service->UniqueName())
406 return true;
407 }
408 return false;
409}
410
Chris Masone2b105542011-06-22 10:58:09 -0700411void Manager::RegisterService(const ServiceRefPtr &to_manage) {
Gaurav Shahc6d6c722011-11-17 18:59:39 -0800412 VLOG(2) << "In " << __func__ << "(): Registering service "
413 << to_manage->UniqueName();
mukesh agrawald835b202011-10-07 15:26:47 -0700414
Paul Stewartbba6a5b2011-11-02 18:45:59 -0700415 bool configured = false;
Paul Stewarta41e38d2011-11-11 07:47:29 -0800416 for (vector<ProfileRefPtr>::reverse_iterator it = profiles_.rbegin();
417 !configured && it != profiles_.rend();
Chris Masone157aa0c2011-10-03 09:24:31 -0700418 ++it) {
Paul Stewartbba6a5b2011-11-02 18:45:59 -0700419 configured = (*it)->ConfigureService(to_manage);
Chris Masone157aa0c2011-10-03 09:24:31 -0700420 }
Chris Masone6791a432011-07-12 13:23:19 -0700421
422 // If not found, add it to the ephemeral profile
Paul Stewartbba6a5b2011-11-02 18:45:59 -0700423 if (!configured)
Chris Masone6515aab2011-10-12 16:19:09 -0700424 ephemeral_profile_->AdoptService(to_manage);
Chris Masone6791a432011-07-12 13:23:19 -0700425
426 // Now add to OUR list.
Chris Masonec1e50412011-06-07 13:04:53 -0700427 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700428 for (it = services_.begin(); it != services_.end(); ++it) {
mukesh agrawald835b202011-10-07 15:26:47 -0700429 CHECK(to_manage->UniqueName() != (*it)->UniqueName());
Chris Masone9be4a9d2011-05-16 15:44:09 -0700430 }
Chris Masonec1e50412011-06-07 13:04:53 -0700431 services_.push_back(to_manage);
Paul Stewart22aa71b2011-09-16 12:15:11 -0700432 SortServices();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700433}
434
Chris Masone6515aab2011-10-12 16:19:09 -0700435void Manager::DeregisterService(const ServiceRefPtr &to_forget) {
Chris Masonec1e50412011-06-07 13:04:53 -0700436 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700437 for (it = services_.begin(); it != services_.end(); ++it) {
Chris Masone6791a432011-07-12 13:23:19 -0700438 if (to_forget->UniqueName() == (*it)->UniqueName()) {
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800439 DCHECK(!(*it)->connection());
Chris Masone9be4a9d2011-05-16 15:44:09 -0700440 services_.erase(it);
Paul Stewart22aa71b2011-09-16 12:15:11 -0700441 SortServices();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700442 return;
443 }
444 }
445}
446
mukesh agrawal00917ce2011-11-22 23:56:55 +0000447void Manager::UpdateService(const ServiceRefPtr &to_update) {
448 CHECK(to_update);
Paul Stewart03dba0b2011-08-22 16:32:45 -0700449 LOG(INFO) << "Service " << to_update->UniqueName() << " updated;"
Gaurav Shahc6d6c722011-11-17 18:59:39 -0800450 << " state: " << Service::ConnectStateToString(to_update->state())
451 << " failure: "
452 << Service::ConnectFailureToString(to_update->failure());
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000453 VLOG(2) << "IsConnected(): " << to_update->IsConnected();
454 VLOG(2) << "IsConnecting(): " << to_update->IsConnecting();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800455 if (to_update->IsConnected()) {
mukesh agrawal00917ce2011-11-22 23:56:55 +0000456 to_update->MakeFavorite();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800457 if (to_update->profile().get() == ephemeral_profile_.get()) {
458 if (profiles_.empty()) {
459 LOG(ERROR) << "Cannot assign profile to service: no profiles exist!";
460 } else {
461 MoveServiceToProfile(to_update, profiles_.back());
462 }
463 }
464 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700465 SortServices();
Paul Stewart03dba0b2011-08-22 16:32:45 -0700466}
467
Paul Stewartfdd16072011-09-16 12:41:35 -0700468void Manager::FilterByTechnology(Technology::Identifier tech,
Chris Masonec1e50412011-06-07 13:04:53 -0700469 vector<DeviceRefPtr> *found) {
Chris Masone9be4a9d2011-05-16 15:44:09 -0700470 CHECK(found);
Chris Masonec1e50412011-06-07 13:04:53 -0700471 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700472 for (it = devices_.begin(); it != devices_.end(); ++it) {
473 if ((*it)->TechnologyIs(tech))
474 found->push_back(*it);
475 }
476}
477
Paul Stewart22aa71b2011-09-16 12:15:11 -0700478ServiceRefPtr Manager::FindService(const string& name) {
Chris Masonec1e50412011-06-07 13:04:53 -0700479 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700480 for (it = services_.begin(); it != services_.end(); ++it) {
Chris Masone6791a432011-07-12 13:23:19 -0700481 if (name == (*it)->UniqueName())
Chris Masonee0dea762011-06-09 09:06:03 -0700482 return *it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700483 }
Chris Masonee0dea762011-06-09 09:06:03 -0700484 return NULL;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700485}
486
mukesh agrawalffa3d042011-10-06 15:26:10 -0700487void Manager::HelpRegisterDerivedString(
488 const string &name,
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800489 string(Manager::*get)(Error *),
mukesh agrawalffa3d042011-10-06 15:26:10 -0700490 void(Manager::*set)(const string&, Error *)) {
Chris Masone27c4aa52011-07-02 13:10:14 -0700491 store_.RegisterDerivedString(
492 name,
493 StringAccessor(new CustomAccessor<Manager, string>(this, get, set)));
Chris Masoneb925cc82011-06-22 15:39:57 -0700494}
495
mukesh agrawalffa3d042011-10-06 15:26:10 -0700496void Manager::HelpRegisterDerivedStrings(
497 const string &name,
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800498 Strings(Manager::*get)(Error *),
mukesh agrawalffa3d042011-10-06 15:26:10 -0700499 void(Manager::*set)(const Strings &, Error *)) {
Chris Masone27c4aa52011-07-02 13:10:14 -0700500 store_.RegisterDerivedStrings(
501 name,
502 StringsAccessor(new CustomAccessor<Manager, Strings>(this, get, set)));
Chris Masoneb925cc82011-06-22 15:39:57 -0700503}
504
Paul Stewart22aa71b2011-09-16 12:15:11 -0700505void Manager::SortServices() {
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800506 VLOG(4) << "In " << __func__;
507 ConnectionRefPtr default_connection;
508 if (!services_.empty()) {
509 // Keep track of the connection that was last considered default.
510 default_connection = services_[0]->connection();
511 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700512 sort(services_.begin(), services_.end(), ServiceSorter(technology_order_));
Paul Stewarta41e38d2011-11-11 07:47:29 -0800513
514 vector<string> service_paths;
515 vector<ServiceRefPtr>::iterator it;
516 for (it = services_.begin(); it != services_.end(); ++it) {
517 if ((*it)->IsVisible()) {
518 service_paths.push_back((*it)->GetRpcIdentifier());
519 }
520 }
521 adaptor_->EmitRpcIdentifierArrayChanged(flimflam::kServicesProperty,
522 service_paths);
Gaurav Shah435de2c2011-11-17 19:01:07 -0800523
524 Error error;
525 adaptor_->EmitStringsChanged(flimflam::kConnectedTechnologiesProperty,
526 ConnectedTechnologies(&error));
527 adaptor_->EmitStringChanged(flimflam::kDefaultTechnologyProperty,
528 DefaultTechnology(&error));
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800529
530 if (!services_.empty()) {
531 if (default_connection.get() &&
532 (services_[0]->connection().get() != default_connection.get())) {
533 default_connection->SetIsDefault(false);
534 }
535 if (services_[0]->connection().get()) {
536 services_[0]->connection()->SetIsDefault(true);
537 }
538 }
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800539
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000540 AutoConnect();
541}
542
543void Manager::AutoConnect() {
544 // We might be called in the middle of another request (e.g., as a
545 // consequence of Service::SetState calling UpdateService). To avoid
546 // re-entrancy issues in dbus-c++, defer to the event loop.
547 dispatcher_->PostTask(
548 task_factory_.NewRunnableMethod(&Manager::AutoConnectTask));
549 return;
550}
551
552void Manager::AutoConnectTask() {
553 if (services_.empty()) {
554 LOG(INFO) << "No services.";
555 return;
556 }
557
558 if (VLOG_IS_ON(4)) {
559 for (vector<ServiceRefPtr>::const_iterator it = services_.begin();
560 it != services_.end(); ++it) {
561 VLOG(4) << "Sorted service list: ";
562 VLOG(4) << "Service " << (*it)->friendly_name()
563 << " IsConnected: " << (*it)->IsConnected()
564 << " IsConnecting: " << (*it)->IsConnecting()
565 << " IsFailed: " << (*it)->IsFailed()
566 << " connectable: " << (*it)->connectable()
567 << " auto_connect: " << (*it)->auto_connect()
568 << " favorite: " << (*it)->favorite()
569 << " priority: " << (*it)->priority()
570 << " security_level: " << (*it)->security_level()
571 << " strength: " << (*it)->strength()
572 << " UniqueName: " << (*it)->UniqueName();
573 }
574 }
575
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800576 // Perform auto-connect.
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000577 for (vector<ServiceRefPtr>::iterator it = services_.begin();
578 it != services_.end(); ++it) {
579 if ((*it)->auto_connect()) {
580 LOG(INFO) << "Initiating connect to " << (*it)->friendly_name() << ".";
581 (*it)->AutoConnect();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800582 }
583 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700584}
585
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800586string Manager::CalculateState(Error */*error*/) {
Chris Masoneb925cc82011-06-22 15:39:57 -0700587 return flimflam::kStateOffline;
588}
589
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800590vector<string> Manager::AvailableTechnologies(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -0800591 set<string> unique_technologies;
592 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
593 it != devices_.end(); ++it) {
594 unique_technologies.insert(
595 Technology::NameFromIdentifier((*it)->technology()));
596 }
597 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -0700598}
599
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800600vector<string> Manager::ConnectedTechnologies(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -0800601 set<string> unique_technologies;
602 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
603 it != devices_.end(); ++it) {
604 if ((*it)->IsConnected())
605 unique_technologies.insert(
606 Technology::NameFromIdentifier((*it)->technology()));
607 }
608 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -0700609}
610
Gaurav Shah435de2c2011-11-17 19:01:07 -0800611string Manager::DefaultTechnology(Error *error) {
612 return (!services_.empty() && services_[0]->IsConnected()) ?
613 services_[0]->GetTechnologyString(error) : "";
Chris Masoneb925cc82011-06-22 15:39:57 -0700614}
615
Gaurav Shah435de2c2011-11-17 19:01:07 -0800616vector<string> Manager::EnabledTechnologies(Error *error) {
617 // TODO(gauravsh): This must be wired up to the RPC interface to handle
618 // enabled/disabled devices as set by the user. crosbug.com/23319
619 return AvailableTechnologies(error);
Chris Masoneb925cc82011-06-22 15:39:57 -0700620}
621
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800622vector<string> Manager::EnumerateDevices(Error */*error*/) {
Chris Masone3c3f6a12011-07-01 10:01:41 -0700623 vector<string> device_rpc_ids;
624 for (vector<DeviceRefPtr>::const_iterator it = devices_.begin();
625 it != devices_.end();
626 ++it) {
627 device_rpc_ids.push_back((*it)->GetRpcIdentifier());
628 }
629 return device_rpc_ids;
630}
631
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800632vector<string> Manager::EnumerateAvailableServices(Error */*error*/) {
Chris Masone3c3f6a12011-07-01 10:01:41 -0700633 vector<string> service_rpc_ids;
634 for (vector<ServiceRefPtr>::const_iterator it = services_.begin();
635 it != services_.end();
636 ++it) {
637 service_rpc_ids.push_back((*it)->GetRpcIdentifier());
638 }
639 return service_rpc_ids;
640}
641
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800642vector<string> Manager::EnumerateWatchedServices(Error *error) {
Chris Masone6791a432011-07-12 13:23:19 -0700643 // TODO(cmasone): Filter this list for services in appropriate states.
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800644 return EnumerateAvailableServices(error);
Chris Masone3c3f6a12011-07-01 10:01:41 -0700645}
646
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800647string Manager::GetActiveProfileName(Error */*error*/) {
Chris Masone7df0c672011-07-15 10:24:54 -0700648 return ActiveProfile()->GetFriendlyName();
Chris Masone7aa5f902011-07-11 11:13:35 -0700649}
650
mukesh agrawal32399322011-09-01 10:53:43 -0700651// called via RPC (e.g., from ManagerDBusAdaptor)
mukesh agrawal7a4e4002011-09-06 11:26:05 -0700652WiFiServiceRefPtr Manager::GetWifiService(const KeyValueStore &args,
653 Error *error) {
Paul Stewarta41e38d2011-11-11 07:47:29 -0800654 vector<DeviceRefPtr> wifi_devices;
Paul Stewart22aa71b2011-09-16 12:15:11 -0700655 FilterByTechnology(Technology::kWifi, &wifi_devices);
mukesh agrawal7a4e4002011-09-06 11:26:05 -0700656 if (wifi_devices.empty()) {
657 error->Populate(Error::kInvalidArguments, kManagerErrorNoDevice);
658 return NULL;
659 } else {
660 WiFi *wifi = dynamic_cast<WiFi *>(wifi_devices.front().get());
661 CHECK(wifi);
662 return wifi->GetService(args, error);
663 }
664}
665
666// called via RPC (e.g., from ManagerDBusAdaptor)
Paul Stewart22aa71b2011-09-16 12:15:11 -0700667void Manager::RequestScan(const string &technology, Error *error) {
mukesh agrawal32399322011-09-01 10:53:43 -0700668 if (technology == flimflam::kTypeWifi || technology == "") {
669 vector<DeviceRefPtr> wifi_devices;
Paul Stewartfdd16072011-09-16 12:41:35 -0700670 FilterByTechnology(Technology::kWifi, &wifi_devices);
mukesh agrawal32399322011-09-01 10:53:43 -0700671
672 for (vector<DeviceRefPtr>::iterator it = wifi_devices.begin();
673 it != wifi_devices.end();
674 ++it) {
Darin Petkovc0865312011-09-16 15:31:20 -0700675 (*it)->Scan(error);
mukesh agrawal32399322011-09-01 10:53:43 -0700676 }
677 } else {
678 // TODO(quiche): support scanning for other technologies?
Paul Stewartbe005172011-11-02 18:10:29 -0700679 Error::PopulateAndLog(error, Error::kInvalidArguments,
680 "Unrecognized technology " + technology);
mukesh agrawal32399322011-09-01 10:53:43 -0700681 }
682}
683
Paul Stewart22aa71b2011-09-16 12:15:11 -0700684string Manager::GetTechnologyOrder() {
685 vector<string> technology_names;
686 for (vector<Technology::Identifier>::iterator it = technology_order_.begin();
687 it != technology_order_.end();
688 ++it) {
689 technology_names.push_back(Technology::NameFromIdentifier(*it));
690 }
691
692 return JoinString(technology_names, ',');
693}
694
695void Manager::SetTechnologyOrder(const string &order, Error *error) {
696 vector<Technology::Identifier> new_order;
697 map<Technology::Identifier, bool> seen;
698
699 vector<string> order_parts;
700 base::SplitString(order, ',', &order_parts);
701
702 for (vector<string>::iterator it = order_parts.begin();
703 it != order_parts.end();
704 ++it) {
705 Technology::Identifier identifier = Technology::IdentifierFromName(*it);
706
707 if (identifier == Technology::kUnknown) {
Paul Stewartbe005172011-11-02 18:10:29 -0700708 Error::PopulateAndLog(error, Error::kInvalidArguments,
709 *it + " is an unknown technology name");
Paul Stewart22aa71b2011-09-16 12:15:11 -0700710 return;
711 }
712
713 if (ContainsKey(seen, identifier)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700714 Error::PopulateAndLog(error, Error::kInvalidArguments,
715 *it + " is duplicated in the list");
Paul Stewart22aa71b2011-09-16 12:15:11 -0700716 return;
717 }
718 seen[identifier] = true;
719 new_order.push_back(identifier);
720 }
721
722 technology_order_ = new_order;
723 SortServices();
724}
725
Paul Stewart75897df2011-04-27 09:05:53 -0700726} // namespace shill