blob: a05f431705f3f92e7c81bf2e96d7eff053f5ab22 [file]
// Copyright (c) 2010 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 "src/service.h"
#include <glog/logging.h>
#include "src/device.h"
namespace cashew {
// Flimflam Service D-Bus identifiers
static const char* kFlimflamServiceName = "org.chromium.flimflam";
// Flimflam Service property names
static const char *kFlimflamServiceDeviceProperty = "Device";
static const char *kFlimflamServiceStateProperty = "State";
static const char* kFlimflamServiceTypeProperty = "Type";
// Flimflam Service on-the-wire State values
static const char* kFlimflamServiceStateIdle = "idle";
static const char* kFlimflamServiceStateCarrier = "carrier";
static const char* kFlimflamServiceStateAssociation = "association";
static const char* kFlimflamServiceStateConfiguration = "configuration";
static const char* kFlimflamServiceStateReady = "ready";
static const char* kFlimflamServiceStateDisconnect = "disconnect";
static const char* kFlimflamServiceStateFailure = "failure";
static const char* kFlimflamServiceStateActivationFailure =
"activation-failure";
// Flimflam Service on-the-wire Type values
static const char* kFlimflamServiceTypeEthernet = "ethernet";
static const char* kFlimflamServiceTypeWifi = "wifi";
static const char* kFlimflamServiceTypeWimax = "wimax";
static const char* kFlimflamServiceTypeBluetooth = "bluetooth";
static const char* kFlimflamServiceTypeCellular = "cellular";
Service::Service(DBus::Connection& connection, // NOLINT
const DBus::Path& path)
: DBus::ObjectProxy(connection, path, kFlimflamServiceName),
connection_(connection), path_(path), state_(kStateUnknown),
type_(kTypeUnknown), device_(NULL) {
// init our state with a GetProperties() call to our Flimflam service path
// we'll update this state by monitoring PropertyChanged signals
GetServiceProperties();
// init our data plans list with a hardcoded plan
// TODO(vlaviano): implement backend and return real data
AddHardcodedDataPlan();
}
Service::~Service() {
DeleteDataPlans();
if (device_ != NULL) {
DLOG(INFO) << path_ << ": deleting device " << device_->GetPath();
delete device_;
device_ = NULL;
}
}
const DBus::Path& Service::GetPath() const {
return path_;
}
Service::State Service::GetState() const {
return state_;
}
Service::Type Service::GetType() const {
return type_;
}
Device* Service::GetDevice() const {
return device_;
}
DBusDataPlanList Service::GetDBusDataPlans() const {
DBusDataPlanList dbus_data_plans;
DataPlanList::const_iterator it;
for (it = data_plans_.begin(); it != data_plans_.end(); ++it) {
DataPlan *plan = *it;
DCHECK(plan != NULL);
dbus_data_plans.push_back(plan->ToDBusFormat());
}
return dbus_data_plans;
}
// Flimflam Service D-Bus Proxy methods
void Service::PropertyChanged(const std::string& property_name,
const DBus::Variant& new_value) {
DLOG(INFO) << path_ << ": PropertyChanged: property_name = " << property_name;
if (property_name.compare(kFlimflamServiceDeviceProperty) == 0) {
OnDeviceUpdate(new_value.reader().get_path());
} else if (property_name.compare(kFlimflamServiceStateProperty) == 0) {
OnStateUpdate(new_value.reader().get_string());
} else if (property_name.compare(kFlimflamServiceTypeProperty) == 0) {
OnTypeUpdate(new_value.reader().get_string());
} else {
// we don't care about this property
}
}
// Private methods
Service::State Service::StateFromString(const std::string& state) const {
if (state.compare(kFlimflamServiceStateIdle) == 0) {
return kStateIdle;
}
if (state.compare(kFlimflamServiceStateCarrier) == 0) {
return kStateCarrier;
}
if (state.compare(kFlimflamServiceStateAssociation) == 0) {
return kStateAssociation;
}
if (state.compare(kFlimflamServiceStateConfiguration) == 0) {
return kStateConfiguration;
}
if (state.compare(kFlimflamServiceStateReady) == 0) {
return kStateReady;
}
if (state.compare(kFlimflamServiceStateDisconnect) == 0) {
return kStateDisconnect;
}
if (state.compare(kFlimflamServiceStateFailure) == 0) {
return kStateFailure;
}
if (state.compare(kFlimflamServiceStateActivationFailure) == 0) {
return kStateActivationFailure;
}
return kStateUnknown;
}
Service::Type Service::TypeFromString(const std::string& type) const {
if (type.compare(kFlimflamServiceTypeEthernet) == 0) {
return kTypeEthernet;
}
if (type.compare(kFlimflamServiceTypeWifi) == 0) {
return kTypeWifi;
}
if (type.compare(kFlimflamServiceTypeWimax) == 0) {
return kTypeWimax;
}
if (type.compare(kFlimflamServiceTypeBluetooth) == 0) {
return kTypeBluetooth;
}
if (type.compare(kFlimflamServiceTypeCellular) == 0) {
return kTypeCellular;
}
return kTypeUnknown;
}
void Service::OnDeviceUpdate(const DBus::Path& device_path) {
DLOG(INFO) << path_ << ": OnDeviceUpdate: device_path = " << device_path;
// if there's an existing device with a non-matching path: destroy it and
// fall through to make a new one below.
if (device_ != NULL && device_->GetPath().compare(device_path)) {
LOG(WARNING) << path_ << ": OnDeviceUpdate: device path changed from "
<< device_->GetPath() << " to " << device_path;
delete device_;
device_ = NULL;
}
// if there's an existing device with matching path: all is well
if (device_ != NULL) {
return;
}
// if there's no existing device: make one
device_ = new(std::nothrow) Device(connection_, device_path);
if (device_ == NULL) {
LOG(ERROR) << path_ << ": OnDeviceUpdate: couldn't create device for "
<< device_path;
return;
}
DLOG(INFO) << path_ << ": OnDeviceUpdate: created device for "
<< device_path;
}
void Service::OnStateUpdate(const std::string& state) {
DLOG(INFO) << path_ << ": OnStateUpdate: state = " << state;
state_ = StateFromString(state);
// TODO(vlaviano): react to state changes
// note that ready does not necessarily mean that we're the default route
}
void Service::OnTypeUpdate(const std::string& type) {
DLOG(INFO) << path_ << ": OnTypeUpdate: type = " << type;
type_ = TypeFromString(type);
if (type_ != kTypeCellular) {
LOG(WARNING) << path_ << ": OnTypeUpdate: type is not cellular!";
}
}
void Service::GetServiceProperties() {
DLOG(INFO) << path_ << ": GetServiceProperties";
PropertyMap properties;
// dbus-c++ throws exceptions
// invoke the "Existing Non-conformant Code" clause of the style guide and
// isolate the rest of the system from this
try {
// TODO(vlaviano): make this call asynchronous
properties = GetProperties();
} catch (DBus::Error& error) { // NOLINT
LOG(WARNING) << path_
<< ": GetServiceProperties: GetProperties() -> Exception: "
<< error.name() << ": " << error.message();
// TODO(vlaviano): schedule another attempt later
return;
} catch (...) { // NOLINT
LOG(WARNING) << path_
<< ": GetServiceProperties: GetProperties() -> Exception";
// TODO(vlaviano): schedule another attempt later
return;
}
DLOG(INFO) << "Received " << properties.size() << " properties";
// grab the properties in which we're interested
PropertyMap::const_iterator it;
it = properties.find(kFlimflamServiceDeviceProperty);
if (it != properties.end()) {
const DBus::Variant& value = static_cast<DBus::Variant>(it->second);
OnDeviceUpdate(value.reader().get_path());
} else {
DLOG(WARNING) << path_ << ": GetServiceProperties: no Device property";
}
it = properties.find(kFlimflamServiceStateProperty);
if (it != properties.end()) {
const DBus::Variant& value = static_cast<DBus::Variant>(it->second);
OnStateUpdate(value.reader().get_string());
} else {
DLOG(WARNING) << path_ << ": GetServiceProperties: no State property";
}
it = properties.find(kFlimflamServiceTypeProperty);
if (it != properties.end()) {
const DBus::Variant& value = static_cast<DBus::Variant>(it->second);
OnTypeUpdate(value.reader().get_string());
} else {
DLOG(WARNING) << path_ << ": GetServiceProperties: no Type property";
}
}
void Service::DeleteDataPlans() {
while (!data_plans_.empty()) {
DataPlan *plan = *data_plans_.begin();
DCHECK(plan != NULL);
DLOG(INFO) << path_ << ": DeleteDataPlans: deleting plan: "
<< plan->GetName();
delete plan;
data_plans_.erase(data_plans_.begin());
}
}
void Service::AddHardcodedDataPlan() {
const std::string name = "Chromium OS Test Plan";
DataPlan::Type type = DataPlan::kTypeMeteredPaid;
base::Time update_time = base::Time::Now();
base::TimeDelta twelve_hours = base::TimeDelta::FromHours(12);
base::Time start_time = base::Time::Now() - twelve_hours;
base::Time end_time = base::Time::Now() + twelve_hours;
Bytes data_bytes_max = 100*1024*1024; // 100 MB
Bytes data_bytes_used = 30*1024*1024; // 30 MB
DataPlan *plan = new(std::nothrow) DataPlan(name, type, update_time,
start_time, end_time,
data_bytes_max, data_bytes_used);
if (plan == NULL) {
LOG(ERROR) << path_ << ": AddHardcodedDataPlan: could not create plan";
return;
}
data_plans_.push_back(plan);
}
} // namespace cashew