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"
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"
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
) {
46 provider_properties
.GetStringWithoutPathExpansion(
47 shill::kOpenVPNUserProperty
, &username
);
48 if (username
.empty()) {
49 NET_LOG_EVENT("OpenVPN: No username", service_path
);
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
);
59 NET_LOG_EVENT("OpenVPN Is Configured", service_path
);
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
);
68 provider_properties
.GetBooleanWithoutPathExpansion(
69 shill::kPassphraseRequiredProperty
, &passphrase_required
);
70 if (passphrase_required
) {
71 NET_LOG_EVENT("VPN: Passphrase Required", service_path
);
74 NET_LOG_EVENT("VPN Is Configured", service_path
);
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();
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
[] =
111 const char NetworkConnectionHandler::kErrorConfigureFailed
[] =
113 const char NetworkConnectionHandler::kErrorConnectCanceled
[] =
115 const char NetworkConnectionHandler::kErrorCertLoadTimeout
[] =
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
) {
130 CONNECT_REQUESTED
= 0,
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
),
146 certificates_loaded_(false) {
149 NetworkConnectionHandler::~NetworkConnectionHandler() {
150 if (network_state_handler_
)
151 network_state_handler_
->RemoveObserver(this, FROM_HERE
);
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;
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())
208 logged_in_time_
= base::TimeTicks::Now();
211 void NetworkConnectionHandler::OnCertificatesLoaded(
212 const net::CertificateList
& cert_list
,
214 certificates_loaded_
= true;
215 NET_LOG_EVENT("Certificates Loaded", "");
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
);
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
);
245 // For existing networks, perform some immediate consistency checks.
246 if (network
->IsConnectedState()) {
247 InvokeConnectErrorCallback(service_path
, error_callback
, kErrorConnected
);
250 if (network
->IsConnectingState()) {
251 InvokeConnectErrorCallback(service_path
, error_callback
,
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
);
263 if (IsAuthenticationError(error
)) {
264 InvokeConnectErrorCallback(service_path
, error_callback
,
265 kErrorAuthenticationRequired
);
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(
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
);
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(
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
);
313 NET_LOG_ERROR("Disconnect Error: Not Found", service_path
);
314 network_handler::RunErrorCallback(error_callback
, service_path
,
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
, "");
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
);
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
);
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
);
411 service_properties
.GetStringWithoutPathExpansion(shill::kGuidProperty
, &guid
);
413 service_properties
.GetStringWithoutPathExpansion(shill::kProfileProperty
,
415 const base::DictionaryValue
* user_policy
=
416 managed_configuration_handler_
->FindPolicyByGuidAndProfile(guid
, profile
);
418 client_cert::ClientCertConfig cert_config_from_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
;
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
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
);
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
);
465 // Check certificate properties from policy.
466 if (cert_config_from_policy
.client_cert_type
==
467 onc::client_cert::kPattern
) {
468 if (!ClientCertResolver::ResolveCertificatePatternSync(
470 cert_config_from_policy
.pattern
,
471 &config_properties
)) {
472 ErrorCallbackForPendingRequest(service_path
, kErrorCertificateRequired
);
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
);
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
);
495 // If it's L2TP/IPsec PSK, there is no properties to configure, so proceed
497 if (client_cert_type
== client_cert::CONFIG_TYPE_NONE
) {
498 CallShillConnect(service_path
);
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(),
510 base::Bind(&NetworkConnectionHandler::HandleConfigurationFailure
,
511 AsWeakPtr(), service_path
));
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
);
522 CallShillConnect(service_path
);
525 void NetworkConnectionHandler::QueueConnectRequest(
526 const std::string
& service_path
) {
527 ConnectRequest
* request
= GetPendingRequest(service_path
);
529 NET_LOG_ERROR("No pending request to queue", service_path
);
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
);
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(
553 base::Bind(&NetworkConnectionHandler::CheckCertificatesLoaded
,
555 base::TimeDelta::FromSeconds(kMaxCertLoadTimeSeconds
) - dtime
);
558 void NetworkConnectionHandler::CheckCertificatesLoaded() {
559 if (certificates_loaded_
)
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_
)
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
);
606 NET_LOG_ERROR("HandleConfigurationFailure called with no pending request.",
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
);
620 NET_LOG_ERROR("HandleShillConnectSuccess called with no pending request.",
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
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
);
639 NET_LOG_ERROR("HandleShillConnectFailure called with no pending request.",
643 network_handler::ErrorCallback error_callback
= request
->error_callback
;
644 pending_requests_
.erase(service_path
);
646 if (dbus_error_name
== shill::kErrorResultAlreadyConnected
) {
647 error
= kErrorConnected
;
648 } else if (dbus_error_name
== shill::kErrorResultInProgress
) {
649 error
= kErrorConnecting
;
651 NET_LOG_ERROR("Connect Failure, Shill error: " + dbus_error_name
,
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
);
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
);
667 return; // NetworkState may not be be updated yet.
669 if (network
->IsConnectingState()) {
670 request
->connect_state
= ConnectRequest::CONNECT_CONNECTING
;
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(
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
);
688 if (network
->connection_state() == shill::kStateIdle
&&
689 request
->connect_state
!= ConnectRequest::CONNECT_CONNECTING
) {
690 // Connection hasn't started yet, keep waiting.
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
;
701 error_name
= kErrorConnectFailed
;
702 if (network
->connection_state() != shill::kStateFailure
) {
703 NET_LOG_ERROR("Unexpected State: " + network
->connection_state(),
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
);
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
);
737 NET_LOG_ERROR("ErrorCallbackForPendingRequest with no pending request.",
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
,
754 FOR_EACH_OBSERVER(NetworkConnectionObserver
, observers_
,
755 ConnectFailed(service_path
, error_name
));
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