| // 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_number_conversions.h" |
| #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"; |
| case ERROR_BAD_PASSPHRASE: |
| return "Bad Passphrase"; |
| case ERROR_BAD_WEPKEY: |
| return "Bad WEP Key"; |
| } |
| return "Unknown Error"; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // 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(); |
| } else { |
| InitTestData(); |
| } |
| 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, 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 std::string& service_path) { |
| if (CrosLibrary::Get()->EnsureLoaded()) { |
| DeleteRememberedService(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=\"" + |
| base::IntToString(refresh) + "\"/>"); |
| output.append("</head><body>"); |
| if (refresh > 0) { |
| output.append("(Auto-refreshing page every " + |
| base::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::InitTestData() { |
| ethernet_.Clear(); |
| ethernet_.set_connected(true); |
| |
| wifi_networks_.clear(); |
| WifiNetwork wifi1 = WifiNetwork(); |
| wifi1.set_service_path("fw1"); |
| wifi1.set_name("Fake Wifi 1"); |
| wifi1.set_strength(90); |
| wifi1.set_connected(false); |
| wifi1.set_encryption(SECURITY_NONE); |
| wifi_networks_.push_back(wifi1); |
| |
| WifiNetwork wifi2 = WifiNetwork(); |
| wifi2.set_service_path("fw2"); |
| wifi2.set_name("Fake Wifi 2"); |
| wifi2.set_strength(70); |
| wifi2.set_connected(true); |
| wifi2.set_encryption(SECURITY_WEP); |
| wifi_networks_.push_back(wifi2); |
| |
| WifiNetwork wifi3 = WifiNetwork(); |
| wifi3.set_service_path("fw3"); |
| wifi3.set_name("Fake Wifi 3"); |
| wifi3.set_strength(50); |
| wifi3.set_connected(false); |
| wifi3.set_encryption(SECURITY_WEP); |
| wifi_networks_.push_back(wifi3); |
| |
| wifi_ = wifi2; |
| |
| cellular_networks_.clear(); |
| |
| cellular_networks_.clear(); |
| CellularNetwork cellular1 = CellularNetwork(); |
| cellular1.set_service_path("fc1"); |
| cellular1.set_name("Fake Cellular 1"); |
| cellular1.set_strength(90); |
| cellular1.set_connected(false); |
| cellular_networks_.push_back(cellular1); |
| |
| CellularNetwork cellular2 = CellularNetwork(); |
| cellular2.set_service_path("fc2"); |
| cellular2.set_name("Fake Cellular 2"); |
| cellular2.set_strength(70); |
| cellular2.set_connected(true); |
| cellular_networks_.push_back(cellular2); |
| |
| CellularNetwork cellular3 = CellularNetwork(); |
| cellular3.set_service_path("fc3"); |
| cellular3.set_name("Fake Cellular 3"); |
| cellular3.set_strength(50); |
| cellular3.set_connected(false); |
| cellular_networks_.push_back(cellular3); |
| |
| cellular_ = cellular2; |
| |
| remembered_wifi_networks_.clear(); |
| remembered_wifi_networks_.push_back(wifi2); |
| |
| remembered_cellular_networks_.clear(); |
| remembered_cellular_networks_.push_back(cellular2); |
| |
| int devices = (1 << TYPE_ETHERNET) | (1 << TYPE_WIFI) | |
| (1 << TYPE_CELLULAR); |
| available_devices_ = devices; |
| enabled_devices_ = devices; |
| connected_devices_ = devices; |
| offline_mode_ = false; |
| } |
| |
| 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 |