Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/base/network_change_notifier_win.h" | 5 #include "net/base/network_change_notifier_win.h" |
| 6 | 6 |
| 7 #include <iphlpapi.h> | 7 #include <iphlpapi.h> |
| 8 #include <winsock2.h> | 8 #include <winsock2.h> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/location.h" | 11 #include "base/location.h" |
| 12 #include "base/logging.h" | 12 #include "base/logging.h" |
| 13 #include "base/macros.h" | 13 #include "base/macros.h" |
| 14 #include "base/message_loop/message_loop.h" | 14 #include "base/message_loop/message_loop.h" |
| 15 #include "base/metrics/histogram_macros.h" | 15 #include "base/metrics/histogram_macros.h" |
| 16 #include "base/single_thread_task_runner.h" | 16 #include "base/single_thread_task_runner.h" |
| 17 #include "base/task_runner_util.h" | |
| 17 #include "base/threading/thread.h" | 18 #include "base/threading/thread.h" |
| 18 #include "base/threading/thread_task_runner_handle.h" | 19 #include "base/threading/thread_task_runner_handle.h" |
| 19 #include "base/time/time.h" | 20 #include "base/time/time.h" |
| 20 #include "net/base/winsock_init.h" | 21 #include "net/base/winsock_init.h" |
| 21 #include "net/base/winsock_util.h" | 22 #include "net/base/winsock_util.h" |
| 22 #include "net/dns/dns_config_service.h" | 23 #include "net/dns/dns_config_service.h" |
| 23 | 24 |
| 24 namespace net { | 25 namespace net { |
| 25 | 26 |
| 26 namespace { | 27 namespace { |
| 27 | 28 |
| 28 // Time between NotifyAddrChange retries, on failure. | 29 // Time between NotifyAddrChange retries, on failure. |
| 29 const int kWatchForAddressChangeRetryIntervalMs = 500; | 30 const int kWatchForAddressChangeRetryIntervalMs = 500; |
| 30 | 31 |
| 31 } // namespace | |
| 32 | |
| 33 // Thread on which we can run DnsConfigService, which requires AssertIOAllowed | |
| 34 // to open registry keys and to handle FilePathWatcher updates. | |
| 35 class NetworkChangeNotifierWin::DnsConfigServiceThread : public base::Thread { | |
| 36 public: | |
| 37 DnsConfigServiceThread() : base::Thread("DnsConfigService") {} | |
| 38 | |
| 39 ~DnsConfigServiceThread() override { Stop(); } | |
| 40 | |
| 41 void Init() override { | |
| 42 service_ = DnsConfigService::CreateSystemService(); | |
| 43 service_->WatchConfig(base::Bind(&NetworkChangeNotifier::SetDnsConfig)); | |
| 44 } | |
| 45 | |
| 46 void CleanUp() override { service_.reset(); } | |
| 47 | |
| 48 private: | |
| 49 std::unique_ptr<DnsConfigService> service_; | |
| 50 | |
| 51 DISALLOW_COPY_AND_ASSIGN(DnsConfigServiceThread); | |
| 52 }; | |
| 53 | |
| 54 NetworkChangeNotifierWin::NetworkChangeNotifierWin() | |
| 55 : NetworkChangeNotifier(NetworkChangeCalculatorParamsWin()), | |
| 56 is_watching_(false), | |
| 57 sequential_failures_(0), | |
| 58 dns_config_service_thread_(new DnsConfigServiceThread()), | |
| 59 last_computed_connection_type_(RecomputeCurrentConnectionType()), | |
| 60 last_announced_offline_(last_computed_connection_type_ == | |
| 61 CONNECTION_NONE), | |
| 62 weak_factory_(this) { | |
| 63 memset(&addr_overlapped_, 0, sizeof addr_overlapped_); | |
| 64 addr_overlapped_.hEvent = WSACreateEvent(); | |
| 65 } | |
| 66 | |
| 67 NetworkChangeNotifierWin::~NetworkChangeNotifierWin() { | |
| 68 if (is_watching_) { | |
| 69 CancelIPChangeNotify(&addr_overlapped_); | |
| 70 addr_watcher_.StopWatching(); | |
| 71 } | |
| 72 WSACloseEvent(addr_overlapped_.hEvent); | |
| 73 } | |
| 74 | |
| 75 // static | |
| 76 NetworkChangeNotifier::NetworkChangeCalculatorParams | |
| 77 NetworkChangeNotifierWin::NetworkChangeCalculatorParamsWin() { | |
| 78 NetworkChangeCalculatorParams params; | |
| 79 // Delay values arrived at by simple experimentation and adjusted so as to | |
| 80 // produce a single signal when switching between network connections. | |
| 81 params.ip_address_offline_delay_ = base::TimeDelta::FromMilliseconds(1500); | |
| 82 params.ip_address_online_delay_ = base::TimeDelta::FromMilliseconds(1500); | |
| 83 params.connection_type_offline_delay_ = | |
| 84 base::TimeDelta::FromMilliseconds(1500); | |
| 85 params.connection_type_online_delay_ = base::TimeDelta::FromMilliseconds(500); | |
| 86 return params; | |
| 87 } | |
| 88 | |
| 89 // This implementation does not return the actual connection type but merely | 32 // This implementation does not return the actual connection type but merely |
| 90 // determines if the user is "online" (in which case it returns | 33 // determines if the user is "online" (in which case it returns |
| 91 // CONNECTION_UNKNOWN) or "offline" (and then it returns CONNECTION_NONE). | 34 // CONNECTION_UNKNOWN) or "offline" (and then it returns CONNECTION_NONE). |
| 92 // This is challenging since the only thing we can test with certainty is | 35 // This is challenging since the only thing we can test with certainty is |
| 93 // whether a *particular* host is reachable. | 36 // whether a *particular* host is reachable. |
| 94 // | 37 // |
| 95 // While we can't conclusively determine when a user is "online", we can at | 38 // While we can't conclusively determine when a user is "online", we can at |
| 96 // least reliably recognize some of the situtations when they are clearly | 39 // least reliably recognize some of the situtations when they are clearly |
| 97 // "offline". For example, if the user's laptop is not plugged into an ethernet | 40 // "offline". For example, if the user's laptop is not plugged into an ethernet |
| 98 // network and is not connected to any wireless networks, it must be offline. | 41 // network and is not connected to any wireless networks, it must be offline. |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 127 // workstation. Here is what I found: | 70 // workstation. Here is what I found: |
| 128 // * Approach (1) was pretty much zero-cost after the initial call. | 71 // * Approach (1) was pretty much zero-cost after the initial call. |
| 129 // * Approach (2) took an average of 3.25 milliseconds to enumerate the | 72 // * Approach (2) took an average of 3.25 milliseconds to enumerate the |
| 130 // adapters. | 73 // adapters. |
| 131 // * Approach (3) took an average of 0.8 ms to enumerate the providers. | 74 // * Approach (3) took an average of 0.8 ms to enumerate the providers. |
| 132 // | 75 // |
| 133 // In terms of correctness, all three approaches were comparable for the simple | 76 // In terms of correctness, all three approaches were comparable for the simple |
| 134 // experiments I ran... However none of them correctly returned "offline" when | 77 // experiments I ran... However none of them correctly returned "offline" when |
| 135 // executing 'ipconfig /release'. | 78 // executing 'ipconfig /release'. |
| 136 // | 79 // |
| 137 NetworkChangeNotifier::ConnectionType | 80 // It is not thread safe, see crbug.com/324913. |
| 138 NetworkChangeNotifierWin::RecomputeCurrentConnectionType() const { | 81 NetworkChangeNotifier::ConnectionType RecomputeCurrentConnectionType() { |
| 139 DCHECK(CalledOnValidThread()); | |
| 140 | |
| 141 EnsureWinsockInit(); | 82 EnsureWinsockInit(); |
| 142 | 83 |
| 143 // The following code was adapted from: | 84 // The following code was adapted from: |
| 144 // http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/net/notifier/ base/win/async_network_alive_win32.cc?view=markup&pathrev=47343 | 85 // http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/net/notifier/ base/win/async_network_alive_win32.cc?view=markup&pathrev=47343 |
| 145 // The main difference is we only call WSALookupServiceNext once, whereas | 86 // The main difference is we only call WSALookupServiceNext once, whereas |
| 146 // the earlier code would traverse the entire list and pass LUP_FLUSHPREVIOUS | 87 // the earlier code would traverse the entire list and pass LUP_FLUSHPREVIOUS |
| 147 // to skip past the large results. | 88 // to skip past the large results. |
| 148 | 89 |
| 149 HANDLE ws_handle; | 90 HANDLE ws_handle; |
| 150 WSAQUERYSET query_set = {0}; | 91 WSAQUERYSET query_set = {0}; |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 194 } else { | 135 } else { |
| 195 LOG(WARNING) << "WSALookupServiceNext() failed with:" << result; | 136 LOG(WARNING) << "WSALookupServiceNext() failed with:" << result; |
| 196 } | 137 } |
| 197 } | 138 } |
| 198 | 139 |
| 199 result = WSALookupServiceEnd(ws_handle); | 140 result = WSALookupServiceEnd(ws_handle); |
| 200 LOG_IF(ERROR, result != 0) | 141 LOG_IF(ERROR, result != 0) |
| 201 << "WSALookupServiceEnd() failed with: " << result; | 142 << "WSALookupServiceEnd() failed with: " << result; |
| 202 | 143 |
| 203 // TODO(droger): Return something more detailed than CONNECTION_UNKNOWN. | 144 // TODO(droger): Return something more detailed than CONNECTION_UNKNOWN. |
| 204 return found_connection ? ConnectionTypeFromInterfaces() | 145 return found_connection |
| 205 : NetworkChangeNotifier::CONNECTION_NONE; | 146 ? NetworkChangeNotifier::ConnectionTypeFromInterfaces() |
| 147 : NetworkChangeNotifier::CONNECTION_NONE; | |
| 148 } | |
| 149 | |
| 150 } // namespace | |
| 151 | |
| 152 // Thread on which we can run DnsConfigService, which requires AssertIOAllowed | |
| 153 // to open registry keys and to handle FilePathWatcher updates. | |
| 154 class NetworkChangeNotifierWin::DnsConfigServiceThread : public base::Thread { | |
| 155 public: | |
| 156 DnsConfigServiceThread() : base::Thread("DnsConfigService") {} | |
| 157 | |
| 158 ~DnsConfigServiceThread() override { Stop(); } | |
| 159 | |
| 160 void Init() override { | |
| 161 service_ = DnsConfigService::CreateSystemService(); | |
| 162 service_->WatchConfig(base::Bind(&NetworkChangeNotifier::SetDnsConfig)); | |
| 163 } | |
| 164 | |
| 165 void CleanUp() override { service_.reset(); } | |
| 166 | |
| 167 private: | |
| 168 std::unique_ptr<DnsConfigService> service_; | |
| 169 | |
| 170 DISALLOW_COPY_AND_ASSIGN(DnsConfigServiceThread); | |
| 171 }; | |
| 172 | |
| 173 NetworkChangeNotifierWin::NetworkChangeNotifierWin() | |
| 174 : NetworkChangeNotifier(NetworkChangeCalculatorParamsWin()), | |
| 175 is_watching_(false), | |
| 176 sequential_failures_(0), | |
| 177 dns_config_service_thread_(new DnsConfigServiceThread()), | |
| 178 last_computed_connection_type_(RecomputeCurrentConnectionType()), | |
| 179 last_announced_offline_(last_computed_connection_type_ == | |
| 180 CONNECTION_NONE), | |
| 181 calculate_connection_type_( | |
| 182 base::BindRepeating(&RecomputeCurrentConnectionType)), | |
| 183 weak_factory_(this) { | |
| 184 memset(&addr_overlapped_, 0, sizeof addr_overlapped_); | |
| 185 addr_overlapped_.hEvent = WSACreateEvent(); | |
| 186 } | |
| 187 | |
| 188 NetworkChangeNotifierWin::~NetworkChangeNotifierWin() { | |
| 189 if (is_watching_) { | |
| 190 CancelIPChangeNotify(&addr_overlapped_); | |
| 191 addr_watcher_.StopWatching(); | |
| 192 } | |
| 193 WSACloseEvent(addr_overlapped_.hEvent); | |
| 194 } | |
| 195 | |
| 196 // static | |
| 197 NetworkChangeNotifier::NetworkChangeCalculatorParams | |
| 198 NetworkChangeNotifierWin::NetworkChangeCalculatorParamsWin() { | |
| 199 NetworkChangeCalculatorParams params; | |
| 200 // Delay values arrived at by simple experimentation and adjusted so as to | |
| 201 // produce a single signal when switching between network connections. | |
| 202 params.ip_address_offline_delay_ = base::TimeDelta::FromMilliseconds(1500); | |
| 203 params.ip_address_online_delay_ = base::TimeDelta::FromMilliseconds(1500); | |
| 204 params.connection_type_offline_delay_ = | |
| 205 base::TimeDelta::FromMilliseconds(1500); | |
| 206 params.connection_type_online_delay_ = base::TimeDelta::FromMilliseconds(500); | |
| 207 return params; | |
| 206 } | 208 } |
| 207 | 209 |
| 208 NetworkChangeNotifier::ConnectionType | 210 NetworkChangeNotifier::ConnectionType |
| 209 NetworkChangeNotifierWin::GetCurrentConnectionType() const { | 211 NetworkChangeNotifierWin::GetCurrentConnectionType() const { |
| 210 base::AutoLock auto_lock(last_computed_connection_type_lock_); | 212 base::AutoLock auto_lock(last_computed_connection_type_lock_); |
| 211 return last_computed_connection_type_; | 213 return last_computed_connection_type_; |
| 212 } | 214 } |
| 213 | 215 |
| 214 void NetworkChangeNotifierWin::SetCurrentConnectionType( | 216 void NetworkChangeNotifierWin::SetCurrentConnectionType( |
| 215 ConnectionType connection_type) { | 217 ConnectionType connection_type) { |
| 216 base::AutoLock auto_lock(last_computed_connection_type_lock_); | 218 base::AutoLock auto_lock(last_computed_connection_type_lock_); |
| 217 last_computed_connection_type_ = connection_type; | 219 last_computed_connection_type_ = connection_type; |
| 218 } | 220 } |
| 219 | 221 |
| 220 void NetworkChangeNotifierWin::OnObjectSignaled(HANDLE object) { | 222 void NetworkChangeNotifierWin::OnObjectSignaled(HANDLE object) { |
| 221 DCHECK(CalledOnValidThread()); | 223 DCHECK(CalledOnValidThread()); |
| 222 DCHECK(is_watching_); | 224 DCHECK(is_watching_); |
| 223 is_watching_ = false; | 225 is_watching_ = false; |
| 224 | 226 |
| 225 // Start watching for the next address change. | 227 // Start watching for the next address change. |
| 226 WatchForAddressChange(); | 228 WatchForAddressChange(); |
| 229 DCHECK(dns_task_runner_); | |
| 227 | 230 |
| 228 NotifyObservers(); | 231 base::PostTaskAndReplyWithResult( |
| 232 dns_task_runner_.get(), FROM_HERE, calculate_connection_type_, | |
| 233 base::Bind(&NetworkChangeNotifierWin::NotifyObservers, | |
| 234 weak_factory_.GetWeakPtr())); | |
| 229 } | 235 } |
| 230 | 236 |
| 231 void NetworkChangeNotifierWin::NotifyObservers() { | 237 void NetworkChangeNotifierWin::NotifyObservers(ConnectionType connection_type) { |
| 232 DCHECK(CalledOnValidThread()); | 238 DCHECK(CalledOnValidThread()); |
| 233 SetCurrentConnectionType(RecomputeCurrentConnectionType()); | 239 SetCurrentConnectionType(connection_type); |
| 234 NotifyObserversOfIPAddressChange(); | 240 NotifyObserversOfIPAddressChange(); |
| 235 | 241 |
| 236 // Calling GetConnectionType() at this very moment is likely to give | 242 // Calling GetConnectionType() at this very moment is likely to give |
| 237 // the wrong result, so we delay that until a little bit later. | 243 // the wrong result, so we delay that until a little bit later. |
| 238 // | 244 // |
| 239 // The one second delay chosen here was determined experimentally | 245 // The one second delay chosen here was determined experimentally |
| 240 // by adamk on Windows 7. | 246 // by adamk on Windows 7. |
| 241 // If after one second we determine we are still offline, we will | 247 // If after one second we determine we are still offline, we will |
| 242 // delay again. | 248 // delay again. |
| 243 offline_polls_ = 0; | 249 offline_polls_ = 0; |
| 250 // TODO(jkarlin): I'm not sure that calling with 'this' is safe. Can it be | |
| 251 // deleted? | |
| 244 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(1), this, | 252 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(1), this, |
| 245 &NetworkChangeNotifierWin::NotifyParentOfConnectionTypeChange); | 253 &NetworkChangeNotifierWin::NotifyParentOfConnectionTypeChange); |
| 246 } | 254 } |
| 247 | 255 |
| 248 void NetworkChangeNotifierWin::WatchForAddressChange() { | 256 void NetworkChangeNotifierWin::WatchForAddressChange() { |
| 249 DCHECK(CalledOnValidThread()); | 257 DCHECK(CalledOnValidThread()); |
| 250 DCHECK(!is_watching_); | 258 DCHECK(!is_watching_); |
| 251 | 259 |
| 252 // NotifyAddrChange occasionally fails with ERROR_OPEN_FAILED for unknown | 260 // NotifyAddrChange occasionally fails with ERROR_OPEN_FAILED for unknown |
| 253 // reasons. More rarely, it's also been observed failing with | 261 // reasons. More rarely, it's also been observed failing with |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 267 FROM_HERE, base::Bind(&NetworkChangeNotifierWin::WatchForAddressChange, | 275 FROM_HERE, base::Bind(&NetworkChangeNotifierWin::WatchForAddressChange, |
| 268 weak_factory_.GetWeakPtr()), | 276 weak_factory_.GetWeakPtr()), |
| 269 base::TimeDelta::FromMilliseconds( | 277 base::TimeDelta::FromMilliseconds( |
| 270 kWatchForAddressChangeRetryIntervalMs)); | 278 kWatchForAddressChangeRetryIntervalMs)); |
| 271 return; | 279 return; |
| 272 } | 280 } |
| 273 | 281 |
| 274 // Treat the transition from NotifyAddrChange failing to succeeding as a | 282 // Treat the transition from NotifyAddrChange failing to succeeding as a |
| 275 // network change event, since network changes were not being observed in | 283 // network change event, since network changes were not being observed in |
| 276 // that interval. | 284 // that interval. |
| 277 if (sequential_failures_ > 0) | 285 if (sequential_failures_ > 0) { |
| 278 NotifyObservers(); | 286 base::PostTaskAndReplyWithResult( |
| 287 dns_task_runner_.get(), FROM_HERE, calculate_connection_type_, | |
| 288 base::Bind(&NetworkChangeNotifierWin::NotifyObservers, | |
| 289 weak_factory_.GetWeakPtr())); | |
| 290 } | |
| 279 | 291 |
| 280 if (sequential_failures_ < 2000) { | 292 if (sequential_failures_ < 2000) { |
| 281 UMA_HISTOGRAM_COUNTS_10000("Net.NotifyAddrChangeFailures", | 293 UMA_HISTOGRAM_COUNTS_10000("Net.NotifyAddrChangeFailures", |
| 282 sequential_failures_); | 294 sequential_failures_); |
| 283 } | 295 } |
| 284 | 296 |
| 285 is_watching_ = true; | 297 is_watching_ = true; |
| 286 sequential_failures_ = 0; | 298 sequential_failures_ = 0; |
| 287 } | 299 } |
| 288 | 300 |
| 289 bool NetworkChangeNotifierWin::WatchForAddressChangeInternal() { | 301 bool NetworkChangeNotifierWin::WatchForAddressChangeInternal() { |
| 290 DCHECK(CalledOnValidThread()); | 302 DCHECK(CalledOnValidThread()); |
| 291 | 303 |
| 292 if (!dns_config_service_thread_->IsRunning()) { | 304 if (!dns_config_service_thread_->IsRunning()) { |
| 293 dns_config_service_thread_->StartWithOptions( | 305 dns_config_service_thread_->StartWithOptions( |
| 294 base::Thread::Options(base::MessageLoop::TYPE_IO, 0)); | 306 base::Thread::Options(base::MessageLoop::TYPE_IO, 0)); |
| 307 if (!dns_task_runner_) | |
| 308 dns_task_runner_ = | |
| 309 dns_config_service_thread_->message_loop()->task_runner(); | |
| 295 } | 310 } |
| 296 | 311 |
| 297 ResetEventIfSignaled(addr_overlapped_.hEvent); | 312 ResetEventIfSignaled(addr_overlapped_.hEvent); |
| 298 HANDLE handle = NULL; | 313 HANDLE handle = NULL; |
| 299 DWORD ret = NotifyAddrChange(&handle, &addr_overlapped_); | 314 DWORD ret = NotifyAddrChange(&handle, &addr_overlapped_); |
| 300 if (ret != ERROR_IO_PENDING) | 315 if (ret != ERROR_IO_PENDING) |
| 301 return false; | 316 return false; |
| 302 | 317 |
| 303 addr_watcher_.StartWatchingOnce(addr_overlapped_.hEvent, this); | 318 addr_watcher_.StartWatchingOnce(addr_overlapped_.hEvent, this); |
| 304 return true; | 319 return true; |
| 305 } | 320 } |
| 306 | 321 |
| 307 void NetworkChangeNotifierWin::NotifyParentOfConnectionTypeChange() { | 322 void NetworkChangeNotifierWin::NotifyParentOfConnectionTypeChange() { |
| 308 SetCurrentConnectionType(RecomputeCurrentConnectionType()); | 323 base::PostTaskAndReplyWithResult( |
| 324 dns_task_runner_.get(), FROM_HERE, calculate_connection_type_, | |
| 325 base::Bind( | |
| 326 &NetworkChangeNotifierWin::NotifyParentOfConnectionTypeChangeImpl, | |
| 327 weak_factory_.GetWeakPtr())); | |
| 328 } | |
| 329 | |
| 330 void NetworkChangeNotifierWin::NotifyParentOfConnectionTypeChangeImpl( | |
| 331 ConnectionType connection_type) { | |
| 332 SetCurrentConnectionType(connection_type); | |
| 309 bool current_offline = IsOffline(); | 333 bool current_offline = IsOffline(); |
| 310 offline_polls_++; | 334 offline_polls_++; |
| 311 // If we continue to appear offline, delay sending out the notification in | 335 // If we continue to appear offline, delay sending out the notification in |
| 312 // case we appear to go online within 20 seconds. UMA histogram data shows | 336 // case we appear to go online within 20 seconds. UMA histogram data shows |
| 313 // we may not detect the transition to online state after 1 second but within | 337 // we may not detect the transition to online state after 1 second but within |
| 314 // 20 seconds we generally do. | 338 // 20 seconds we generally do. |
| 315 if (last_announced_offline_ && current_offline && offline_polls_ <= 20) { | 339 if (last_announced_offline_ && current_offline && offline_polls_ <= 20) { |
| 316 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(1), this, | 340 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(1), this, |
| 317 &NetworkChangeNotifierWin::NotifyParentOfConnectionTypeChange); | 341 &NetworkChangeNotifierWin::NotifyParentOfConnectionTypeChange); |
| 318 return; | 342 return; |
| 319 } | 343 } |
| 320 if (last_announced_offline_) | 344 if (last_announced_offline_) |
| 321 UMA_HISTOGRAM_CUSTOM_COUNTS("NCN.OfflinePolls", offline_polls_, 1, 50, 50); | 345 UMA_HISTOGRAM_CUSTOM_COUNTS("NCN.OfflinePolls", offline_polls_, 1, 50, 50); |
| 322 last_announced_offline_ = current_offline; | 346 last_announced_offline_ = current_offline; |
| 323 | 347 |
| 324 NotifyObserversOfConnectionTypeChange(); | 348 NotifyObserversOfConnectionTypeChange(); |
| 325 double max_bandwidth_mbps = 0.0; | 349 double max_bandwidth_mbps = 0.0; |
| 326 ConnectionType connection_type = CONNECTION_NONE; | 350 ConnectionType connection_type2 = CONNECTION_NONE; |
|
pauljensen
2017/05/22 18:01:51
can we give this variable a more descriptive name?
jkarlin
2017/05/23 11:44:38
Done.
| |
| 327 GetCurrentMaxBandwidthAndConnectionType(&max_bandwidth_mbps, | 351 GetCurrentMaxBandwidthAndConnectionType(&max_bandwidth_mbps, |
| 328 &connection_type); | 352 &connection_type2); |
| 329 NotifyObserversOfMaxBandwidthChange(max_bandwidth_mbps, connection_type); | 353 NotifyObserversOfMaxBandwidthChange(max_bandwidth_mbps, connection_type2); |
| 330 } | 354 } |
| 331 | 355 |
| 332 } // namespace net | 356 } // namespace net |
| OLD | NEW |