[Session restore] Rename group name Enabled to Restore.
[chromium-blink-merge.git] / chromeos / network / network_connection_handler.cc
blob4cae62c9491a19bf31899c197056c471dd49cc56
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/message_loop/message_loop_proxy.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "chromeos/dbus/dbus_thread_manager.h"
13 #include "chromeos/dbus/shill_manager_client.h"
14 #include "chromeos/dbus/shill_service_client.h"
15 #include "chromeos/network/certificate_pattern.h"
16 #include "chromeos/network/client_cert_resolver.h"
17 #include "chromeos/network/client_cert_util.h"
18 #include "chromeos/network/managed_network_configuration_handler.h"
19 #include "chromeos/network/network_configuration_handler.h"
20 #include "chromeos/network/network_event_log.h"
21 #include "chromeos/network/network_profile_handler.h"
22 #include "chromeos/network/network_state.h"
23 #include "chromeos/network/network_state_handler.h"
24 #include "chromeos/network/shill_property_util.h"
25 #include "dbus/object_path.h"
26 #include "net/cert/x509_certificate.h"
27 #include "third_party/cros_system_api/dbus/service_constants.h"
29 namespace chromeos {
31 namespace {
33 bool IsAuthenticationError(const std::string& error) {
34 return (error == shill::kErrorBadWEPKey ||
35 error == shill::kErrorPppAuthFailed ||
36 error == shill::kErrorEapLocalTlsFailed ||
37 error == shill::kErrorEapRemoteTlsFailed ||
38 error == shill::kErrorEapAuthenticationFailed);
41 bool VPNRequiresCredentials(const std::string& service_path,
42 const std::string& provider_type,
43 const base::DictionaryValue& provider_properties) {
44 if (provider_type == shill::kProviderOpenVpn) {
45 std::string username;
46 provider_properties.GetStringWithoutPathExpansion(
47 shill::kOpenVPNUserProperty, &username);
48 if (username.empty()) {
49 NET_LOG_EVENT("OpenVPN: No username", service_path);
50 return true;
52 bool passphrase_required = false;
53 provider_properties.GetBooleanWithoutPathExpansion(
54 shill::kPassphraseRequiredProperty, &passphrase_required);
55 if (passphrase_required) {
56 NET_LOG_EVENT("OpenVPN: Passphrase Required", service_path);
57 return true;
59 NET_LOG_EVENT("OpenVPN Is Configured", service_path);
60 } else {
61 bool passphrase_required = false;
62 provider_properties.GetBooleanWithoutPathExpansion(
63 shill::kL2tpIpsecPskRequiredProperty, &passphrase_required);
64 if (passphrase_required) {
65 NET_LOG_EVENT("VPN: PSK Required", service_path);
66 return true;
68 provider_properties.GetBooleanWithoutPathExpansion(
69 shill::kPassphraseRequiredProperty, &passphrase_required);
70 if (passphrase_required) {
71 NET_LOG_EVENT("VPN: Passphrase Required", service_path);
72 return true;
74 NET_LOG_EVENT("VPN Is Configured", service_path);
76 return false;
79 std::string GetDefaultUserProfilePath(const NetworkState* network) {
80 if (!NetworkHandler::IsInitialized() ||
81 (LoginState::IsInitialized() &&
82 !LoginState::Get()->UserHasNetworkProfile()) ||
83 (network && network->type() == shill::kTypeWifi &&
84 network->security_class() == shill::kSecurityNone)) {
85 return NetworkProfileHandler::GetSharedProfilePath();
87 const NetworkProfile* profile =
88 NetworkHandler::Get()->network_profile_handler()->GetDefaultUserProfile();
89 return profile ? profile->path
90 : NetworkProfileHandler::GetSharedProfilePath();
93 } // namespace
95 const char NetworkConnectionHandler::kErrorNotFound[] = "not-found";
96 const char NetworkConnectionHandler::kErrorConnected[] = "connected";
97 const char NetworkConnectionHandler::kErrorConnecting[] = "connecting";
98 const char NetworkConnectionHandler::kErrorNotConnected[] = "not-connected";
99 const char NetworkConnectionHandler::kErrorPassphraseRequired[] =
100 "passphrase-required";
101 const char NetworkConnectionHandler::kErrorBadPassphrase[] = "bad-passphrase";
102 const char NetworkConnectionHandler::kErrorCertificateRequired[] =
103 "certificate-required";
104 const char NetworkConnectionHandler::kErrorConfigurationRequired[] =
105 "configuration-required";
106 const char NetworkConnectionHandler::kErrorAuthenticationRequired[] =
107 "authentication-required";
108 const char NetworkConnectionHandler::kErrorConnectFailed[] = "connect-failed";
109 const char NetworkConnectionHandler::kErrorDisconnectFailed[] =
110 "disconnect-failed";
111 const char NetworkConnectionHandler::kErrorConfigureFailed[] =
112 "configure-failed";
113 const char NetworkConnectionHandler::kErrorConnectCanceled[] =
114 "connect-canceled";
115 const char NetworkConnectionHandler::kErrorCertLoadTimeout[] =
116 "cert-load-timeout";
118 struct NetworkConnectionHandler::ConnectRequest {
119 ConnectRequest(const std::string& service_path,
120 const std::string& profile_path,
121 const base::Closure& success,
122 const network_handler::ErrorCallback& error)
123 : service_path(service_path),
124 profile_path(profile_path),
125 connect_state(CONNECT_REQUESTED),
126 success_callback(success),
127 error_callback(error) {
129 enum ConnectState {
130 CONNECT_REQUESTED = 0,
131 CONNECT_STARTED = 1,
132 CONNECT_CONNECTING = 2
134 std::string service_path;
135 std::string profile_path;
136 ConnectState connect_state;
137 base::Closure success_callback;
138 network_handler::ErrorCallback error_callback;
141 NetworkConnectionHandler::NetworkConnectionHandler()
142 : cert_loader_(NULL),
143 network_state_handler_(NULL),
144 configuration_handler_(NULL),
145 logged_in_(false),
146 certificates_loaded_(false) {
149 NetworkConnectionHandler::~NetworkConnectionHandler() {
150 if (network_state_handler_)
151 network_state_handler_->RemoveObserver(this, FROM_HERE);
152 if (cert_loader_)
153 cert_loader_->RemoveObserver(this);
154 if (LoginState::IsInitialized())
155 LoginState::Get()->RemoveObserver(this);
158 void NetworkConnectionHandler::Init(
159 NetworkStateHandler* network_state_handler,
160 NetworkConfigurationHandler* network_configuration_handler,
161 ManagedNetworkConfigurationHandler* managed_network_configuration_handler) {
162 if (LoginState::IsInitialized())
163 LoginState::Get()->AddObserver(this);
165 if (CertLoader::IsInitialized()) {
166 cert_loader_ = CertLoader::Get();
167 cert_loader_->AddObserver(this);
168 if (cert_loader_->certificates_loaded()) {
169 NET_LOG_EVENT("Certificates Loaded", "");
170 certificates_loaded_ = true;
172 } else {
173 // TODO(tbarzic): Require a mock or stub cert_loader in tests.
174 NET_LOG_EVENT("Certificate Loader not initialized", "");
175 certificates_loaded_ = true;
178 if (network_state_handler) {
179 network_state_handler_ = network_state_handler;
180 network_state_handler_->AddObserver(this, FROM_HERE);
182 configuration_handler_ = network_configuration_handler;
183 managed_configuration_handler_ = managed_network_configuration_handler;
185 // After this point, the NetworkConnectionHandler is fully initialized (all
186 // handler references set, observers registered, ...).
188 if (LoginState::IsInitialized())
189 LoggedInStateChanged();
192 void NetworkConnectionHandler::AddObserver(
193 NetworkConnectionObserver* observer) {
194 observers_.AddObserver(observer);
197 void NetworkConnectionHandler::RemoveObserver(
198 NetworkConnectionObserver* observer) {
199 observers_.RemoveObserver(observer);
202 void NetworkConnectionHandler::LoggedInStateChanged() {
203 LoginState* login_state = LoginState::Get();
204 if (logged_in_ || !login_state->IsUserLoggedIn())
205 return;
207 logged_in_ = true;
208 logged_in_time_ = base::TimeTicks::Now();
211 void NetworkConnectionHandler::OnCertificatesLoaded(
212 const net::CertificateList& cert_list,
213 bool initial_load) {
214 certificates_loaded_ = true;
215 NET_LOG_EVENT("Certificates Loaded", "");
216 if (queued_connect_)
217 ConnectToQueuedNetwork();
220 void NetworkConnectionHandler::ConnectToNetwork(
221 const std::string& service_path,
222 const base::Closure& success_callback,
223 const network_handler::ErrorCallback& error_callback,
224 bool check_error_state) {
225 NET_LOG_USER("ConnectToNetwork", service_path);
226 FOR_EACH_OBSERVER(NetworkConnectionObserver, observers_,
227 ConnectToNetworkRequested(service_path));
229 // Clear any existing queued connect request.
230 queued_connect_.reset();
231 if (HasConnectingNetwork(service_path)) {
232 NET_LOG_USER("Connect Request While Pending", service_path);
233 InvokeConnectErrorCallback(service_path, error_callback, kErrorConnecting);
234 return;
237 // Check cached network state for connected, connecting, or unactivated
238 // networks. These states will not be affected by a recent configuration.
239 // Note: NetworkState may not exist for a network that was recently
240 // configured, in which case these checks do not apply anyway.
241 const NetworkState* network =
242 network_state_handler_->GetNetworkState(service_path);
244 if (network) {
245 // For existing networks, perform some immediate consistency checks.
246 if (network->IsConnectedState()) {
247 InvokeConnectErrorCallback(service_path, error_callback, kErrorConnected);
248 return;
250 if (network->IsConnectingState()) {
251 InvokeConnectErrorCallback(service_path, error_callback,
252 kErrorConnecting);
253 return;
256 if (check_error_state) {
257 const std::string& error = network->last_error();
258 if (error == shill::kErrorBadPassphrase) {
259 InvokeConnectErrorCallback(service_path, error_callback,
260 kErrorBadPassphrase);
261 return;
263 if (IsAuthenticationError(error)) {
264 InvokeConnectErrorCallback(service_path, error_callback,
265 kErrorAuthenticationRequired);
266 return;
271 // If the network does not have a profile path, specify the correct default
272 // profile here and set it once connected. Otherwise leave it empty to
273 // indicate that it does not need to be set.
274 std::string profile_path;
275 if (!network || network->profile_path().empty())
276 profile_path = GetDefaultUserProfilePath(network);
278 // All synchronous checks passed, add |service_path| to connecting list.
279 pending_requests_.insert(std::make_pair(
280 service_path,
281 ConnectRequest(service_path, profile_path,
282 success_callback, error_callback)));
284 // Connect immediately to 'connectable' networks.
285 // TODO(stevenjb): Shill needs to properly set Connectable for VPN.
286 if (network && network->connectable() && network->type() != shill::kTypeVPN) {
287 CallShillConnect(service_path);
288 return;
291 // Request additional properties to check. VerifyConfiguredAndConnect will
292 // use only these properties, not cached properties, to ensure that they
293 // are up to date after any recent configuration.
294 configuration_handler_->GetShillProperties(
295 service_path,
296 base::Bind(&NetworkConnectionHandler::VerifyConfiguredAndConnect,
297 AsWeakPtr(), check_error_state),
298 base::Bind(&NetworkConnectionHandler::HandleConfigurationFailure,
299 AsWeakPtr(), service_path));
302 void NetworkConnectionHandler::DisconnectNetwork(
303 const std::string& service_path,
304 const base::Closure& success_callback,
305 const network_handler::ErrorCallback& error_callback) {
306 NET_LOG_USER("DisconnectNetwork", service_path);
307 FOR_EACH_OBSERVER(NetworkConnectionObserver, observers_,
308 DiconnectRequested(service_path));
310 const NetworkState* network =
311 network_state_handler_->GetNetworkState(service_path);
312 if (!network) {
313 NET_LOG_ERROR("Disconnect Error: Not Found", service_path);
314 network_handler::RunErrorCallback(error_callback, service_path,
315 kErrorNotFound, "");
316 return;
318 if (!network->IsConnectedState() && !network->IsConnectingState()) {
319 NET_LOG_ERROR("Disconnect Error: Not Connected", service_path);
320 network_handler::RunErrorCallback(error_callback, service_path,
321 kErrorNotConnected, "");
322 return;
324 pending_requests_.erase(service_path);
325 CallShillDisconnect(service_path, success_callback, error_callback);
328 bool NetworkConnectionHandler::HasConnectingNetwork(
329 const std::string& service_path) {
330 return pending_requests_.count(service_path) != 0;
333 bool NetworkConnectionHandler::HasPendingConnectRequest() {
334 return pending_requests_.size() > 0;
337 void NetworkConnectionHandler::NetworkListChanged() {
338 CheckAllPendingRequests();
341 void NetworkConnectionHandler::NetworkPropertiesUpdated(
342 const NetworkState* network) {
343 if (HasConnectingNetwork(network->path()))
344 CheckPendingRequest(network->path());
347 NetworkConnectionHandler::ConnectRequest*
348 NetworkConnectionHandler::GetPendingRequest(const std::string& service_path) {
349 std::map<std::string, ConnectRequest>::iterator iter =
350 pending_requests_.find(service_path);
351 return iter != pending_requests_.end() ? &(iter->second) : NULL;
354 // ConnectToNetwork implementation
356 void NetworkConnectionHandler::VerifyConfiguredAndConnect(
357 bool check_error_state,
358 const std::string& service_path,
359 const base::DictionaryValue& service_properties) {
360 NET_LOG_EVENT("VerifyConfiguredAndConnect", service_path);
362 // If 'passphrase_required' is still true, then the 'Passphrase' property
363 // has not been set to a minimum length value.
364 bool passphrase_required = false;
365 service_properties.GetBooleanWithoutPathExpansion(
366 shill::kPassphraseRequiredProperty, &passphrase_required);
367 if (passphrase_required) {
368 ErrorCallbackForPendingRequest(service_path, kErrorPassphraseRequired);
369 return;
372 std::string type, security_class;
373 service_properties.GetStringWithoutPathExpansion(shill::kTypeProperty, &type);
374 service_properties.GetStringWithoutPathExpansion(
375 shill::kSecurityClassProperty, &security_class);
376 bool connectable = false;
377 service_properties.GetBooleanWithoutPathExpansion(
378 shill::kConnectableProperty, &connectable);
380 // In case NetworkState was not available in ConnectToNetwork (e.g. it had
381 // been recently configured), we need to check Connectable again.
382 if (connectable && type != shill::kTypeVPN) {
383 // TODO(stevenjb): Shill needs to properly set Connectable for VPN.
384 CallShillConnect(service_path);
385 return;
388 // Get VPN provider type and host (required for configuration) and ensure
389 // that required VPN non-cert properties are set.
390 const base::DictionaryValue* provider_properties = NULL;
391 std::string vpn_provider_type, vpn_provider_host, vpn_client_cert_id;
392 if (type == shill::kTypeVPN) {
393 // VPN Provider values are read from the "Provider" dictionary, not the
394 // "Provider.Type", etc keys (which are used only to set the values).
395 if (service_properties.GetDictionaryWithoutPathExpansion(
396 shill::kProviderProperty, &provider_properties)) {
397 provider_properties->GetStringWithoutPathExpansion(
398 shill::kTypeProperty, &vpn_provider_type);
399 provider_properties->GetStringWithoutPathExpansion(
400 shill::kHostProperty, &vpn_provider_host);
401 provider_properties->GetStringWithoutPathExpansion(
402 shill::kL2tpIpsecClientCertIdProperty, &vpn_client_cert_id);
404 if (vpn_provider_type.empty() || vpn_provider_host.empty()) {
405 ErrorCallbackForPendingRequest(service_path, kErrorConfigurationRequired);
406 return;
410 std::string guid;
411 service_properties.GetStringWithoutPathExpansion(shill::kGuidProperty, &guid);
412 std::string profile;
413 service_properties.GetStringWithoutPathExpansion(shill::kProfileProperty,
414 &profile);
415 const base::DictionaryValue* user_policy =
416 managed_configuration_handler_->FindPolicyByGuidAndProfile(guid, profile);
418 client_cert::ClientCertConfig cert_config_from_policy;
419 if (user_policy)
420 client_cert::OncToClientCertConfig(*user_policy, &cert_config_from_policy);
422 client_cert::ConfigType client_cert_type = client_cert::CONFIG_TYPE_NONE;
423 if (type == shill::kTypeVPN) {
424 if (vpn_provider_type == shill::kProviderOpenVpn) {
425 client_cert_type = client_cert::CONFIG_TYPE_OPENVPN;
426 } else {
427 // L2TP/IPSec only requires a certificate if one is specified in ONC
428 // or one was configured by the UI. Otherwise it is L2TP/IPSec with
429 // PSK and doesn't require a certificate.
431 // TODO(benchan): Modify shill to specify the authentication type via
432 // the kL2tpIpsecAuthenticationType property, so that Chrome doesn't need
433 // to deduce the authentication type based on the
434 // kL2tpIpsecClientCertIdProperty here (and also in VPNConfigView).
435 if (!vpn_client_cert_id.empty() ||
436 cert_config_from_policy.client_cert_type !=
437 onc::client_cert::kClientCertTypeNone) {
438 client_cert_type = client_cert::CONFIG_TYPE_IPSEC;
441 } else if (type == shill::kTypeWifi &&
442 security_class == shill::kSecurity8021x) {
443 client_cert_type = client_cert::CONFIG_TYPE_EAP;
446 base::DictionaryValue config_properties;
447 if (client_cert_type != client_cert::CONFIG_TYPE_NONE) {
448 // Note: if we get here then a certificate *may* be required, so we want
449 // to ensure that certificates have loaded successfully before attempting
450 // to connect.
452 // User must be logged in to connect to a network requiring a certificate.
453 if (!logged_in_ || !cert_loader_) {
454 NET_LOG_ERROR("User not logged in", "");
455 ErrorCallbackForPendingRequest(service_path, kErrorCertificateRequired);
456 return;
458 // If certificates have not been loaded yet, queue the connect request.
459 if (!certificates_loaded_) {
460 NET_LOG_EVENT("Certificates not loaded", "");
461 QueueConnectRequest(service_path);
462 return;
465 // Check certificate properties from policy.
466 if (cert_config_from_policy.client_cert_type ==
467 onc::client_cert::kPattern) {
468 if (!ClientCertResolver::ResolveCertificatePatternSync(
469 client_cert_type,
470 cert_config_from_policy.pattern,
471 &config_properties)) {
472 ErrorCallbackForPendingRequest(service_path, kErrorCertificateRequired);
473 return;
475 } else if (check_error_state &&
476 !client_cert::IsCertificateConfigured(client_cert_type,
477 service_properties)) {
478 // Network may not be configured.
479 ErrorCallbackForPendingRequest(service_path, kErrorConfigurationRequired);
480 return;
484 if (type == shill::kTypeVPN) {
485 // VPN may require a username, and/or passphrase to be set. (Check after
486 // ensuring that any required certificates are configured).
487 DCHECK(provider_properties);
488 if (VPNRequiresCredentials(
489 service_path, vpn_provider_type, *provider_properties)) {
490 NET_LOG_USER("VPN Requires Credentials", service_path);
491 ErrorCallbackForPendingRequest(service_path, kErrorConfigurationRequired);
492 return;
495 // If it's L2TP/IPsec PSK, there is no properties to configure, so proceed
496 // to connect.
497 if (client_cert_type == client_cert::CONFIG_TYPE_NONE) {
498 CallShillConnect(service_path);
499 return;
503 if (!config_properties.empty()) {
504 NET_LOG_EVENT("Configuring Network", service_path);
505 configuration_handler_->SetShillProperties(
506 service_path, config_properties,
507 NetworkConfigurationObserver::SOURCE_USER_ACTION,
508 base::Bind(&NetworkConnectionHandler::CallShillConnect, AsWeakPtr(),
509 service_path),
510 base::Bind(&NetworkConnectionHandler::HandleConfigurationFailure,
511 AsWeakPtr(), service_path));
512 return;
515 // Otherwise, we probably still need to configure the network since
516 // 'Connectable' is false. If |check_error_state| is true, signal an
517 // error, otherwise attempt to connect to possibly gain additional error
518 // state from Shill (or in case 'Connectable' is improperly unset).
519 if (check_error_state)
520 ErrorCallbackForPendingRequest(service_path, kErrorConfigurationRequired);
521 else
522 CallShillConnect(service_path);
525 void NetworkConnectionHandler::QueueConnectRequest(
526 const std::string& service_path) {
527 ConnectRequest* request = GetPendingRequest(service_path);
528 if (!request) {
529 NET_LOG_ERROR("No pending request to queue", service_path);
530 return;
533 const int kMaxCertLoadTimeSeconds = 15;
534 base::TimeDelta dtime = base::TimeTicks::Now() - logged_in_time_;
535 if (dtime > base::TimeDelta::FromSeconds(kMaxCertLoadTimeSeconds)) {
536 NET_LOG_ERROR("Certificate load timeout", service_path);
537 InvokeConnectErrorCallback(service_path, request->error_callback,
538 kErrorCertLoadTimeout);
539 return;
542 NET_LOG_EVENT("Connect Request Queued", service_path);
543 queued_connect_.reset(new ConnectRequest(
544 service_path, request->profile_path,
545 request->success_callback, request->error_callback));
546 pending_requests_.erase(service_path);
548 // Post a delayed task to check to see if certificates have loaded. If they
549 // haven't, and queued_connect_ has not been cleared (e.g. by a successful
550 // connect request), cancel the request and notify the user.
551 base::MessageLoopProxy::current()->PostDelayedTask(
552 FROM_HERE,
553 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