Only send _NET_ACTIVE_WINDOW hint if the chromium window is not already active.
[chromium-blink-merge.git] / chromeos / network / network_connection_handler.cc
blobe8c49396ba43b295dd1b3b19259b8d0cb5c92a66
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chromeos/network/network_connection_handler.h"
7 #include "base/bind.h"
8 #include "base/json/json_reader.h"
9 #include "base/location.h"
10 #include "base/single_thread_task_runner.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/thread_task_runner_handle.h"
13 #include "chromeos/dbus/dbus_thread_manager.h"
14 #include "chromeos/dbus/shill_manager_client.h"
15 #include "chromeos/dbus/shill_service_client.h"
16 #include "chromeos/network/certificate_pattern.h"
17 #include "chromeos/network/client_cert_resolver.h"
18 #include "chromeos/network/client_cert_util.h"
19 #include "chromeos/network/managed_network_configuration_handler.h"
20 #include "chromeos/network/network_configuration_handler.h"
21 #include "chromeos/network/network_event_log.h"
22 #include "chromeos/network/network_profile_handler.h"
23 #include "chromeos/network/network_state.h"
24 #include "chromeos/network/network_state_handler.h"
25 #include "chromeos/network/shill_property_util.h"
26 #include "dbus/object_path.h"
27 #include "net/cert/x509_certificate.h"
28 #include "third_party/cros_system_api/dbus/service_constants.h"
30 namespace chromeos {
32 namespace {
34 bool IsAuthenticationError(const std::string& error) {
35 return (error == shill::kErrorBadWEPKey ||
36 error == shill::kErrorPppAuthFailed ||
37 error == shill::kErrorEapLocalTlsFailed ||
38 error == shill::kErrorEapRemoteTlsFailed ||
39 error == shill::kErrorEapAuthenticationFailed);
42 bool VPNRequiresCredentials(const std::string& service_path,
43 const std::string& provider_type,
44 const base::DictionaryValue& provider_properties) {
45 if (provider_type == shill::kProviderOpenVpn) {
46 std::string username;
47 provider_properties.GetStringWithoutPathExpansion(
48 shill::kOpenVPNUserProperty, &username);
49 if (username.empty()) {
50 NET_LOG_EVENT("OpenVPN: No username", service_path);
51 return true;
53 bool passphrase_required = false;
54 provider_properties.GetBooleanWithoutPathExpansion(
55 shill::kPassphraseRequiredProperty, &passphrase_required);
56 if (passphrase_required) {
57 NET_LOG_EVENT("OpenVPN: Passphrase Required", service_path);
58 return true;
60 NET_LOG_EVENT("OpenVPN Is Configured", service_path);
61 } else {
62 bool passphrase_required = false;
63 provider_properties.GetBooleanWithoutPathExpansion(
64 shill::kL2tpIpsecPskRequiredProperty, &passphrase_required);
65 if (passphrase_required) {
66 NET_LOG_EVENT("VPN: PSK Required", service_path);
67 return true;
69 provider_properties.GetBooleanWithoutPathExpansion(
70 shill::kPassphraseRequiredProperty, &passphrase_required);
71 if (passphrase_required) {
72 NET_LOG_EVENT("VPN: Passphrase Required", service_path);
73 return true;
75 NET_LOG_EVENT("VPN Is Configured", service_path);
77 return false;
80 std::string GetDefaultUserProfilePath(const NetworkState* network) {
81 if (!NetworkHandler::IsInitialized() ||
82 (LoginState::IsInitialized() &&
83 !LoginState::Get()->UserHasNetworkProfile()) ||
84 (network && network->type() == shill::kTypeWifi &&
85 network->security_class() == shill::kSecurityNone)) {
86 return NetworkProfileHandler::GetSharedProfilePath();
88 const NetworkProfile* profile =
89 NetworkHandler::Get()->network_profile_handler()->GetDefaultUserProfile();
90 return profile ? profile->path
91 : NetworkProfileHandler::GetSharedProfilePath();
94 } // namespace
96 const char NetworkConnectionHandler::kErrorNotFound[] = "not-found";
97 const char NetworkConnectionHandler::kErrorConnected[] = "connected";
98 const char NetworkConnectionHandler::kErrorConnecting[] = "connecting";
99 const char NetworkConnectionHandler::kErrorNotConnected[] = "not-connected";
100 const char NetworkConnectionHandler::kErrorPassphraseRequired[] =
101 "passphrase-required";
102 const char NetworkConnectionHandler::kErrorBadPassphrase[] = "bad-passphrase";
103 const char NetworkConnectionHandler::kErrorCertificateRequired[] =
104 "certificate-required";
105 const char NetworkConnectionHandler::kErrorConfigurationRequired[] =
106 "configuration-required";
107 const char NetworkConnectionHandler::kErrorAuthenticationRequired[] =
108 "authentication-required";
109 const char NetworkConnectionHandler::kErrorConnectFailed[] = "connect-failed";
110 const char NetworkConnectionHandler::kErrorDisconnectFailed[] =
111 "disconnect-failed";
112 const char NetworkConnectionHandler::kErrorConfigureFailed[] =
113 "configure-failed";
114 const char NetworkConnectionHandler::kErrorConnectCanceled[] =
115 "connect-canceled";
116 const char NetworkConnectionHandler::kErrorCertLoadTimeout[] =
117 "cert-load-timeout";
119 struct NetworkConnectionHandler::ConnectRequest {
120 ConnectRequest(const std::string& service_path,
121 const std::string& profile_path,
122 const base::Closure& success,
123 const network_handler::ErrorCallback& error)
124 : service_path(service_path),
125 profile_path(profile_path),
126 connect_state(CONNECT_REQUESTED),
127 success_callback(success),
128 error_callback(error) {
130 enum ConnectState {
131 CONNECT_REQUESTED = 0,
132 CONNECT_STARTED = 1,
133 CONNECT_CONNECTING = 2
135 std::string service_path;
136 std::string profile_path;
137 ConnectState connect_state;
138 base::Closure success_callback;
139 network_handler::ErrorCallback error_callback;
142 NetworkConnectionHandler::NetworkConnectionHandler()
143 : cert_loader_(NULL),
144 network_state_handler_(NULL),
145 configuration_handler_(NULL),
146 logged_in_(false),
147 certificates_loaded_(false) {
150 NetworkConnectionHandler::~NetworkConnectionHandler() {
151 if (network_state_handler_)
152 network_state_handler_->RemoveObserver(this, FROM_HERE);
153 if (cert_loader_)
154 cert_loader_->RemoveObserver(this);
155 if (LoginState::IsInitialized())
156 LoginState::Get()->RemoveObserver(this);
159 void NetworkConnectionHandler::Init(
160 NetworkStateHandler* network_state_handler,
161 NetworkConfigurationHandler* network_configuration_handler,
162 ManagedNetworkConfigurationHandler* managed_network_configuration_handler) {
163 if (LoginState::IsInitialized())
164 LoginState::Get()->AddObserver(this);
166 if (CertLoader::IsInitialized()) {
167 cert_loader_ = CertLoader::Get();
168 cert_loader_->AddObserver(this);
169 if (cert_loader_->certificates_loaded()) {
170 NET_LOG_EVENT("Certificates Loaded", "");
171 certificates_loaded_ = true;
173 } else {
174 // TODO(tbarzic): Require a mock or stub cert_loader in tests.
175 NET_LOG_EVENT("Certificate Loader not initialized", "");
176 certificates_loaded_ = true;
179 if (network_state_handler) {
180 network_state_handler_ = network_state_handler;
181 network_state_handler_->AddObserver(this, FROM_HERE);
183 configuration_handler_ = network_configuration_handler;
184 managed_configuration_handler_ = managed_network_configuration_handler;
186 // After this point, the NetworkConnectionHandler is fully initialized (all
187 // handler references set, observers registered, ...).
189 if (LoginState::IsInitialized())
190 LoggedInStateChanged();
193 void NetworkConnectionHandler::AddObserver(
194 NetworkConnectionObserver* observer) {
195 observers_.AddObserver(observer);
198 void NetworkConnectionHandler::RemoveObserver(
199 NetworkConnectionObserver* observer) {
200 observers_.RemoveObserver(observer);
203 void NetworkConnectionHandler::LoggedInStateChanged() {
204 LoginState* login_state = LoginState::Get();
205 if (logged_in_ || !login_state->IsUserLoggedIn())
206 return;
208 logged_in_ = true;
209 logged_in_time_ = base::TimeTicks::Now();
212 void NetworkConnectionHandler::OnCertificatesLoaded(
213 const net::CertificateList& cert_list,
214 bool initial_load) {
215 certificates_loaded_ = true;
216 NET_LOG_EVENT("Certificates Loaded", "");
217 if (queued_connect_)
218 ConnectToQueuedNetwork();
221 void NetworkConnectionHandler::ConnectToNetwork(
222 const std::string& service_path,
223 const base::Closure& success_callback,
224 const network_handler::ErrorCallback& error_callback,
225 bool check_error_state) {
226 NET_LOG_USER("ConnectToNetwork", service_path);
227 FOR_EACH_OBSERVER(NetworkConnectionObserver, observers_,
228 ConnectToNetworkRequested(service_path));
230 // Clear any existing queued connect request.
231 queued_connect_.reset();
232 if (HasConnectingNetwork(service_path)) {
233 NET_LOG_USER("Connect Request While Pending", service_path);
234 InvokeConnectErrorCallback(service_path, error_callback, kErrorConnecting);
235 return;
238 // Check cached network state for connected, connecting, or unactivated
239 // networks. These states will not be affected by a recent configuration.
240 // Note: NetworkState may not exist for a network that was recently
241 // configured, in which case these checks do not apply anyway.
242 const NetworkState* network =
243 network_state_handler_->GetNetworkState(service_path);
245 if (network) {
246 // For existing networks, perform some immediate consistency checks.
247 if (network->IsConnectedState()) {
248 InvokeConnectErrorCallback(service_path, error_callback, kErrorConnected);
249 return;
251 if (network->IsConnectingState()) {
252 InvokeConnectErrorCallback(service_path, error_callback,
253 kErrorConnecting);
254 return;
257 if (check_error_state) {
258 const std::string& error = network->last_error();
259 if (error == shill::kErrorBadPassphrase) {
260 InvokeConnectErrorCallback(service_path, error_callback,
261 kErrorBadPassphrase);
262 return;
264 if (IsAuthenticationError(error)) {
265 InvokeConnectErrorCallback(service_path, error_callback,
266 kErrorAuthenticationRequired);
267 return;
272 // If the network does not have a profile path, specify the correct default
273 // profile here and set it once connected. Otherwise leave it empty to
274 // indicate that it does not need to be set.
275 std::string profile_path;
276 if (!network || network->profile_path().empty())
277 profile_path = GetDefaultUserProfilePath(network);
279 // All synchronous checks passed, add |service_path| to connecting list.
280 pending_requests_.insert(std::make_pair(
281 service_path,
282 ConnectRequest(service_path, profile_path,
283 success_callback, error_callback)));
285 // Connect immediately to 'connectable' networks.
286 // TODO(stevenjb): Shill needs to properly set Connectable for VPN.
287 if (network && network->connectable() && network->type() != shill::kTypeVPN) {
288 CallShillConnect(service_path);
289 return;
292 // Request additional properties to check. VerifyConfiguredAndConnect will
293 // use only these properties, not cached properties, to ensure that they
294 // are up to date after any recent configuration.
295 configuration_handler_->GetShillProperties(
296 service_path,
297 base::Bind(&NetworkConnectionHandler::VerifyConfiguredAndConnect,
298 AsWeakPtr(), check_error_state),
299 base::Bind(&NetworkConnectionHandler::HandleConfigurationFailure,
300 AsWeakPtr(), service_path));
303 void NetworkConnectionHandler::DisconnectNetwork(
304 const std::string& service_path,
305 const base::Closure& success_callback,
306 const network_handler::ErrorCallback& error_callback) {
307 NET_LOG_USER("DisconnectNetwork", service_path);
308 FOR_EACH_OBSERVER(NetworkConnectionObserver, observers_,
309 DisconnectRequested(service_path));
311 const NetworkState* network =
312 network_state_handler_->GetNetworkState(service_path);
313 if (!network) {
314 NET_LOG_ERROR("Disconnect Error: Not Found", service_path);
315 network_handler::RunErrorCallback(error_callback, service_path,
316 kErrorNotFound, "");
317 return;
319 if (!network->IsConnectedState() && !network->IsConnectingState()) {
320 NET_LOG_ERROR("Disconnect Error: Not Connected", service_path);
321 network_handler::RunErrorCallback(error_callback, service_path,
322 kErrorNotConnected, "");
323 return;
325 pending_requests_.erase(service_path);
326 CallShillDisconnect(service_path, success_callback, error_callback);
329 bool NetworkConnectionHandler::HasConnectingNetwork(
330 const std::string& service_path) {
331 return pending_requests_.count(service_path) != 0;
334 bool NetworkConnectionHandler::HasPendingConnectRequest() {
335 return pending_requests_.size() > 0;
338 void NetworkConnectionHandler::NetworkListChanged() {
339 CheckAllPendingRequests();
342 void NetworkConnectionHandler::NetworkPropertiesUpdated(
343 const NetworkState* network) {
344 if (HasConnectingNetwork(network->path()))
345 CheckPendingRequest(network->path());
348 NetworkConnectionHandler::ConnectRequest*
349 NetworkConnectionHandler::GetPendingRequest(const std::string& service_path) {
350 std::map<std::string, ConnectRequest>::iterator iter =
351 pending_requests_.find(service_path);
352 return iter != pending_requests_.end() ? &(iter->second) : NULL;
355 // ConnectToNetwork implementation
357 void NetworkConnectionHandler::VerifyConfiguredAndConnect(
358 bool check_error_state,
359 const std::string& service_path,
360 const base::DictionaryValue& service_properties) {
361 NET_LOG_EVENT("VerifyConfiguredAndConnect", service_path);
363 // If 'passphrase_required' is still true, then the 'Passphrase' property
364 // has not been set to a minimum length value.
365 bool passphrase_required = false;
366 service_properties.GetBooleanWithoutPathExpansion(
367 shill::kPassphraseRequiredProperty, &passphrase_required);
368 if (passphrase_required) {
369 ErrorCallbackForPendingRequest(service_path, kErrorPassphraseRequired);
370 return;
373 std::string type, security_class;
374 service_properties.GetStringWithoutPathExpansion(shill::kTypeProperty, &type);
375 service_properties.GetStringWithoutPathExpansion(
376 shill::kSecurityClassProperty, &security_class);
377 bool connectable = false;
378 service_properties.GetBooleanWithoutPathExpansion(
379 shill::kConnectableProperty, &connectable);
381 // In case NetworkState was not available in ConnectToNetwork (e.g. it had
382 // been recently configured), we need to check Connectable again.
383 if (connectable && type != shill::kTypeVPN) {
384 // TODO(stevenjb): Shill needs to properly set Connectable for VPN.
385 CallShillConnect(service_path);
386 return;
389 // Get VPN provider type and host (required for configuration) and ensure
390 // that required VPN non-cert properties are set.
391 const base::DictionaryValue* provider_properties = NULL;
392 std::string vpn_provider_type, vpn_provider_host, vpn_client_cert_id;
393 if (type == shill::kTypeVPN) {
394 // VPN Provider values are read from the "Provider" dictionary, not the
395 // "Provider.Type", etc keys (which are used only to set the values).
396 if (service_properties.GetDictionaryWithoutPathExpansion(
397 shill::kProviderProperty, &provider_properties)) {
398 provider_properties->GetStringWithoutPathExpansion(
399 shill::kTypeProperty, &vpn_provider_type);
400 provider_properties->GetStringWithoutPathExpansion(
401 shill::kHostProperty, &vpn_provider_host);
402 provider_properties->GetStringWithoutPathExpansion(
403 shill::kL2tpIpsecClientCertIdProperty, &vpn_client_cert_id);
405 if (vpn_provider_type.empty() || vpn_provider_host.empty()) {
406 ErrorCallbackForPendingRequest(service_path, kErrorConfigurationRequired);
407 return;
411 std::string guid;
412 service_properties.GetStringWithoutPathExpansion(shill::kGuidProperty, &guid);
413 std::string profile;
414 service_properties.GetStringWithoutPathExpansion(shill::kProfileProperty,
415 &profile);
416 const base::DictionaryValue* user_policy =
417 managed_configuration_handler_->FindPolicyByGuidAndProfile(guid, profile);
419 client_cert::ClientCertConfig cert_config_from_policy;
420 if (user_policy)
421 client_cert::OncToClientCertConfig(*user_policy, &cert_config_from_policy);
423 client_cert::ConfigType client_cert_type = client_cert::CONFIG_TYPE_NONE;
424 if (type == shill::kTypeVPN) {
425 if (vpn_provider_type == shill::kProviderOpenVpn) {
426 client_cert_type = client_cert::CONFIG_TYPE_OPENVPN;
427 } else {
428 // L2TP/IPSec only requires a certificate if one is specified in ONC
429 // or one was configured by the UI. Otherwise it is L2TP/IPSec with
430 // PSK and doesn't require a certificate.
432 // TODO(benchan): Modify shill to specify the authentication type via
433 // the kL2tpIpsecAuthenticationType property, so that Chrome doesn't need
434 // to deduce the authentication type based on the
435 // kL2tpIpsecClientCertIdProperty here (and also in VPNConfigView).
436 if (!vpn_client_cert_id.empty() ||
437 cert_config_from_policy.client_cert_type !=
438 onc::client_cert::kClientCertTypeNone) {
439 client_cert_type = client_cert::CONFIG_TYPE_IPSEC;
442 } else if (type == shill::kTypeWifi &&
443 security_class == shill::kSecurity8021x) {
444 client_cert_type = client_cert::CONFIG_TYPE_EAP;
447 base::DictionaryValue config_properties;
448 if (client_cert_type != client_cert::CONFIG_TYPE_NONE) {
449 // Note: if we get here then a certificate *may* be required, so we want
450 // to ensure that certificates have loaded successfully before attempting
451 // to connect.
453 // User must be logged in to connect to a network requiring a certificate.
454 if (!logged_in_ || !cert_loader_) {
455 NET_LOG_ERROR("User not logged in", "");
456 ErrorCallbackForPendingRequest(service_path, kErrorCertificateRequired);
457 return;
459 // If certificates have not been loaded yet, queue the connect request.
460 if (!certificates_loaded_) {
461 NET_LOG_EVENT("Certificates not loaded", "");
462 QueueConnectRequest(service_path);
463 return;
466 // Check certificate properties from policy.
467 if (cert_config_from_policy.client_cert_type ==
468 onc::client_cert::kPattern) {
469 if (!ClientCertResolver::ResolveCertificatePatternSync(
470 client_cert_type,
471 cert_config_from_policy.pattern,
472 &config_properties)) {
473 ErrorCallbackForPendingRequest(service_path, kErrorCertificateRequired);
474 return;
476 } else if (check_error_state &&
477 !client_cert::IsCertificateConfigured(client_cert_type,
478 service_properties)) {
479 // Network may not be configured.
480 ErrorCallbackForPendingRequest(service_path, kErrorConfigurationRequired);
481 return;
485 if (type == shill::kTypeVPN) {
486 // VPN may require a username, and/or passphrase to be set. (Check after
487 // ensuring that any required certificates are configured).
488 DCHECK(provider_properties);
489 if (VPNRequiresCredentials(
490 service_path, vpn_provider_type, *provider_properties)) {
491 NET_LOG_USER("VPN Requires Credentials", service_path);
492 ErrorCallbackForPendingRequest(service_path, kErrorConfigurationRequired);
493 return;
496 // If it's L2TP/IPsec PSK, there is no properties to configure, so proceed
497 // to connect.
498 if (client_cert_type == client_cert::CONFIG_TYPE_NONE) {
499 CallShillConnect(service_path);
500 return;
504 if (!config_properties.empty()) {
505 NET_LOG_EVENT("Configuring Network", service_path);
506 configuration_handler_->SetShillProperties(
507 service_path, config_properties,
508 NetworkConfigurationObserver::SOURCE_USER_ACTION,
509 base::Bind(&NetworkConnectionHandler::CallShillConnect, AsWeakPtr(),
510 service_path),
511 base::Bind(&NetworkConnectionHandler::HandleConfigurationFailure,
512 AsWeakPtr(), service_path));
513 return;
516 // Otherwise, we probably still need to configure the network since
517 // 'Connectable' is false. If |check_error_state| is true, signal an
518 // error, otherwise attempt to connect to possibly gain additional error
519 // state from Shill (or in case 'Connectable' is improperly unset).
520 if (check_error_state)
521 ErrorCallbackForPendingRequest(service_path, kErrorConfigurationRequired);
522 else
523 CallShillConnect(service_path);
526 void NetworkConnectionHandler::QueueConnectRequest(
527 const std::string& service_path) {
528 ConnectRequest* request = GetPendingRequest(service_path);
529 if (!request) {
530 NET_LOG_ERROR("No pending request to queue", service_path);
531 return;
534 const int kMaxCertLoadTimeSeconds = 15;
535 base::TimeDelta dtime = base::TimeTicks::Now() - logged_in_time_;
536 if (dtime > base::TimeDelta::FromSeconds(kMaxCertLoadTimeSeconds)) {
537 NET_LOG_ERROR("Certificate load timeout", service_path);
538 InvokeConnectErrorCallback(service_path, request->error_callback,
539 kErrorCertLoadTimeout);
540 return;
543 NET_LOG_EVENT("Connect Request Queued", service_path);
544 queued_connect_.reset(new ConnectRequest(
545 service_path, request->profile_path,
546 request->success_callback, request->error_callback));
547 pending_requests_.erase(service_path);
549 // Post a delayed task to check to see if certificates have loaded. If they
550 // haven't, and queued_connect_ has not been cleared (e.g. by a successful
551 // connect request), cancel the request and notify the user.
552 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
553 FROM_HERE, base::Bind(&NetworkConnectionHandler::CheckCertificatesLoaded,
554 AsWeakPtr()),
555 base::TimeDelta::FromSeconds(kMaxCertLoadTimeSeconds) - dtime);
558 void NetworkConnectionHandler::CheckCertificatesLoaded() {
559 if (certificates_loaded_)
560 return;
561 // If queued_connect_ has been cleared (e.g. another connect request occurred
562 // and wasn't queued), do nothing here.
563 if (!queued_connect_)
564 return;
565 // Otherwise, notify the user.
566 NET_LOG_ERROR("Certificate load timeout", queued_connect_->service_path);
567 InvokeConnectErrorCallback(queued_connect_->service_path,
568 queued_connect_->error_callback,
569 kErrorCertLoadTimeout);
570 queued_connect_.reset();
573 void NetworkConnectionHandler::ConnectToQueuedNetwork() {
574 DCHECK(queued_connect_);
576 // Make a copy of |queued_connect_| parameters, because |queued_connect_|
577 // will get reset at the beginning of |ConnectToNetwork|.
578 std::string service_path = queued_connect_->service_path;
579 base::Closure success_callback = queued_connect_->success_callback;
580 network_handler::ErrorCallback error_callback =
581 queued_connect_->error_callback;
583 NET_LOG_EVENT("Connecting to Queued Network", service_path);
584 ConnectToNetwork(service_path, success_callback, error_callback,
585 false /* check_error_state */);
588 void NetworkConnectionHandler::CallShillConnect(
589 const std::string& service_path) {
590 NET_LOG_EVENT("Sending Connect Request to Shill", service_path);
591 network_state_handler_->ClearLastErrorForNetwork(service_path);
592 DBusThreadManager::Get()->GetShillServiceClient()->Connect(
593 dbus::ObjectPath(service_path),
594 base::Bind(&NetworkConnectionHandler::HandleShillConnectSuccess,
595 AsWeakPtr(), service_path),
596 base::Bind(&NetworkConnectionHandler::HandleShillConnectFailure,
597 AsWeakPtr(), service_path));
600 void NetworkConnectionHandler::HandleConfigurationFailure(
601 const std::string& service_path,
602 const std::string& error_name,
603 scoped_ptr<base::DictionaryValue> error_data) {
604 ConnectRequest* request = GetPendingRequest(service_path);
605 if (!request) {
606 NET_LOG_ERROR("HandleConfigurationFailure called with no pending request.",
607 service_path);
608 return;
610 network_handler::ErrorCallback error_callback = request->error_callback;
611 pending_requests_.erase(service_path);
612 InvokeConnectErrorCallback(service_path, error_callback,
613 kErrorConfigureFailed);
616 void NetworkConnectionHandler::HandleShillConnectSuccess(
617 const std::string& service_path) {
618 ConnectRequest* request = GetPendingRequest(service_path);
619 if (!request) {
620 NET_LOG_ERROR("HandleShillConnectSuccess called with no pending request.",
621 service_path);
622 return;
624 request->connect_state = ConnectRequest::CONNECT_STARTED;
625 NET_LOG_EVENT("Connect Request Acknowledged", service_path);
626 // Do not call success_callback here, wait for one of the following
627 // conditions:
628 // * State transitions to a non connecting state indicating success or failure
629 // * Network is no longer in the visible list, indicating failure
630 CheckPendingRequest(service_path);
633 void NetworkConnectionHandler::HandleShillConnectFailure(
634 const std::string& service_path,
635 const std::string& dbus_error_name,
636 const std::string& dbus_error_message) {
637 ConnectRequest* request = GetPendingRequest(service_path);
638 if (!request) {
639 NET_LOG_ERROR("HandleShillConnectFailure called with no pending request.",
640 service_path);
641 return;
643 network_handler::ErrorCallback error_callback = request->error_callback;
644 pending_requests_.erase(service_path);
645 std::string error;
646 if (dbus_error_name == shill::kErrorResultAlreadyConnected) {
647 error = kErrorConnected;
648 } else if (dbus_error_name == shill::kErrorResultInProgress) {
649 error = kErrorConnecting;
650 } else {
651 NET_LOG_ERROR("Connect Failure, Shill error: " + dbus_error_name,
652 service_path);
653 error = kErrorConnectFailed;
655 InvokeConnectErrorCallback(service_path, error_callback, error);
658 void NetworkConnectionHandler::CheckPendingRequest(
659 const std::string service_path) {
660 ConnectRequest* request = GetPendingRequest(service_path);
661 DCHECK(request);
662 if (request->connect_state == ConnectRequest::CONNECT_REQUESTED)
663 return; // Request has not started, ignore update
664 const NetworkState* network =
665 network_state_handler_->GetNetworkState(service_path);
666 if (!network)
667 return; // NetworkState may not be be updated yet.
669 if (network->IsConnectingState()) {
670 request->connect_state = ConnectRequest::CONNECT_CONNECTING;
671 return;
673 if (network->IsConnectedState()) {
674 if (!request->profile_path.empty()) {
675 // If a profile path was specified, set it on a successful connection.
676 configuration_handler_->SetNetworkProfile(
677 service_path,
678 request->profile_path,
679 NetworkConfigurationObserver::SOURCE_USER_ACTION,
680 base::Bind(&base::DoNothing),
681 chromeos::network_handler::ErrorCallback());
683 InvokeConnectSuccessCallback(request->service_path,
684 request->success_callback);
685 pending_requests_.erase(service_path);
686 return;
688 if (network->connection_state() == shill::kStateIdle &&
689 request->connect_state != ConnectRequest::CONNECT_CONNECTING) {
690 // Connection hasn't started yet, keep waiting.
691 return;
694 // Network is neither connecting or connected; an error occurred.
695 std::string error_name; // 'Canceled' or 'Failed'
696 if (network->connection_state() == shill::kStateIdle &&
697 pending_requests_.size() > 1) {
698 // Another connect request canceled this one.
699 error_name = kErrorConnectCanceled;
700 } else {
701 error_name = kErrorConnectFailed;
702 if (network->connection_state() != shill::kStateFailure) {
703 NET_LOG_ERROR("Unexpected State: " + network->connection_state(),
704 service_path);
708 network_handler::ErrorCallback error_callback = request->error_callback;
709 pending_requests_.erase(service_path);
710 InvokeConnectErrorCallback(service_path, error_callback, error_name);
713 void NetworkConnectionHandler::CheckAllPendingRequests() {
714 for (std::map<std::string, ConnectRequest>::iterator iter =
715 pending_requests_.begin(); iter != pending_requests_.end(); ++iter) {
716 CheckPendingRequest(iter->first);
720 // Connect callbacks
722 void NetworkConnectionHandler::InvokeConnectSuccessCallback(
723 const std::string& service_path,
724 const base::Closure& success_callback) {
725 NET_LOG_EVENT("Connect Request Succeeded", service_path);
726 if (!success_callback.is_null())
727 success_callback.Run();
728 FOR_EACH_OBSERVER(NetworkConnectionObserver, observers_,
729 ConnectSucceeded(service_path));
732 void NetworkConnectionHandler::ErrorCallbackForPendingRequest(
733 const std::string& service_path,
734 const std::string& error_name) {
735 ConnectRequest* request = GetPendingRequest(service_path);
736 if (!request) {
737 NET_LOG_ERROR("ErrorCallbackForPendingRequest with no pending request.",
738 service_path);
739 return;
741 // Remove the entry before invoking the callback in case it triggers a retry.
742 network_handler::ErrorCallback error_callback = request->error_callback;
743 pending_requests_.erase(service_path);
744 InvokeConnectErrorCallback(service_path, error_callback, error_name);
747 void NetworkConnectionHandler::InvokeConnectErrorCallback(
748 const std::string& service_path,
749 const network_handler::ErrorCallback& error_callback,
750 const std::string& error_name) {
751 NET_LOG_ERROR("Connect Failure: " + error_name, service_path);
752 network_handler::RunErrorCallback(error_callback, service_path, error_name,
753 "");
754 FOR_EACH_OBSERVER(NetworkConnectionObserver, observers_,
755 ConnectFailed(service_path, error_name));
758 // Disconnect
760 void NetworkConnectionHandler::CallShillDisconnect(
761 const std::string& service_path,
762 const base::Closure& success_callback,
763 const network_handler::ErrorCallback& error_callback) {
764 NET_LOG_USER("Disconnect Request", service_path);
765 DBusThreadManager::Get()->GetShillServiceClient()->Disconnect(
766 dbus::ObjectPath(service_path),
767 base::Bind(&NetworkConnectionHandler::HandleShillDisconnectSuccess,
768 AsWeakPtr(), service_path, success_callback),
769 base::Bind(&network_handler::ShillErrorCallbackFunction,
770 kErrorDisconnectFailed, service_path, error_callback));
773 void NetworkConnectionHandler::HandleShillDisconnectSuccess(
774 const std::string& service_path,
775 const base::Closure& success_callback) {
776 NET_LOG_EVENT("Disconnect Request Sent", service_path);
777 if (!success_callback.is_null())
778 success_callback.Run();
781 } // namespace chromeos