diff options
Diffstat (limited to 'chrome/browser/chromeos/cros/network_library.cc')
-rw-r--r-- | chrome/browser/chromeos/cros/network_library.cc | 824 |
1 files changed, 824 insertions, 0 deletions
diff --git a/chrome/browser/chromeos/cros/network_library.cc b/chrome/browser/chromeos/cros/network_library.cc new file mode 100644 index 0000000..7538111 --- /dev/null +++ b/chrome/browser/chromeos/cros/network_library.cc @@ -0,0 +1,824 @@ +// Copyright (c) 2010 The Chromium 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 "chrome/browser/chromeos/cros/network_library.h" + +#include <algorithm> + +#include "base/string_util.h" +#include "base/utf_string_conversions.h" +#include "chrome/browser/chrome_thread.h" +#include "chrome/browser/chromeos/cros/cros_library.h" +#include "net/url_request/url_request_job.h" + +// Allows InvokeLater without adding refcounting. This class is a Singleton and +// won't be deleted until it's last InvokeLater is run. +DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::NetworkLibraryImpl); + +namespace chromeos { + +static const std::string kGoogleWifi = "Google"; +static const std::string kGoogleAWifi = "Google-A"; + +// Helper function to wrap Html with <th> tag. +static std::string WrapWithTH(std::string text) { + return "<th>" + text + "</th>"; +} + +// Helper function to wrap Html with <td> tag. +static std::string WrapWithTD(std::string text) { + return "<td>" + text + "</td>"; +} + +// Helper function to create an Html table header for a Network. +static std::string ToHtmlTableHeader(Network* network) { + std::string str; + if (network->type() == TYPE_WIFI || network->type() == TYPE_CELLULAR) { + str += WrapWithTH("Name") + WrapWithTH("Auto-Connect") + + WrapWithTH("Strength"); + if (network->type() == TYPE_WIFI) + str += WrapWithTH("Encryption") + WrapWithTH("Passphrase") + + WrapWithTH("Identity") + WrapWithTH("Certificate"); + } + str += WrapWithTH("State") + WrapWithTH("Error") + WrapWithTH("IP Address"); + return str; +} + +// Helper function to create an Html table row for a Network. +static std::string ToHtmlTableRow(Network* network) { + std::string str; + if (network->type() == TYPE_WIFI || network->type() == TYPE_CELLULAR) { + WirelessNetwork* wireless = static_cast<WirelessNetwork*>(network); + str += WrapWithTD(wireless->name()) + + WrapWithTD(IntToString(wireless->auto_connect())) + + WrapWithTD(IntToString(wireless->strength())); + if (network->type() == TYPE_WIFI) { + WifiNetwork* wifi = static_cast<WifiNetwork*>(network); + str += WrapWithTD(wifi->GetEncryptionString()) + + WrapWithTD(wifi->passphrase()) + WrapWithTD(wifi->identity()) + + WrapWithTD(wifi->cert_path()); + } + } + str += WrapWithTD(network->GetStateString()) + + WrapWithTD(network->GetErrorString()) + WrapWithTD(network->ip_address()); + return str; +} + +//////////////////////////////////////////////////////////////////////////////// +// Network + +void Network::Clear() { + type_ = TYPE_UNKNOWN; + state_ = STATE_UNKNOWN; + error_ = ERROR_UNKNOWN; + service_path_.clear(); + device_path_.clear(); + ip_address_.clear(); +} + +void Network::ConfigureFromService(const ServiceInfo& service) { + type_ = service.type; + state_ = service.state; + error_ = service.error; + service_path_ = service.service_path; + device_path_ = service.device_path ? service.device_path : std::string(); + ip_address_.clear(); + // If connected, get ip config. + if (connected() && service.device_path) { + IPConfigStatus* ipconfig_status = ListIPConfigs(service.device_path); + if (ipconfig_status) { + for (int i = 0; i < ipconfig_status->size; i++) { + IPConfig ipconfig = ipconfig_status->ips[i]; + if (strlen(ipconfig.address) > 0) + ip_address_ = ipconfig.address; + } + FreeIPConfigStatus(ipconfig_status); + } + } +} + +std::string Network::GetStateString() { + switch (state_) { + case STATE_UNKNOWN: + break; + case STATE_IDLE: + return "Idle"; + case STATE_CARRIER: + return "Carrier"; + case STATE_ASSOCIATION: + return "Association"; + case STATE_CONFIGURATION: + return "Configuration"; + case STATE_READY: + return "Ready"; + case STATE_DISCONNECT: + return "Disconnect"; + case STATE_FAILURE: + return "Failure"; + } + return "Unknown"; +} + +std::string Network::GetErrorString() { + switch (error_) { + case ERROR_UNKNOWN: + break; + case ERROR_OUT_OF_RANGE: + return "Out Of Range"; + case ERROR_PIN_MISSING: + return "Pin Missing"; + case ERROR_DHCP_FAILED: + return "DHCP Failed"; + case ERROR_CONNECT_FAILED: + return "Connect Failed"; + } + return ""; +} + +//////////////////////////////////////////////////////////////////////////////// +// WirelessNetwork + +void WirelessNetwork::Clear() { + Network::Clear(); + name_.clear(); + strength_ = 0; + auto_connect_ = false; +} + +void WirelessNetwork::ConfigureFromService(const ServiceInfo& service) { + Network::ConfigureFromService(service); + name_ = service.name; + strength_ = service.strength; + auto_connect_ = service.auto_connect; +} + +//////////////////////////////////////////////////////////////////////////////// +// CellularNetwork + +void CellularNetwork::Clear() { + WirelessNetwork::Clear(); +} + +void CellularNetwork::ConfigureFromService(const ServiceInfo& service) { + WirelessNetwork::ConfigureFromService(service); +} + +//////////////////////////////////////////////////////////////////////////////// +// WifiNetwork + +void WifiNetwork::Clear() { + WirelessNetwork::Clear(); + encryption_ = SECURITY_NONE; + passphrase_.clear(); + identity_.clear(); + cert_path_.clear(); +} + +void WifiNetwork::ConfigureFromService(const ServiceInfo& service) { + WirelessNetwork::ConfigureFromService(service); + encryption_ = service.security; + passphrase_ = service.passphrase; + identity_ = service.identity; + cert_path_ = service.cert_path; +} + +std::string WifiNetwork::GetEncryptionString() { + switch (encryption_) { + case SECURITY_UNKNOWN: + break; + case SECURITY_NONE: + return ""; + case SECURITY_WEP: + return "WEP"; + case SECURITY_WPA: + return "WPA"; + case SECURITY_RSN: + return "RSN"; + case SECURITY_8021X: + return "8021X"; + } + return "Unknown";} + +//////////////////////////////////////////////////////////////////////////////// +// NetworkLibrary + +// static +const int NetworkLibraryImpl::kNetworkTrafficeTimerSecs = 1; + +NetworkLibraryImpl::NetworkLibraryImpl() + : traffic_type_(0), + network_status_connection_(NULL), + available_devices_(0), + enabled_devices_(0), + connected_devices_(0), + offline_mode_(false) { + if (CrosLibrary::Get()->EnsureLoaded()) { + Init(); + } + g_url_request_job_tracker.AddObserver(this); +} + +NetworkLibraryImpl::~NetworkLibraryImpl() { + if (network_status_connection_) { + DisconnectMonitorNetwork(network_status_connection_); + } + g_url_request_job_tracker.RemoveObserver(this); +} + +//////////////////////////////////////////////////////////////////////////////// +// NetworkLibraryImpl, URLRequestJobTracker::JobObserver implementation: + +void NetworkLibraryImpl::OnJobAdded(URLRequestJob* job) { + CheckNetworkTraffic(false); +} + +void NetworkLibraryImpl::OnJobRemoved(URLRequestJob* job) { + CheckNetworkTraffic(false); +} + +void NetworkLibraryImpl::OnJobDone(URLRequestJob* job, + const URLRequestStatus& status) { + CheckNetworkTraffic(false); +} + +void NetworkLibraryImpl::OnJobRedirect(URLRequestJob* job, const GURL& location, + int status_code) { + CheckNetworkTraffic(false); +} + +void NetworkLibraryImpl::OnBytesRead(URLRequestJob* job, const char* buf, + int byte_count) { + CheckNetworkTraffic(true); +} + +void NetworkLibraryImpl::AddObserver(Observer* observer) { + observers_.AddObserver(observer); +} + +void NetworkLibraryImpl::RemoveObserver(Observer* observer) { + observers_.RemoveObserver(observer); +} + +//////////////////////////////////////////////////////////////////////////////// + +bool NetworkLibraryImpl::FindWifiNetworkByPath( + const std::string& path, WifiNetwork* result) const { + const WifiNetwork* wifi = + GetWirelessNetworkByPath(wifi_networks_, path); + if (wifi) { + if (result) + *result = *wifi; + return true; + } + return false; +} + +bool NetworkLibraryImpl::FindCellularNetworkByPath( + const std::string& path, CellularNetwork* result) const { + const CellularNetwork* cellular = + GetWirelessNetworkByPath(cellular_networks_, path); + if (cellular) { + if (result) + *result = *cellular; + return true; + } + return false; +} + +void NetworkLibraryImpl::RequestWifiScan() { + if (CrosLibrary::Get()->EnsureLoaded()) { + RequestScan(TYPE_WIFI); + } +} + +bool NetworkLibraryImpl::GetWifiAccessPoints(WifiAccessPointVector* result) { + if (!CrosLibrary::Get()->EnsureLoaded()) + return false; + DeviceNetworkList* network_list = GetDeviceNetworkList(); + if (network_list == NULL) + return false; + result->clear(); + result->reserve(network_list->network_size); + const base::Time now = base::Time::Now(); + for (size_t i = 0; i < network_list->network_size; ++i) { + DCHECK(network_list->networks[i].address); + DCHECK(network_list->networks[i].name); + WifiAccessPoint ap; + ap.mac_address = network_list->networks[i].address; + ap.name = network_list->networks[i].name; + ap.timestamp = now - + base::TimeDelta::FromSeconds(network_list->networks[i].age_seconds); + ap.signal_strength = network_list->networks[i].strength; + ap.channel = network_list->networks[i].channel; + result->push_back(ap); + } + FreeDeviceNetworkList(network_list); + return true; +} + +bool NetworkLibraryImpl::ConnectToPreferredNetworkIfAvailable() { + // TODO(chocobo): Add the concept of preferred network to libcros. + // So that we don't have to hard-code Google-A here. + if (CrosLibrary::Get()->EnsureLoaded()) { + LOG(INFO) << "Attempting to auto-connect to Google wifi."; + // First force a refresh of the system info. + UpdateSystemInfo(); + + // If ethernet is connected, then don't bother. + if (ethernet_connected()) { + LOG(INFO) << "Ethernet connected, so don't need Google wifi."; + return false; + } + + WifiNetwork* wifi = GetPreferredNetwork(); + if (!wifi) { + LOG(INFO) << "Google-A/Google wifi not found or set to not auto-connect."; + return false; + } + + // Save the wifi path, so we know which one we want to auto-connect to. + const std::string wifi_path = wifi->service_path(); + + // It takes some time for the enterprise daemon to start up and populate the + // certificate and identity. So we wait at most 3 seconds here. And every + // 100ms, we refetch the system info and check the cert and identify on the + // wifi. The enterprise daemon takes between 0.4 to 0.9 seconds to setup. + bool setup = false; + for (int i = 0; i < 30; i++) { + // Update the system and refetch the network. + UpdateSystemInfo(); + wifi = GetWirelessNetworkByPath(wifi_networks_, wifi_path); + // See if identity and certpath are available. + if (wifi && !wifi->identity().empty() && !wifi->cert_path().empty()) { + LOG(INFO) << "Google wifi set up after " << (i*0.1) << " seconds."; + setup = true; + break; + } + PlatformThread::Sleep(100); + } + + if (!setup) { + LOG(INFO) << "Google wifi not set up after 3 seconds."; + return false; + } + + // Now that we have a setup Google wifi, we can connect to it. + ConnectToNetwork(wifi_path.c_str(), NULL); + return true; + } + return false; +} + +bool NetworkLibraryImpl::PreferredNetworkConnected() { + WifiNetwork* wifi = GetPreferredNetwork(); + return wifi && wifi->connected(); +} + +bool NetworkLibraryImpl::PreferredNetworkFailed() { + WifiNetwork* wifi = GetPreferredNetwork(); + return !wifi || wifi->failed(); +} + +void NetworkLibraryImpl::ConnectToWifiNetwork(WifiNetwork network, + const std::string& password, + const std::string& identity, + const std::string& certpath) { + if (CrosLibrary::Get()->EnsureLoaded()) { + ConnectToNetworkWithCertInfo(network.service_path().c_str(), + password.empty() ? NULL : password.c_str(), + identity.empty() ? NULL : identity.c_str(), + certpath.empty() ? NULL : certpath.c_str()); + } +} + +void NetworkLibraryImpl::ConnectToWifiNetwork(const std::string& ssid, + const std::string& password, + const std::string& identity, + const std::string& certpath, + bool auto_connect) { + if (CrosLibrary::Get()->EnsureLoaded()) { + // First create a service from hidden network. + ServiceInfo* service = GetWifiService(ssid.c_str(), + SECURITY_UNKNOWN); + if (service) { + // Set auto-connect. + SetAutoConnect(service->service_path, auto_connect); + // Now connect to that service. + ConnectToNetworkWithCertInfo(service->service_path, + password.empty() ? NULL : password.c_str(), + identity.empty() ? NULL : identity.c_str(), + certpath.empty() ? NULL : certpath.c_str()); + + // Clean up ServiceInfo object. + FreeServiceInfo(service); + } else { + LOG(WARNING) << "Cannot find hidden network: " << ssid; + // TODO(chocobo): Show error message. + } + } +} + +void NetworkLibraryImpl::ConnectToCellularNetwork(CellularNetwork network) { + if (CrosLibrary::Get()->EnsureLoaded()) { + ConnectToNetwork(network.service_path().c_str(), NULL); + } +} + +void NetworkLibraryImpl::DisconnectFromWirelessNetwork( + const WirelessNetwork& network) { + if (CrosLibrary::Get()->EnsureLoaded()) { + DisconnectFromNetwork(network.service_path().c_str()); + } +} + +void NetworkLibraryImpl::SaveCellularNetwork(const CellularNetwork& network) { + // Update the wifi network in the local cache. + CellularNetwork* cellular = GetWirelessNetworkByPath(cellular_networks_, + network.service_path()); + if (cellular) + *cellular = network; + + // Update the cellular network with libcros. + if (CrosLibrary::Get()->EnsureLoaded()) { + SetAutoConnect(network.service_path().c_str(), network.auto_connect()); + } +} + +void NetworkLibraryImpl::SaveWifiNetwork(const WifiNetwork& network) { + // Update the wifi network in the local cache. + WifiNetwork* wifi = GetWirelessNetworkByPath(wifi_networks_, + network.service_path()); + if (wifi) + *wifi = network; + + // Update the wifi network with libcros. + if (CrosLibrary::Get()->EnsureLoaded()) { + SetPassphrase(network.service_path().c_str(), network.passphrase().c_str()); + SetIdentity(network.service_path().c_str(), network.identity().c_str()); + SetCertPath(network.service_path().c_str(), network.cert_path().c_str()); + SetAutoConnect(network.service_path().c_str(), network.auto_connect()); + } +} + +void NetworkLibraryImpl::ForgetWirelessNetwork(const WirelessNetwork& network) { + if (CrosLibrary::Get()->EnsureLoaded()) { + DeleteRememberedService(network.service_path().c_str()); + } +} + +void NetworkLibraryImpl::EnableEthernetNetworkDevice(bool enable) { + EnableNetworkDeviceType(TYPE_ETHERNET, enable); +} + +void NetworkLibraryImpl::EnableWifiNetworkDevice(bool enable) { + EnableNetworkDeviceType(TYPE_WIFI, enable); +} + +void NetworkLibraryImpl::EnableCellularNetworkDevice(bool enable) { + EnableNetworkDeviceType(TYPE_CELLULAR, enable); +} + +void NetworkLibraryImpl::EnableOfflineMode(bool enable) { + if (!CrosLibrary::Get()->EnsureLoaded()) + return; + + // If network device is already enabled/disabled, then don't do anything. + if (enable && offline_mode_) { + LOG(INFO) << "Trying to enable offline mode when it's already enabled. "; + return; + } + if (!enable && !offline_mode_) { + LOG(INFO) << "Trying to disable offline mode when it's already disabled. "; + return; + } + + if (SetOfflineMode(enable)) { + offline_mode_ = enable; + } +} + +NetworkIPConfigVector NetworkLibraryImpl::GetIPConfigs( + const std::string& device_path) { + NetworkIPConfigVector ipconfig_vector; + if (!device_path.empty()) { + IPConfigStatus* ipconfig_status = ListIPConfigs(device_path.c_str()); + if (ipconfig_status) { + for (int i = 0; i < ipconfig_status->size; i++) { + IPConfig ipconfig = ipconfig_status->ips[i]; + ipconfig_vector.push_back( + NetworkIPConfig(device_path, ipconfig.type, ipconfig.address, + ipconfig.netmask, ipconfig.gateway, + ipconfig.name_servers)); + } + FreeIPConfigStatus(ipconfig_status); + // Sort the list of ip configs by type. + std::sort(ipconfig_vector.begin(), ipconfig_vector.end()); + } + } + return ipconfig_vector; +} + +std::string NetworkLibraryImpl::GetHtmlInfo(int refresh) { + std::string output; + output.append("<html><head><title>About Network</title>"); + if (refresh > 0) + output.append("<meta http-equiv=\"refresh\" content=\"" + + IntToString(refresh) + "\"/>"); + output.append("</head><body>"); + if (refresh > 0) + output.append("(Auto-refreshing page every " + IntToString(refresh) + "s)"); + else + output.append("(To auto-refresh this page: about:network/<secs>)"); + + output.append("<h3>Ethernet:</h3><table border=1>"); + output.append("<tr>" + ToHtmlTableHeader(ðernet_) + "</tr>"); + output.append("<tr>" + ToHtmlTableRow(ðernet_) + "</tr>"); + + output.append("</table><h3>Wifi:</h3><table border=1>"); + for (size_t i = 0; i < wifi_networks_.size(); ++i) { + if (i == 0) + output.append("<tr>" + ToHtmlTableHeader(&wifi_networks_[i]) + "</tr>"); + output.append("<tr>" + ToHtmlTableRow(&wifi_networks_[i]) + "</tr>"); + } + + output.append("</table><h3>Cellular:</h3><table border=1>"); + for (size_t i = 0; i < cellular_networks_.size(); ++i) { + if (i == 0) + output.append("<tr>" + ToHtmlTableHeader(&cellular_networks_[i]) + + "</tr>"); + output.append("<tr>" + ToHtmlTableRow(&cellular_networks_[i]) + "</tr>"); + } + + output.append("</table><h3>Remembered Wifi:</h3><table border=1>"); + for (size_t i = 0; i < remembered_wifi_networks_.size(); ++i) { + if (i == 0) + output.append("<tr>" + ToHtmlTableHeader(&remembered_wifi_networks_[i]) + + "</tr>"); + output.append("<tr>" + ToHtmlTableRow(&remembered_wifi_networks_[i]) + + "</tr>"); + } + + output.append("</table><h3>Remembered Cellular:</h3><table border=1>"); + for (size_t i = 0; i < remembered_cellular_networks_.size(); ++i) { + if (i == 0) + output.append("<tr>" + + ToHtmlTableHeader(&remembered_cellular_networks_[i]) + "</tr>"); + output.append("<tr>" + ToHtmlTableRow(&remembered_cellular_networks_[i]) + + "</tr>"); + } + + output.append("</table></body></html>"); + return output; +} + +// static +void NetworkLibraryImpl::NetworkStatusChangedHandler(void* object) { + NetworkLibraryImpl* network = static_cast<NetworkLibraryImpl*>(object); + DCHECK(network); + network->UpdateNetworkStatus(); +} + +// static +void NetworkLibraryImpl::ParseSystem(SystemInfo* system, + EthernetNetwork* ethernet, + WifiNetworkVector* wifi_networks, + CellularNetworkVector* cellular_networks, + WifiNetworkVector* remembered_wifi_networks, + CellularNetworkVector* remembered_cellular_networks) { + DLOG(INFO) << "ParseSystem:"; + ethernet->Clear(); + for (int i = 0; i < system->service_size; i++) { + const ServiceInfo& service = system->services[i]; + DLOG(INFO) << " (" << service.type << + ") " << service.name << + " mode=" << service.mode << + " state=" << service.state << + " sec=" << service.security << + " req=" << service.passphrase_required << + " pass=" << service.passphrase << + " id=" << service.identity << + " certpath=" << service.cert_path << + " str=" << service.strength << + " fav=" << service.favorite << + " auto=" << service.auto_connect << + " error=" << service.error; + // Once a connected ethernet service is found, disregard other ethernet + // services that are also found + if (service.type == TYPE_ETHERNET && !(ethernet->connected())) + ethernet->ConfigureFromService(service); + else if (service.type == TYPE_WIFI) + wifi_networks->push_back(WifiNetwork(service)); + else if (service.type == TYPE_CELLULAR) + cellular_networks->push_back(CellularNetwork(service)); + } + DLOG(INFO) << "Remembered networks:"; + for (int i = 0; i < system->remembered_service_size; i++) { + const ServiceInfo& service = system->remembered_services[i]; + // Only serices marked as auto_connect are considered remembered networks. + // TODO(chocobo): Don't add to remembered service if currently available. + if (service.auto_connect) { + DLOG(INFO) << " (" << service.type << + ") " << service.name << + " mode=" << service.mode << + " sec=" << service.security << + " pass=" << service.passphrase << + " id=" << service.identity << + " certpath=" << service.cert_path << + " auto=" << service.auto_connect; + if (service.type == TYPE_WIFI) + remembered_wifi_networks->push_back(WifiNetwork(service)); + else if (service.type == TYPE_CELLULAR) + remembered_cellular_networks->push_back(CellularNetwork(service)); + } + } +} + +void NetworkLibraryImpl::Init() { + // First, get the currently available networks. This data is cached + // on the connman side, so the call should be quick. + LOG(INFO) << "Getting initial CrOS network info."; + UpdateSystemInfo(); + + LOG(INFO) << "Registering for network status updates."; + // Now, register to receive updates on network status. + network_status_connection_ = MonitorNetwork(&NetworkStatusChangedHandler, + this); +} + +void NetworkLibraryImpl::UpdateSystemInfo() { + if (CrosLibrary::Get()->EnsureLoaded()) { + UpdateNetworkStatus(); + } +} + +WifiNetwork* NetworkLibraryImpl::GetPreferredNetwork() { + // First look for Google-A then look for Google. + // Only care if set to auto-connect. + WifiNetwork* wifi = GetWifiNetworkByName(kGoogleAWifi); + // If wifi found and set to not auto-connect, then ignore it. + if (wifi && !wifi->auto_connect()) + wifi = NULL; + + if (!wifi) { + wifi = GetWifiNetworkByName(kGoogleWifi); + // If wifi found and set to not auto-connect, then ignore it. + if (wifi && !wifi->auto_connect()) + wifi = NULL; + } + return wifi; +} + +WifiNetwork* NetworkLibraryImpl::GetWifiNetworkByName(const std::string& name) { + for (size_t i = 0; i < wifi_networks_.size(); ++i) { + if (wifi_networks_[i].name().compare(name) == 0) { + return &wifi_networks_[i]; + } + } + return NULL; +} + +template<typename T> T* NetworkLibraryImpl::GetWirelessNetworkByPath( + std::vector<T>& networks, const std::string& path) { + typedef typename std::vector<T>::iterator iter_t; + iter_t iter = std::find_if(networks.begin(), networks.end(), + WirelessNetwork::ServicePathEq(path)); + return (iter != networks.end()) ? &(*iter) : NULL; +} + +// const version +template<typename T> const T* NetworkLibraryImpl::GetWirelessNetworkByPath( + const std::vector<T>& networks, const std::string& path) const { + typedef typename std::vector<T>::const_iterator iter_t; + iter_t iter = std::find_if(networks.begin(), networks.end(), + WirelessNetwork::ServicePathEq(path)); + return (iter != networks.end()) ? &(*iter) : NULL; +} + +void NetworkLibraryImpl::EnableNetworkDeviceType(ConnectionType device, + bool enable) { + if (!CrosLibrary::Get()->EnsureLoaded()) + return; + + // If network device is already enabled/disabled, then don't do anything. + if (enable && (enabled_devices_ & (1 << device))) { + LOG(WARNING) << "Trying to enable a device that's already enabled: " + << device; + return; + } + if (!enable && !(enabled_devices_ & (1 << device))) { + LOG(WARNING) << "Trying to disable a device that's already disabled: " + << device; + return; + } + + EnableNetworkDevice(device, enable); +} + +void NetworkLibraryImpl::UpdateNetworkStatus() { + // Make sure we run on UI thread. + if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) { + ChromeThread::PostTask( + ChromeThread::UI, FROM_HERE, + NewRunnableMethod(this, + &NetworkLibraryImpl::UpdateNetworkStatus)); + return; + } + + SystemInfo* system = GetSystemInfo(); + if (!system) + return; + + wifi_networks_.clear(); + cellular_networks_.clear(); + remembered_wifi_networks_.clear(); + remembered_cellular_networks_.clear(); + ParseSystem(system, ðernet_, &wifi_networks_, &cellular_networks_, + &remembered_wifi_networks_, &remembered_cellular_networks_); + + wifi_ = WifiNetwork(); + for (size_t i = 0; i < wifi_networks_.size(); i++) { + if (wifi_networks_[i].connecting_or_connected()) { + wifi_ = wifi_networks_[i]; + break; // There is only one connected or connecting wifi network. + } + } + cellular_ = CellularNetwork(); + for (size_t i = 0; i < cellular_networks_.size(); i++) { + if (cellular_networks_[i].connecting_or_connected()) { + cellular_ = cellular_networks_[i]; + break; // There is only one connected or connecting cellular network. + } + } + + available_devices_ = system->available_technologies; + enabled_devices_ = system->enabled_technologies; + connected_devices_ = system->connected_technologies; + offline_mode_ = system->offline_mode; + + FOR_EACH_OBSERVER(Observer, observers_, NetworkChanged(this)); + FreeSystemInfo(system); +} + +void NetworkLibraryImpl::CheckNetworkTraffic(bool download) { + // If we already have a pending upload and download notification, then + // shortcut and return. + if (traffic_type_ == (Observer::TRAFFIC_DOWNLOAD | Observer::TRAFFIC_UPLOAD)) + return; + // Figure out if we are uploading and/or downloading. We are downloading + // if download == true. We are uploading if we have upload progress. + if (download) + traffic_type_ |= Observer::TRAFFIC_DOWNLOAD; + if ((traffic_type_ & Observer::TRAFFIC_UPLOAD) == 0) { + URLRequestJobTracker::JobIterator it; + for (it = g_url_request_job_tracker.begin(); + it != g_url_request_job_tracker.end(); + ++it) { + URLRequestJob* job = *it; + if (job->GetUploadProgress() > 0) { + traffic_type_ |= Observer::TRAFFIC_UPLOAD; + break; + } + } + } + // If we have new traffic data to send out and the timer is not currently + // running, then start a new timer. + if (traffic_type_ && !timer_.IsRunning()) { + timer_.Start(base::TimeDelta::FromSeconds(kNetworkTrafficeTimerSecs), this, + &NetworkLibraryImpl::NetworkTrafficTimerFired); + } +} + +void NetworkLibraryImpl:: NetworkTrafficTimerFired() { + ChromeThread::PostTask( + ChromeThread::UI, FROM_HERE, + NewRunnableMethod(this, &NetworkLibraryImpl::NotifyNetworkTraffic, + traffic_type_)); + // Reset traffic type so that we don't send the same data next time. + traffic_type_ = 0; +} + +void NetworkLibraryImpl::NotifyNetworkTraffic(int traffic_type) { + FOR_EACH_OBSERVER(Observer, observers_, NetworkTraffic(this, traffic_type)); +} + +bool NetworkLibraryImpl::Connected() const { + return ethernet_connected() || wifi_connected() || cellular_connected(); +} + +bool NetworkLibraryImpl::Connecting() const { + return ethernet_connecting() || wifi_connecting() || cellular_connecting(); +} + +const std::string& NetworkLibraryImpl::IPAddress() const { + // Returns highest priority IP address. + if (ethernet_connected()) + return ethernet_.ip_address(); + if (wifi_connected()) + return wifi_.ip_address(); + if (cellular_connected()) + return cellular_.ip_address(); + return ethernet_.ip_address(); +} + +} // namespace chromeos |