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/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"
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
) {
47 provider_properties
.GetStringWithoutPathExpansion(
48 shill::kOpenVPNUserProperty
, &username
);
49 if (username
.empty()) {
50 NET_LOG_EVENT("OpenVPN: No username", service_path
);
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
);
60 NET_LOG_EVENT("OpenVPN Is Configured", service_path
);
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
);
69 provider_properties
.GetBooleanWithoutPathExpansion(
70 shill::kPassphraseRequiredProperty
, &passphrase_required
);
71 if (passphrase_required
) {
72 NET_LOG_EVENT("VPN: Passphrase Required", service_path
);
75 NET_LOG_EVENT("VPN Is Configured", service_path
);
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();
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
[] =
112 const char NetworkConnectionHandler::kErrorConfigureFailed
[] =
114 const char NetworkConnectionHandler::kErrorConnectCanceled
[] =
116 const char NetworkConnectionHandler::kErrorCertLoadTimeout
[] =
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
) {
131 CONNECT_REQUESTED
= 0,
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
),
147 certificates_loaded_(false) {
150 NetworkConnectionHandler::~NetworkConnectionHandler() {
151 if (network_state_handler_
)
152 network_state_handler_
->RemoveObserver(this, FROM_HERE
);
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;
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())
209 logged_in_time_
= base::TimeTicks::Now();
212 void NetworkConnectionHandler::OnCertificatesLoaded(
213 const net::CertificateList
& cert_list
,
215 certificates_loaded_
= true;
216 NET_LOG_EVENT("Certificates Loaded", "");
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
);
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
);
246 // For existing networks, perform some immediate consistency checks.
247 if (network
->IsConnectedState()) {
248 InvokeConnectErrorCallback(service_path
, error_callback
, kErrorConnected
);
251 if (network
->IsConnectingState()) {
252 InvokeConnectErrorCallback(service_path
, error_callback
,
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
);
264 if (IsAuthenticationError(error
)) {
265 InvokeConnectErrorCallback(service_path
, error_callback
,
266 kErrorAuthenticationRequired
);
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(
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
);
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(
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
);
314 NET_LOG_ERROR("Disconnect Error: Not Found", service_path
);
315 network_handler::RunErrorCallback(error_callback
, service_path
,
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
, "");
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
);
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
);
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
);
412 service_properties
.GetStringWithoutPathExpansion(shill::kGuidProperty
, &guid
);
414 service_properties
.GetStringWithoutPathExpansion(shill::kProfileProperty
,
416 const base::DictionaryValue
* user_policy
=
417 managed_configuration_handler_
->FindPolicyByGuidAndProfile(guid
, profile
);
419 client_cert::ClientCertConfig cert_config_from_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
;
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
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
);
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
);
466 // Check certificate properties from policy.
467 if (cert_config_from_policy
.client_cert_type
==
468 onc::client_cert::kPattern
) {
469 if (!ClientCertResolver::ResolveCertificatePatternSync(
471 cert_config_from_policy
.pattern
,
472 &config_properties
)) {
473 ErrorCallbackForPendingRequest(service_path
, kErrorCertificateRequired
);
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
);
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
);
496 // If it's L2TP/IPsec PSK, there is no properties to configure, so proceed
498 if (client_cert_type
== client_cert::CONFIG_TYPE_NONE
) {
499 CallShillConnect(service_path
);
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(),
511 base::Bind(&NetworkConnectionHandler::HandleConfigurationFailure
,
512 AsWeakPtr(), service_path
));
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
);
523 CallShillConnect(service_path
);
526 void NetworkConnectionHandler::QueueConnectRequest(
527 const std::string
& service_path
) {
528 ConnectRequest
* request
= GetPendingRequest(service_path
);
530 NET_LOG_ERROR("No pending request to queue", service_path
);
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
);
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
,
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