blob: 959119dc0d462fcfcbc1530b19ef60d90c969a30 [file] [log] [blame]
// Copyright 2014 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "apmanager/manager.h"
#include <base/bind.h>
#include <chromeos/dbus/service_constants.h>
using chromeos::dbus_utils::AsyncEventSequencer;
using chromeos::dbus_utils::ExportedObjectManager;
using chromeos::dbus_utils::DBusMethodResponse;
using std::string;
namespace apmanager {
Manager::Manager()
: org::chromium::apmanager::ManagerAdaptor(this),
service_identifier_(0),
device_identifier_(0),
device_info_(this) {}
Manager::~Manager() {
// Terminate all services before cleanup other resources.
for (auto& service : services_) {
service.reset();
}
}
void Manager::RegisterAsync(ExportedObjectManager* object_manager,
const scoped_refptr<dbus::Bus>& bus,
AsyncEventSequencer* sequencer) {
CHECK(!dbus_object_) << "Already registered";
dbus_object_.reset(
new chromeos::dbus_utils::DBusObject(
object_manager,
bus,
org::chromium::apmanager::ManagerAdaptor::GetObjectPath()));
RegisterWithDBusObject(dbus_object_.get());
dbus_object_->RegisterAsync(
sequencer->GetHandler("Manager.RegisterAsync() failed.", true));
bus_ = bus;
shill_proxy_.Init(bus);
firewall_manager_.Init(bus);
}
void Manager::Start() {
device_info_.Start();
}
void Manager::Stop() {
device_info_.Stop();
}
void Manager::CreateService(
std::unique_ptr<DBusMethodResponse<dbus::ObjectPath>> response,
dbus::Message* message) {
LOG(INFO) << "Manager::CreateService";
scoped_refptr<AsyncEventSequencer> sequencer(new AsyncEventSequencer());
std::unique_ptr<Service> service(new Service(this, service_identifier_));
service->RegisterAsync(
dbus_object_->GetObjectManager().get(), bus_, sequencer.get());
sequencer->OnAllTasksCompletedCall({
base::Bind(&Manager::OnServiceRegistered,
base::Unretained(this),
base::Passed(&response),
base::Passed(&service))
});
base::Closure on_connection_vanish = base::Bind(
&Manager::OnAPServiceOwnerDisappeared,
base::Unretained(this),
service_identifier_);
service_watchers_[service_identifier_].reset(
new DBusServiceWatcher{bus_, message->GetSender(), on_connection_vanish});
service_identifier_++;
}
bool Manager::RemoveService(chromeos::ErrorPtr* error,
dbus::Message* message,
const dbus::ObjectPath& in_service) {
for (auto it = services_.begin(); it != services_.end(); ++it) {
if ((*it)->dbus_path() == in_service) {
// Verify the owner.
auto watcher = service_watchers_.find((*it)->identifier());
CHECK(watcher != service_watchers_.end())
<< "DBus watcher not created for service: " << (*it)->identifier();
if (watcher->second->connection_name() != message->GetSender()) {
chromeos::Error::AddToPrintf(
error, FROM_HERE, chromeos::errors::dbus::kDomain, kManagerError,
"Service %d is owned by another local process.",
(*it)->identifier());
return false;
}
service_watchers_.erase(watcher);
services_.erase(it);
return true;
}
}
chromeos::Error::AddTo(
error, FROM_HERE, chromeos::errors::dbus::kDomain, kManagerError,
"Service does not exist");
return false;
}
scoped_refptr<Device> Manager::GetAvailableDevice() {
for (const auto& device : devices_) {
// Look for an unused device with AP interface mode support.
if (!device->GetInUsed() && !device->GetPreferredApInterface().empty()) {
return device;
}
}
return nullptr;
}
scoped_refptr<Device> Manager::GetDeviceFromInterfaceName(
const string& interface_name) {
for (const auto& device : devices_) {
if (device->InterfaceExists(interface_name)) {
return device;
}
}
return nullptr;
}
void Manager::RegisterDevice(scoped_refptr<Device> device) {
LOG(INFO) << "Manager::RegisterDevice: registering device "
<< device->GetDeviceName();
// Register device DBbus interfaces.
scoped_refptr<AsyncEventSequencer> sequencer(new AsyncEventSequencer());
device->RegisterAsync(dbus_object_->GetObjectManager().get(),
bus_,
sequencer.get(),
device_identifier_++);
sequencer->OnAllTasksCompletedCall({
base::Bind(&Manager::OnDeviceRegistered,
base::Unretained(this),
device)
});
}
void Manager::ClaimInterface(const string& interface_name) {
shill_proxy_.ClaimInterface(interface_name);
}
void Manager::ReleaseInterface(const string& interface_name) {
shill_proxy_.ReleaseInterface(interface_name);
}
void Manager::RequestDHCPPortAccess(const string& interface) {
firewall_manager_.RequestDHCPPortAccess(interface);
}
void Manager::ReleaseDHCPPortAccess(const string& interface) {
firewall_manager_.ReleaseDHCPPortAccess(interface);
}
void Manager::OnServiceRegistered(
std::unique_ptr<DBusMethodResponse<dbus::ObjectPath>> response,
std::unique_ptr<Service> service,
bool success) {
LOG(INFO) << "ServiceRegistered";
// Success should always be true since we've said that failures are fatal.
CHECK(success) << "Init of one or more objects has failed.";
// Remove this service if the owner doesn't exist anymore. It is theoretically
// possible to have the owner disappear before the AP service complete its
// registration with DBus.
if (service_watchers_.find(service->identifier()) ==
service_watchers_.end()) {
LOG(INFO) << "Service " << service->identifier()
<< ": owner doesn't exist anymore";
service.reset();
return;
}
// Add service to the service list and return the service dbus path for the
// CreateService call.
dbus::ObjectPath service_path = service->dbus_path();
services_.push_back(std::move(service));
response->Return(service_path);
}
void Manager::OnDeviceRegistered(scoped_refptr<Device> device, bool success) {
// Success should always be true since we've said that failures are fatal.
CHECK(success) << "Init of one or more objects has failed.";
devices_.push_back(device);
// TODO(zqiu): Property update for available devices.
}
void Manager::OnAPServiceOwnerDisappeared(int service_identifier) {
LOG(INFO) << "Owner for service " << service_identifier << " disappeared";
// Remove service watcher.
auto watcher = service_watchers_.find(service_identifier);
CHECK(watcher != service_watchers_.end())
<< "Owner disappeared without watcher setup";
service_watchers_.erase(watcher);
// Remove the service.
for (auto it = services_.begin(); it != services_.end(); ++it) {
if ((*it)->identifier() == service_identifier) {
services_.erase(it);
return;
}
}
LOG(INFO) << "Owner for service " << service_identifier
<< " disappeared before it is registered";
}
} // namespace apmanager