| Index: src/service.cc
|
| diff --git a/src/service.cc b/src/service.cc
|
| index 7427022e31b442213f7c57f3ae29a793ee75d725..39b69bd94c8e799b30ba2596a55d81e85de80985 100644
|
| --- a/src/service.cc
|
| +++ b/src/service.cc
|
| @@ -1,4 +1,4 @@
|
| -// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
|
| +// Copyright (c) 2010, 2011 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.
|
|
|
| @@ -6,935 +6,21 @@
|
|
|
| #include <glog/logging.h>
|
|
|
| -#include "src/data_plan_provider.h"
|
| -#include "src/device.h"
|
| -#include "src/policy.h"
|
| -#include "src/service_manager.h"
|
| +#include "src/service_impl.h"
|
|
|
| namespace cashew {
|
|
|
| -// Flimflam Service D-Bus identifiers
|
| -static const char *kFlimflamServiceName = "org.chromium.flimflam";
|
| -
|
| -// Flimflam Service property names
|
| -static const char *kFlimflamServiceConnectivityStateProperty =
|
| - "ConnectivityState";
|
| -static const char *kFlimflamServiceDeviceProperty = "Device";
|
| -static const char *kFlimflamServiceStateProperty = "State";
|
| -static const char *kFlimflamServiceTypeProperty = "Type";
|
| -static const char *kFlimflamServiceUsageUrlProperty = "Cellular.UsageUrl";
|
| -
|
| -// Flimflam Service on-the-wire ConnectivityState values
|
| -static const char *kFlimflamServiceConnectivityStateUnknown = "unknown";
|
| -static const char *kFlimflamServiceConnectivityStateRestricted = "restricted";
|
| -static const char *kFlimflamServiceConnectivityStateUnrestricted =
|
| - "unrestricted";
|
| -static const char *kFlimflamServiceConnectivityStateNone = "none";
|
| -
|
| -// 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";
|
| -
|
| -// Chromium OS Usage API property names
|
| -static const char *kCrosUsageVersionProperty = "version";
|
| -static const char *kCrosUsageStatusProperty = "status";
|
| -static const char *kCrosUsageRestrictedProperty = "restricted";
|
| -static const char *kCrosUsagePlansProperty = "plans";
|
| -
|
| -// Chromium OS Usage API version values
|
| -static const int kCrosUsageVersionMinSupported = 1;
|
| -static const int kCrosUsageVersionMaxSupported = 1;
|
| -
|
| -// Chromium OS Usage API status values
|
| -// NOTE: add new values to IsValidCrosUsageStatus below also
|
| -static const char *kCrosUsageStatusOk = "OK";
|
| -static const char *kCrosUsageStatusError = "ERROR";
|
| -static const char *kCrosUsageStatusMalformedRequest = "MALFORMED REQUEST";
|
| -static const char *kCrosUsageStatusInternalError = "INTERNAL ERROR";
|
| -static const char *kCrosUsageStatusServiceUnavailable = "SERVICE UNAVAILABLE";
|
| -static const char *kCrosUsageStatusRequestRefused = "REQUEST REFUSED";
|
| -static const char *kCrosUsageStatusUnknownDevice = "UNKNOWN DEVICE";
|
| -
|
| -// GetServiceProperties retry interval
|
| -static const guint kSecondsPerMinute = 60;
|
| -static const guint kGetServicePropertiesIntervalSeconds = 1 * kSecondsPerMinute;
|
| -
|
| -Service::Service(ServiceManager * const parent,
|
| - DBus::Connection& connection, // NOLINT
|
| - const DBus::Path& path)
|
| - : DBus::ObjectProxy(connection, path, kFlimflamServiceName),
|
| - parent_(CHECK_NOTNULL(parent)), connection_(connection), path_(path),
|
| - state_(kStateUnknown), type_(kTypeUnknown), device_(NULL),
|
| - provider_(NULL), request_in_progress_(false),
|
| - update_timeout_source_(NULL), policy_(NULL),
|
| - is_default_service_(false), get_properties_source_id_(0),
|
| - retrying_get_properties_(false),
|
| - connectivity_state_(kConnectivityStateUnknown) {
|
| - // schedule a GetProperties() call to our Flimflam service path to init state
|
| - // we'll keep trying periodically until we succeed
|
| - // we'll subsequently update this state by monitoring PropertyChanged signals
|
| - get_properties_source_id_ =
|
| - g_idle_add(StaticGetServicePropertiesCallback, this);
|
| - if (get_properties_source_id_ == 0) {
|
| - LOG(ERROR) << path_ << ": ctor: g_idle_add failed";
|
| - }
|
| - property_changed_handler_.delegate(this);
|
| -}
|
| -
|
| -Service::~Service() {
|
| - DeleteCarrierState();
|
| - DeleteDataPlans(&data_plans_);
|
| - if (device_ != NULL) {
|
| - DLOG(INFO) << path_ << ": deleting device " << device_->GetPath();
|
| - delete device_;
|
| - device_ = NULL;
|
| - }
|
| - if (get_properties_source_id_ != 0 &&
|
| - !g_source_remove(get_properties_source_id_)) {
|
| - DLOG(WARNING) << path_ << ": dtor: g_source_remove failed";
|
| - }
|
| -}
|
| -
|
| -const DBus::Path& Service::GetPath() const {
|
| - return path_;
|
| -}
|
| -
|
| -Service::State Service::GetState() const {
|
| - return state_;
|
| -}
|
| -
|
| -Service::Type Service::GetType() const {
|
| - return type_;
|
| -}
|
| -
|
| // static
|
| Service::Type Service::TypeFromString(const std::string& type) {
|
| - if (type == kFlimflamServiceTypeEthernet) {
|
| - return kTypeEthernet;
|
| - }
|
| - if (type == kFlimflamServiceTypeWifi) {
|
| - return kTypeWifi;
|
| - }
|
| - if (type == kFlimflamServiceTypeWimax) {
|
| - return kTypeWimax;
|
| - }
|
| - if (type == kFlimflamServiceTypeBluetooth) {
|
| - return kTypeBluetooth;
|
| - }
|
| - if (type == kFlimflamServiceTypeCellular) {
|
| - return kTypeCellular;
|
| - }
|
| - return kTypeUnknown;
|
| -}
|
| -
|
| -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);
|
| - // filter out inactive plans
|
| - if (plan->IsActive()) {
|
| - dbus_data_plans.push_back(plan->ToDBusFormat());
|
| - } else {
|
| - DLOG(INFO) << path_ << ": GetBusDataPlans: skipping inactive plan: \""
|
| - << plan->GetName() << "\"";
|
| - }
|
| - }
|
| - return dbus_data_plans;
|
| -}
|
| -
|
| -bool Service::IsDefaultService() const {
|
| - if (is_default_service_) {
|
| - // cross-check with parent's idea of default technology
|
| - if (parent_->GetDefaultTechnology() != kTypeCellular) {
|
| - DLOG(WARNING) << path_ << ": IsDefaultService: "
|
| - << "service manager doesn't think default technology is cellular";
|
| - }
|
| - return true;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -Service::ConnectivityState Service::GetConnectivityState() const {
|
| - return connectivity_state_;
|
| -}
|
| -
|
| -// 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;
|
| - // Queue a tuple representing this signal for later processing from the glib
|
| - // main loop. We do this to avoid libdbus-c++ deadlocks that can occur when
|
| - // sending a dbus message from within a dbus callback like this one.
|
| - PropertyChangedSignal signal(property_name, new_value);
|
| - property_changed_handler_.EnqueueSignal(signal);
|
| -}
|
| -
|
| -// PropertyChangedDelegate methods
|
| -
|
| -void Service::OnPropertyChanged(const PropertyChangedHandler *handler,
|
| - const std::string& property_name,
|
| - const DBus::Variant& new_value) {
|
| - DCHECK(handler == &property_changed_handler_);
|
| - DLOG(INFO) << path_ << ": OnPropertyChanged: property_name = "
|
| - << property_name;
|
| - if (property_name == kFlimflamServiceDeviceProperty) {
|
| - OnDeviceUpdate(new_value.reader().get_path());
|
| - } else if (property_name == kFlimflamServiceStateProperty) {
|
| - OnStateUpdate(new_value.reader().get_string());
|
| - } else if (property_name == kFlimflamServiceTypeProperty) {
|
| - OnTypeUpdate(new_value.reader().get_string());
|
| - } else if (property_name == kFlimflamServiceUsageUrlProperty) {
|
| - OnUsageUrlUpdate(new_value.reader().get_string());
|
| - } else if (property_name == kFlimflamServiceConnectivityStateProperty) {
|
| - OnConnectivityStateUpdate(new_value.reader().get_string());
|
| - } else {
|
| - // we don't care about this property
|
| - }
|
| -}
|
| -
|
| -// Device methods
|
| -
|
| -void Service::OnCarrierUpdate(const std::string& carrier) {
|
| - DLOG(INFO) << path_ << ": OnCarrierUpdate: carrier = " << carrier;
|
| - DCHECK(device_ != NULL);
|
| - DCHECK(carrier == device_->GetCarrier());
|
| -
|
| - // get rid of state associated with old carrier
|
| - if (provider_ != NULL) {
|
| - DCHECK(carrier != provider_->GetCarrier());
|
| - }
|
| - DeleteCarrierState();
|
| -
|
| - // if we don't have new carrier info, we can't do anything now
|
| - if (carrier.empty()) {
|
| - return;
|
| - }
|
| -
|
| - // create state for new carrier
|
| - DLOG(INFO) << path_ << ": OnCarrierUpdate: creating data plan provider";
|
| - provider_ = new(std::nothrow) DataPlanProvider(carrier);
|
| - if (provider_ == NULL) {
|
| - LOG(ERROR) << path_
|
| - << ": OnCarrierUpdate: could not create data plan provider";
|
| - return;
|
| - }
|
| - provider_->SetDelegate(this);
|
| - DLOG(INFO) << path_ << ": OnCarrierUpdate: getting policy for " << carrier;
|
| - policy_ = Policy::GetPolicy(carrier);
|
| - if (policy_ == NULL) {
|
| - LOG(ERROR) << path_ << ": OnCarrierUpdate: could not get policy for "
|
| - << carrier;
|
| - DeleteCarrierState();
|
| - return;
|
| - }
|
| -
|
| - // if we already have usage url, set new provider in motion
|
| - if (!usage_url_.empty()) {
|
| - provider_->SetUsageUrl(usage_url_);
|
| - ReconsiderSendingUsageRequests();
|
| - } else {
|
| - // we'll do this later in OnUsageUrlUpdate
|
| - }
|
| -}
|
| -
|
| -void Service::OnByteCounterUpdate(uint64 rx_bytes, uint64 tx_bytes) {
|
| - DCHECK(device_ != NULL);
|
| - DCHECK(device_->ByteCounterRunning());
|
| - DLOG(INFO) << path_ << ": OnByteCounterUpdate: rx_bytes = " << rx_bytes
|
| - << ", tx_bytes = " << tx_bytes;
|
| - DataPlan *active_plan = DataPlan::GetActivePlan(data_plans_);
|
| - if (active_plan == NULL) {
|
| - DLOG(WARNING) << path_ << ": OnByteCounterUpdate: no active plan";
|
| - return;
|
| - }
|
| - Bytes local_bytes_used = rx_bytes + tx_bytes;
|
| - DLOG(INFO) << path_ << ": OnByteCounterUpdate: local_bytes_used = "
|
| - << local_bytes_used;
|
| - // try to detect two error conditions:
|
| - // (1) overflow of the unsigned addition above prior to the assignment
|
| - // (2) no overflow, but result has high order bit set and so is interpreted as
|
| - // a negative number when assigned to |local_bytes_used|
|
| - if (local_bytes_used < 0 ||
|
| - static_cast<uint64>(local_bytes_used) < rx_bytes ||
|
| - static_cast<uint64>(local_bytes_used) < tx_bytes) {
|
| - LOG(WARNING) << path_ << ": OnByteCounterUpdate: overflow detected";
|
| - return;
|
| - }
|
| - active_plan->SetLocalBytesUsed(local_bytes_used);
|
| - DLOG(INFO) << path_
|
| - << ": OnByteCounterUpdate: updated plan state: data bytes used = "
|
| - << active_plan->GetDataBytesUsed() << ", local bytes used = "
|
| - << active_plan->GetLocalBytesUsed() << ", total bytes used = "
|
| - << active_plan->GetTotalBytesUsed();
|
| - MaybeEmitDataPlansUpdate();
|
| -}
|
| -
|
| -// DataPlanProviderDelegate methods
|
| -
|
| -void Service::OnRequestComplete(const DataPlanProvider *provider,
|
| - bool successful,
|
| - const Value *parsed_usage_update) {
|
| - DCHECK(provider != NULL);
|
| - DCHECK(!successful || parsed_usage_update != NULL);
|
| - if (provider != provider_) {
|
| - DLOG(WARNING) << path_ << ": OnRequestComplete: wrong provider";
|
| - return;
|
| - }
|
| - DCHECK(request_in_progress_);
|
| - DCHECK(policy_ != NULL);
|
| - DLOG(INFO) << path_ << ": OnRequestComplete: result = " << successful;
|
| - request_in_progress_ = false;
|
| - if (!successful) {
|
| - LOG(WARNING) << path_ << ": OnRequestComplete: request failed";
|
| - return;
|
| - }
|
| -
|
| - // interpret and validate parsed usage update
|
| - if (!parsed_usage_update->IsType(Value::TYPE_DICTIONARY)) {
|
| - LOG(WARNING) << path_
|
| - << ": OnRequestComplete: root value is not a dictionary";
|
| - return;
|
| - }
|
| - const DictionaryValue *root =
|
| - static_cast<const DictionaryValue*>(parsed_usage_update);
|
| -
|
| - int version;
|
| - if (!root->GetInteger(kCrosUsageVersionProperty, &version)) {
|
| - LOG(WARNING) << path_ << ": OnRequestComplete: no version property";
|
| - return;
|
| - }
|
| - DLOG(INFO) << path_ << ": OnRequestComplete: version = " << version;
|
| - if (version < kCrosUsageVersionMinSupported ||
|
| - version > kCrosUsageVersionMaxSupported) {
|
| - LOG(WARNING) << path_ << ": OnRequestComplete: version " << version
|
| - << " not in supported range of [" << kCrosUsageVersionMinSupported
|
| - << ", " << kCrosUsageVersionMaxSupported << "]";
|
| - return;
|
| - }
|
| -
|
| - std::string status;
|
| - if (!root->GetString(kCrosUsageStatusProperty, &status)) {
|
| - LOG(WARNING) << path_ << ": OnRequestComplete: no status property";
|
| - return;
|
| - }
|
| - DLOG(INFO) << path_ << ": OnRequestComplete: status = " << status;
|
| - if (!IsValidCrosUsageStatus(status)) {
|
| - LOG(WARNING) << path_ << ": OnRequestComplete: invalid status: " << status;
|
| - return;
|
| - }
|
| - if (status != kCrosUsageStatusOk) {
|
| - LOG(WARNING) << path_ << ": OnRequestComplete: status: " << status;
|
| - OnCrosUsageErrorResult(status);
|
| - return;
|
| - }
|
| -
|
| - bool restricted = false;
|
| - if (root->GetBoolean(kCrosUsageRestrictedProperty, &restricted)) {
|
| - DLOG(INFO) << path_ << ": OnRequestComplete: restricted = " << restricted;
|
| - // TODO(vlaviano): this should probably be combined with flimflam's
|
| - // ConnectivityState property to arrive at a conclusion.
|
| -
|
| - } else {
|
| - DLOG(INFO) << path_ << ": OnRequestComplete: no restricted property";
|
| - // restricted property is optional
|
| - }
|
| -
|
| - ListValue *plans = NULL; // list to which this points is owned by dictionary
|
| - if (!root->GetList(kCrosUsagePlansProperty, &plans)) {
|
| - LOG(WARNING) << path_ << ": OnRequestComplete: no plans property";
|
| - return;
|
| - }
|
| - DCHECK(plans != NULL);
|
| - size_t plans_size = plans->GetSize();
|
| - DLOG(INFO) << path_ << ": OnRequestComplete: plans list has size "
|
| - << plans_size;
|
| -
|
| - // walk plans list and convert each into a DataPlan object
|
| - DataPlanList new_plans;
|
| - for (size_t i = 0; i < plans_size; ++i) {
|
| - DictionaryValue *plan_dict = NULL;
|
| - if (!plans->GetDictionary(i, &plan_dict)) {
|
| - LOG(WARNING) << path_
|
| - << ": OnRequestComplete: could not get plan[" << i << "]";
|
| - continue;
|
| - }
|
| - DCHECK(plan_dict != NULL);
|
| - DataPlan *plan = DataPlan::FromDictionaryValue(plan_dict, policy_);
|
| - if (plan == NULL) {
|
| - LOG(WARNING) << path_
|
| - << ": OnRequestComplete: could not convert plan[" << i << "]";
|
| - continue;
|
| - }
|
| - DLOG(INFO) << path_ << ": OnRequestComplete: converted plan[" << i << "]";
|
| - new_plans.push_back(plan);
|
| - }
|
| -
|
| - // store new info, causing it to be used for subsequent updates to clients
|
| - DataPlanList old_plans = data_plans_;
|
| - data_plans_ = new_plans;
|
| - LOG(INFO) << path_ << ": OnRequestComplete: updated data plans";
|
| -
|
| - MaybeEmitDataPlansUpdate();
|
| -
|
| - DLOG(INFO) << path_ << ": OnRequestComplete: deleting old data plans";
|
| - DeleteDataPlans(&old_plans);
|
| -
|
| - // start local byte counter so that we can stop hitting usage API
|
| - // we'll stop the counter when we disconnect
|
| - // we don't bother if carrier told us that there are no active data plans
|
| - DataPlan *active_plan = DataPlan::GetActivePlan(data_plans_);
|
| - if (active_plan == NULL) {
|
| - DLOG(INFO) << path_
|
| - << ": OnRequestComplete: no active plans, not starting byte counter";
|
| - return;
|
| - }
|
| - DCHECK(device_ != NULL);
|
| - DCHECK(!device_->ByteCounterRunning());
|
| - if (!device_->StartByteCounter()) {
|
| - LOG(WARNING) << path_
|
| - << ": OnRequestComplete: could not start byte counter";
|
| - // we'll keep the update timer running and try again later
|
| - }
|
| - DLOG(INFO) << path_ << ": OnRequestComplete: started byte counter";
|
| - ReconsiderSendingUsageRequests();
|
| -}
|
| -
|
| -// Service Manager methods
|
| -
|
| -void Service::OnDefaultServiceUpdate(bool is_default_service) {
|
| - DCHECK(is_default_service_ == !is_default_service);
|
| - DLOG(INFO) << path_ << ": OnDefaultServiceUpdate: is_default_service = "
|
| - << is_default_service;
|
| - is_default_service_ = is_default_service;
|
| - if (is_default_service_) {
|
| - // we just became the default service
|
| - // cross-check with parent's idea of default technology
|
| - if (parent_->GetDefaultTechnology() != kTypeCellular) {
|
| - DLOG(WARNING) << path_ << ": OnDefaultServiceUpdate: "
|
| - << "service manager doesn't think default technology is cellular";
|
| - }
|
| - }
|
| - ReconsiderSendingUsageRequests();
|
| -}
|
| -
|
| -void Service::OnFlimflamOnline() {
|
| - DLOG(INFO) << path_ << ": OnFlimflamOnline";
|
| - ReconsiderSendingUsageRequests();
|
| -}
|
| -
|
| -void Service::OnFlimflamOffline() {
|
| - DLOG(INFO) << path_ << ": OnFlimflamOffline";
|
| - ReconsiderSendingUsageRequests();
|
| -}
|
| -
|
| -// glib integration interface
|
| -
|
| -guint Service::GetGetPropertiesSourceId() const {
|
| - return get_properties_source_id_;
|
| -}
|
| -
|
| -void Service::SetGetPropertiesSourceId(guint source_id) {
|
| - get_properties_source_id_ = source_id;
|
| -}
|
| -
|
| -bool Service::RetryingGetProperties() const {
|
| - return retrying_get_properties_;
|
| -}
|
| -
|
| -void Service::OnRetryingGetProperties(bool retrying) {
|
| - retrying_get_properties_ = retrying;
|
| + return ServiceImpl::TypeFromString(type);
|
| }
|
|
|
| -// Private methods
|
| -
|
| // static
|
| -Service::ConnectivityState Service::ConnectivityStateFromString(
|
| - const std::string& connectivity_state) {
|
| - if (connectivity_state == kFlimflamServiceConnectivityStateUnknown) {
|
| - return kConnectivityStateUnknown;
|
| - }
|
| - if (connectivity_state == kFlimflamServiceConnectivityStateRestricted) {
|
| - return kConnectivityStateRestricted;
|
| - }
|
| - if (connectivity_state == kFlimflamServiceConnectivityStateUnrestricted) {
|
| - return kConnectivityStateUnrestricted;
|
| - }
|
| - if (connectivity_state == kFlimflamServiceConnectivityStateNone) {
|
| - return kConnectivityStateNone;
|
| - }
|
| - return kConnectivityStateUnknown;
|
| -}
|
| -
|
| -// static
|
| -Service::State Service::StateFromString(const std::string& state) {
|
| - if (state == kFlimflamServiceStateIdle) {
|
| - return kStateIdle;
|
| - }
|
| - if (state == kFlimflamServiceStateCarrier) {
|
| - return kStateCarrier;
|
| - }
|
| - if (state == kFlimflamServiceStateAssociation) {
|
| - return kStateAssociation;
|
| - }
|
| - if (state == kFlimflamServiceStateConfiguration) {
|
| - return kStateConfiguration;
|
| - }
|
| - if (state == kFlimflamServiceStateReady) {
|
| - return kStateReady;
|
| - }
|
| - if (state == kFlimflamServiceStateDisconnect) {
|
| - return kStateDisconnect;
|
| - }
|
| - if (state == kFlimflamServiceStateFailure) {
|
| - return kStateFailure;
|
| - }
|
| - if (state == kFlimflamServiceStateActivationFailure) {
|
| - return kStateActivationFailure;
|
| - }
|
| - return kStateUnknown;
|
| -}
|
| -
|
| -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() != 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(this, 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::OnConnectivityStateUpdate(const std::string& connectivity_state) {
|
| - DLOG(INFO) << path_ << ": OnConnectivityStateUpdate: connectivity_state = "
|
| - << connectivity_state;
|
| - Service::ConnectivityState new_connectivity_state =
|
| - ConnectivityStateFromString(connectivity_state);
|
| - if (connectivity_state_ == new_connectivity_state) {
|
| - return;
|
| - }
|
| - connectivity_state_ = new_connectivity_state;
|
| - ReconsiderSendingUsageRequests();
|
| -}
|
| -
|
| -void Service::OnStateUpdate(const std::string& state) {
|
| - DLOG(INFO) << path_ << ": OnStateUpdate: state = " << state;
|
| - Service::State old_state = state_;
|
| - state_ = StateFromString(state);
|
| - if (old_state != kStateReady && IsConnected()) {
|
| - OnConnected();
|
| - } else if (old_state == kStateReady && !IsConnected()) {
|
| - OnDisconnected();
|
| - }
|
| -}
|
| -
|
| -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::OnUsageUrlUpdate(const std::string& usage_url) {
|
| - DLOG(INFO) << path_ << ": OnUsageUrlUpdate: url = " << usage_url;
|
| - if (usage_url == usage_url_) {
|
| - return;
|
| - }
|
| - usage_url_ = usage_url;
|
| - if (provider_ != NULL) {
|
| - DCHECK(usage_url_ != provider_->GetUsageUrl());
|
| - StopSendingUsageRequests();
|
| - provider_->SetUsageUrl(usage_url_);
|
| - ReconsiderSendingUsageRequests();
|
| - }
|
| -}
|
| -
|
| -// static
|
| -gboolean Service::StaticGetServicePropertiesCallback(gpointer data) {
|
| - Service *service = reinterpret_cast<Service*>(data);
|
| - CHECK_NOTNULL(service);
|
| - DCHECK_NE(service->GetGetPropertiesSourceId(), 0);
|
| - if (!service->GetServiceProperties()) {
|
| - // call failed, so try again later
|
| - DLOG(WARNING) << service->GetPath()
|
| - << ": StaticGetServicePropertiesCallback: "
|
| - << "GetServiceProperties failed, will retry in "
|
| - << kGetServicePropertiesIntervalSeconds << " secs";
|
| - // if we've arrived here from our first g_idle_add call, set up a timer
|
| - if (!service->RetryingGetProperties()) {
|
| - guint source_id =
|
| - g_timeout_add_seconds(kGetServicePropertiesIntervalSeconds,
|
| - StaticGetServicePropertiesCallback, service);
|
| - service->SetGetPropertiesSourceId(source_id);
|
| - if (source_id == 0) {
|
| - LOG(ERROR) << service->GetPath()
|
| - << ": StaticGetServicePropertiesCallback: "
|
| - << "g_timeout_add_seconds failed";
|
| - return FALSE; // get rid of old glib source and give up
|
| - }
|
| - service->OnRetryingGetProperties(true);
|
| - // get rid of our old glib source, but our new timer will call us
|
| - return FALSE;
|
| - }
|
| - // otherwise, our timer is already set up
|
| - // return TRUE to indicate that we want to be called again later
|
| - return TRUE;
|
| - }
|
| - service->SetGetPropertiesSourceId(0);
|
| - service->OnRetryingGetProperties(false);
|
| - return FALSE; // we succeeded, so don't repeat
|
| -}
|
| -
|
| -bool 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();
|
| - return false;
|
| - } catch (...) { // NOLINT
|
| - LOG(WARNING) << path_
|
| - << ": GetServiceProperties: GetProperties() -> Exception";
|
| - return false;
|
| - }
|
| - DLOG(INFO) << path_ << ": GetServiceProperties: 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";
|
| - }
|
| - // don't expect to find Cellular.* properties if we're not a cellular service
|
| - if (type_ != kTypeCellular) {
|
| - return true;
|
| - }
|
| - it = properties.find(kFlimflamServiceUsageUrlProperty);
|
| - if (it != properties.end()) {
|
| - const DBus::Variant& value = static_cast<DBus::Variant>(it->second);
|
| - OnUsageUrlUpdate(value.reader().get_string());
|
| - } else {
|
| - DLOG(WARNING) << path_
|
| - << ": GetServiceProperties: no Cellular.UsageUrl property";
|
| - }
|
| - // flimflam docs re: ConnectivityState: "This state is currently only
|
| - // computed for services of type Cellular"
|
| - it = properties.find(kFlimflamServiceConnectivityStateProperty);
|
| - if (it != properties.end()) {
|
| - const DBus::Variant& value = static_cast<DBus::Variant>(it->second);
|
| - OnConnectivityStateUpdate(value.reader().get_string());
|
| - } else {
|
| - DLOG(WARNING) << path_
|
| - << ": GetServiceProperties: no ConnectivityState property";
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -void Service::DeleteDataPlans(DataPlanList *data_plans) {
|
| - DCHECK(data_plans != NULL);
|
| - 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);
|
| -}
|
| -
|
| -void Service::RequestUsageUpdate() {
|
| - DCHECK(ShouldSendUsageRequests());
|
| - if (request_in_progress_) {
|
| - DLOG(WARNING) << path_
|
| - << ": RequestUsageUpdate: request already in progress";
|
| - return;
|
| - }
|
| - request_in_progress_ = true;
|
| - if (!provider_->RequestUsageUpdate()) {
|
| - DLOG(WARNING) << path_ << ": RequestUsageUpdate: request failed";
|
| - request_in_progress_ = false;
|
| - } else {
|
| - DLOG(INFO) << path_ << ": RequestUsageUpdate: request succeeded";
|
| - }
|
| -}
|
| -
|
| -void Service::CancelPendingRequests() {
|
| - if (provider_ != NULL && request_in_progress_) {
|
| - provider_->CancelPendingRequests();
|
| - request_in_progress_ = false;
|
| - }
|
| -}
|
| -
|
| -gboolean Service::UpdateTimeoutCallback() {
|
| - DLOG(INFO) << path_ << ": UpdateTimeoutCallback";
|
| - RequestUsageUpdate();
|
| - return TRUE;
|
| -}
|
| -
|
| -// static
|
| -gboolean Service::StaticUpdateTimeoutCallback(gpointer data) {
|
| - Service *service = reinterpret_cast<Service*>(data);
|
| - CHECK_NOTNULL(service);
|
| - return service->UpdateTimeoutCallback();
|
| -}
|
| -
|
| -bool Service::CreateUpdateTimer() {
|
| - DCHECK(provider_ != NULL);
|
| - DCHECK(policy_ != NULL);
|
| - guint idle_seconds = policy_->GetUpdateTimerIdleSecs(data_plans_);
|
| - DLOG(INFO) << path_ << ": CreateUpdateTimer: idle_seconds = " << idle_seconds;
|
| - if (update_timeout_source_ != NULL) {
|
| - DLOG(WARNING) << path_ << ": CreateUpdateTimer: timer already running";
|
| - return false;
|
| - }
|
| - update_timeout_source_ = g_timeout_source_new_seconds(idle_seconds);
|
| - if (update_timeout_source_ == NULL) {
|
| - DLOG(WARNING) << path_
|
| - << ": CreateUpdateTimer: could not create timeout source";
|
| - return false;
|
| - }
|
| - g_source_set_callback(update_timeout_source_, StaticUpdateTimeoutCallback,
|
| - this, NULL);
|
| - g_source_attach(update_timeout_source_, NULL);
|
| - return true;
|
| -}
|
| -
|
| -void Service::DestroyUpdateTimer() {
|
| - DLOG(INFO) << path_ << ": DestroyUpdateTimer";
|
| - if (update_timeout_source_ != NULL) {
|
| - g_source_destroy(update_timeout_source_);
|
| - update_timeout_source_ = NULL;
|
| - }
|
| -}
|
| -
|
| -void Service::DeleteCarrierState() {
|
| - DLOG(INFO) << path_ << ": DeleteCarrierState";
|
| - if (policy_ != NULL) {
|
| - DLOG(INFO) << path_ << ": DeleteCarrierState: deleting policy";
|
| - delete policy_;
|
| - policy_ = NULL;
|
| - }
|
| - StopSendingUsageRequests();
|
| - if (provider_ != NULL) {
|
| - DLOG(INFO) << path_ << ": DeleteCarrierState: deleting data plan provider";
|
| - delete provider_;
|
| - provider_ = NULL;
|
| - }
|
| -}
|
| -
|
| -bool Service::IsValidCrosUsageStatus(const std::string& status) const {
|
| - if (status == kCrosUsageStatusOk ||
|
| - status == kCrosUsageStatusError ||
|
| - status == kCrosUsageStatusMalformedRequest ||
|
| - status == kCrosUsageStatusInternalError ||
|
| - status == kCrosUsageStatusServiceUnavailable ||
|
| - status == kCrosUsageStatusRequestRefused ||
|
| - status == kCrosUsageStatusUnknownDevice) {
|
| - return true;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -void Service::OnCrosUsageErrorResult(const std::string& status) {
|
| - DLOG(WARNING) << path_ << ": OnCrosUsageErrorResult: " << status;
|
| - // TODO(vlaviano): hook for future use
|
| -}
|
| -
|
| -bool Service::IsConnected() const {
|
| - if (state_ != kStateReady) {
|
| - return false;
|
| - }
|
| - // cross-check with parent Service Manager's idea of Flimflam global
|
| - // connectivity state
|
| - if (ServiceManager::IsOfflineConnectivityState(
|
| - parent_->GetConnectivityState())) {
|
| - DLOG(WARNING) << path_
|
| - << ": IsConnected: service manager thinks we're offline";
|
| - return false;
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -void Service::OnConnected() {
|
| - DLOG(INFO) << path_ << ": OnConnected";
|
| - DCHECK(IsConnected());
|
| - ReconsiderSendingUsageRequests();
|
| -}
|
| -
|
| -void Service::OnDisconnected() {
|
| - DLOG(INFO) << path_ << ": OnDisconnected";
|
| - DCHECK(!IsConnected());
|
| - // stop byte counter
|
| - // we'll issue a new usage API request when we reconnect
|
| - if (device_ != NULL) {
|
| - device_->StopByteCounter();
|
| - }
|
| - ReconsiderSendingUsageRequests();
|
| -}
|
| -
|
| -bool Service::IsSendingUsageRequests() const {
|
| - return request_in_progress_ || update_timeout_source_ != NULL;
|
| -}
|
| -
|
| -// NOTE: we centralize our decisionmaking here to avoid insanity and just call
|
| -// ReconsiderSendingUsageRequests when anything changes
|
| -bool Service::ShouldSendUsageRequests() const {
|
| - if (provider_ == NULL) {
|
| - DLOG(INFO) << path_ << ": ShouldSendUsageRequests: no: no provider";
|
| - DCHECK(policy_ == NULL);
|
| - return false;
|
| - }
|
| - DCHECK(device_ != NULL);
|
| - DCHECK(!device_->GetCarrier().empty());
|
| - DCHECK(policy_ != NULL);
|
| - if (usage_url_.empty()) {
|
| - DLOG(INFO) << path_ << ": ShouldSendUsageRequests: no: no usage url";
|
| - return false;
|
| - }
|
| - if (ServiceManager::IsOfflineConnectivityState(
|
| - parent_->GetConnectivityState())) {
|
| - DLOG(INFO) << path_
|
| - << ": ShouldSendUsageRequests: no: flimflam is offline";
|
| - return false;
|
| - }
|
| - if (!IsConnected()) {
|
| - DLOG(INFO) << path_ << ": ShouldSendUsageRequests: no: not connected";
|
| - return false;
|
| - }
|
| - if (!IsDefaultService()) {
|
| - DLOG(INFO) << path_ << ": ShouldSendUsageRequests: no: not default service";
|
| - return false;
|
| - }
|
| - // TODO(vlaviano): this is a blunt way to ensure that we don't count local
|
| - // traffic if we're already in the restricted pool when cashew starts
|
| - if (GetConnectivityState() == kConnectivityStateRestricted) {
|
| - DLOG(INFO) << path_ << ": ShouldSendUsageRequests: no: in restricted pool";
|
| - return false;
|
| - }
|
| - if (device_->ByteCounterRunning()) {
|
| - DLOG(INFO) << path_
|
| - << ": ShouldSendUsageRequests: no: local byte counter is running";
|
| - return false;
|
| - }
|
| - DLOG(INFO) << path_ << ": ShouldSendUsageRequests: yes";
|
| - return true;
|
| -}
|
| -
|
| -void Service::StopSendingUsageRequests() {
|
| - DLOG(INFO) << path_ << ": StopSendingUsageRequests";
|
| - DestroyUpdateTimer();
|
| - CancelPendingRequests();
|
| -}
|
| -
|
| -void Service::StartSendingUsageRequests() {
|
| - DLOG(INFO) << path_ << ": StartSendingUsageRequests";
|
| - DCHECK(!IsSendingUsageRequests());
|
| - RequestUsageUpdate();
|
| - CreateUpdateTimer();
|
| -}
|
| -
|
| -void Service::ReconsiderSendingUsageRequests() {
|
| - DLOG(INFO) << path_ << ": ReconsiderSendingUsageRequests";
|
| - if (!IsSendingUsageRequests() && ShouldSendUsageRequests()) {
|
| - StartSendingUsageRequests();
|
| - } else if (IsSendingUsageRequests() && !ShouldSendUsageRequests()) {
|
| - StopSendingUsageRequests();
|
| - }
|
| -}
|
| -
|
| -void Service::MaybeEmitDataPlansUpdate() {
|
| - DCHECK(policy_ != NULL);
|
| - if (policy_->ShouldEmitDataPlansUpdate(data_plans_)) {
|
| - DLOG(INFO) << path_ << ": MaybeEmitDataPlansUpdate: sending update";
|
| - parent_->EmitDataPlansUpdate(*this);
|
| - } else {
|
| - DLOG(INFO) << path_ << ": MaybeEmitDataPlansUpdate: not sending update";
|
| - }
|
| +Service* Service::NewService(ServiceManager * const parent,
|
| + DBus::Connection& connection, // NOLINT
|
| + const DBus::Path& path) {
|
| + DCHECK(parent != NULL);
|
| + return new(std::nothrow) ServiceImpl(parent, connection, path);
|
| }
|
|
|
| } // namespace cashew
|
|
|