Explicitly add python-numpy dependency to install-build-deps.
[chromium-blink-merge.git] / chromeos / network / network_connection_handler.cc
blob6d2bc5994c67a355d58def885264b131156366d0
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/cert_loader.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_handler_callbacks.h"
23 #include "chromeos/network/network_profile_handler.h"
24 #include "chromeos/network/network_state.h"
25 #include "chromeos/network/network_state_handler.h"
26 #include "chromeos/network/shill_property_util.h"
27 #include "dbus/object_path.h"
28 #include "net/cert/x509_certificate.h"
29 #include "third_party/cros_system_api/dbus/service_constants.h"
31 namespace chromeos {
33 namespace {
35 void InvokeErrorCallback(const std::string& service_path,
36 const network_handler::ErrorCallback& error_callback,
37 const std::string& error_name) {
38 NET_LOG_ERROR("Connect Error: " + error_name, service_path);
39 network_handler::RunErrorCallback(
40 error_callback, service_path, error_name, "");
43 bool IsAuthenticationError(const std::string& error) {
44 return (error == shill::kErrorBadWEPKey ||
45 error == shill::kErrorPppAuthFailed ||
46 error == shill::kErrorEapLocalTlsFailed ||
47 error == shill::kErrorEapRemoteTlsFailed ||
48 error == shill::kErrorEapAuthenticationFailed);
51 bool VPNRequiresCredentials(const std::string& service_path,
52 const std::string& provider_type,
53 const base::DictionaryValue& provider_properties) {
54 if (provider_type == shill::kProviderOpenVpn) {
55 std::string username;
56 provider_properties.GetStringWithoutPathExpansion(
57 shill::kOpenVPNUserProperty, &username);
58 if (username.empty()) {
59 NET_LOG_EVENT("OpenVPN: No username", service_path);
60 return true;
62 bool passphrase_required = false;
63 provider_properties.GetBooleanWithoutPathExpansion(
64 shill::kPassphraseRequiredProperty, &passphrase_required);
65 if (passphrase_required) {
66 NET_LOG_EVENT("OpenVPN: Passphrase Required", service_path);
67 return true;
69 NET_LOG_EVENT("OpenVPN Is Configured", service_path);
70 } else {
71 bool passphrase_required = false;
72 provider_properties.GetBooleanWithoutPathExpansion(
73 shill::kL2tpIpsecPskRequiredProperty, &passphrase_required);
74 if (passphrase_required) {
75 NET_LOG_EVENT("VPN: PSK Required", service_path);
76 return true;
78 provider_properties.GetBooleanWithoutPathExpansion(
79 shill::kPassphraseRequiredProperty, &passphrase_required);
80 if (passphrase_required) {
81 NET_LOG_EVENT("VPN: Passphrase Required", service_path);
82 return true;
84 NET_LOG_EVENT("VPN Is Configured", service_path);
86 return false;
89 std::string GetDefaultUserProfilePath(const NetworkState* network) {
90 if (!NetworkHandler::IsInitialized() ||
91 (LoginState::IsInitialized() &&
92 !LoginState::Get()->UserHasNetworkProfile()) ||
93 (network && network->type() == shill::kTypeWifi &&
94 network->security() == shill::kSecurityNone)) {
95 return NetworkProfileHandler::GetSharedProfilePath();
97 const NetworkProfile* profile =
98 NetworkHandler::Get()->network_profile_handler()->GetDefaultUserProfile();
99 return profile ? profile->path
100 : NetworkProfileHandler::GetSharedProfilePath();
103 } // namespace
105 const char NetworkConnectionHandler::kErrorNotFound[] = "not-found";
106 const char NetworkConnectionHandler::kErrorConnected[] = "connected";
107 const char NetworkConnectionHandler::kErrorConnecting[] = "connecting";
108 const char NetworkConnectionHandler::kErrorNotConnected[] = "not-connected";
109 const char NetworkConnectionHandler::kErrorPassphraseRequired[] =
110 "passphrase-required";
111 const char NetworkConnectionHandler::kErrorActivationRequired[] =
112 "activation-required";
113 const char NetworkConnectionHandler::kErrorCertificateRequired[] =
114 "certificate-required";
115 const char NetworkConnectionHandler::kErrorConfigurationRequired[] =
116 "configuration-required";
117 const char NetworkConnectionHandler::kErrorAuthenticationRequired[] =
118 "authentication-required";
119 const char NetworkConnectionHandler::kErrorShillError[] = "shill-error";
120 const char NetworkConnectionHandler::kErrorConfigureFailed[] =
121 "configure-failed";
122 const char NetworkConnectionHandler::kErrorConnectCanceled[] =
123 "connect-canceled";
124 const char NetworkConnectionHandler::kErrorCertLoadTimeout[] =
125 "cert-load-timeout";
127 struct NetworkConnectionHandler::ConnectRequest {
128 ConnectRequest(const std::string& service_path,
129 const std::string& profile_path,
130 const base::Closure& success,
131 const network_handler::ErrorCallback& error)
132 : service_path(service_path),
133 profile_path(profile_path),
134 connect_state(CONNECT_REQUESTED),
135 success_callback(success),
136 error_callback(error) {
138 enum ConnectState {
139 CONNECT_REQUESTED = 0,
140 CONNECT_STARTED = 1,
141 CONNECT_CONNECTING = 2
143 std::string service_path;
144 std::string profile_path;
145 ConnectState connect_state;
146 base::Closure success_callback;
147 network_handler::ErrorCallback error_callback;
150 NetworkConnectionHandler::NetworkConnectionHandler()
151 : cert_loader_(NULL),
152 network_state_handler_(NULL),
153 configuration_handler_(NULL),
154 logged_in_(false),
155 certificates_loaded_(false) {
158 NetworkConnectionHandler::~NetworkConnectionHandler() {
159 if (network_state_handler_)
160 network_state_handler_->RemoveObserver(this, FROM_HERE);
161 if (cert_loader_)
162 cert_loader_->RemoveObserver(this);
163 if (LoginState::IsInitialized())
164 LoginState::Get()->RemoveObserver(this);
167 void NetworkConnectionHandler::Init(
168 NetworkStateHandler* network_state_handler,
169 NetworkConfigurationHandler* network_configuration_handler,
170 ManagedNetworkConfigurationHandler* managed_network_configuration_handler) {
171 if (LoginState::IsInitialized())
172 LoginState::Get()->AddObserver(this);
174 if (CertLoader::IsInitialized()) {
175 cert_loader_ = CertLoader::Get();
176 cert_loader_->AddObserver(this);
177 if (cert_loader_->certificates_loaded()) {
178 NET_LOG_EVENT("Certificates Loaded", "");
179 certificates_loaded_ = true;
181 } else {
182 // TODO(tbarzic): Require a mock or stub cert_loader in tests.
183 NET_LOG_EVENT("Certificate Loader not initialized", "");
184 certificates_loaded_ = true;
187 if (network_state_handler) {
188 network_state_handler_ = network_state_handler;
189 network_state_handler_->AddObserver(this, FROM_HERE);
191 configuration_handler_ = network_configuration_handler;
192 managed_configuration_handler_ = managed_network_configuration_handler;
194 // After this point, the NetworkConnectionHandler is fully initialized (all
195 // handler references set, observers registered, ...).
197 if (LoginState::IsInitialized())
198 LoggedInStateChanged();
201 void NetworkConnectionHandler::AddObserver(Observer* observer) {
202 observers_.AddObserver(observer);
205 void NetworkConnectionHandler::RemoveObserver(Observer* observer) {
206 observers_.RemoveObserver(observer);
209 void NetworkConnectionHandler::LoggedInStateChanged() {
210 LoginState* login_state = LoginState::Get();
211 if (logged_in_ || !login_state->IsUserLoggedIn())
212 return;
214 NET_LOG_EVENT("Logged In", "");
215 logged_in_ = true;
216 logged_in_time_ = base::TimeTicks::Now();
219 void NetworkConnectionHandler::OnCertificatesLoaded(
220 const net::CertificateList& cert_list,
221 bool initial_load) {
222 certificates_loaded_ = true;
223 NET_LOG_EVENT("Certificates Loaded", "");
224 if (queued_connect_)
225 ConnectToQueuedNetwork();
228 void NetworkConnectionHandler::ConnectToNetwork(
229 const std::string& service_path,
230 const base::Closure& success_callback,
231 const network_handler::ErrorCallback& error_callback,
232 bool check_error_state) {
233 NET_LOG_USER("ConnectToNetwork", service_path);
234 FOR_EACH_OBSERVER(Observer, observers_,
235 ConnectToNetworkRequested(service_path));
237 // Clear any existing queued connect request.
238 queued_connect_.reset();
239 if (HasConnectingNetwork(service_path)) {
240 NET_LOG_USER("Connect Request While Pending", service_path);
241 InvokeErrorCallback(service_path, error_callback, kErrorConnecting);
242 return;
245 // Check cached network state for connected, connecting, or unactivated
246 // networks. These states will not be affected by a recent configuration.
247 // Note: NetworkState may not exist for a network that was recently
248 // configured, in which case these checks do not apply anyway.
249 const NetworkState* network =
250 network_state_handler_->GetNetworkState(service_path);
252 if (network) {
253 // For existing networks, perform some immediate consistency checks.
254 if (network->IsConnectedState()) {
255 InvokeErrorCallback(service_path, error_callback, kErrorConnected);
256 return;
258 if (network->IsConnectingState()) {
259 InvokeErrorCallback(service_path, error_callback, kErrorConnecting);
260 return;
263 if (check_error_state) {
264 const std::string& error = network->last_error();
265 if (error == shill::kErrorBadPassphrase) {
266 InvokeErrorCallback(service_path, error_callback, error);
267 return;
269 if (IsAuthenticationError(error)) {
270 InvokeErrorCallback(
271 service_path, error_callback, kErrorAuthenticationRequired);
272 return;
277 // If the network does not have a profile path, specify the correct default
278 // profile here and set it once connected. Otherwise leave it empty to
279 // indicate that it does not need to be set.
280 std::string profile_path;
281 if (!network || network->profile_path().empty())
282 profile_path = GetDefaultUserProfilePath(network);
284 // All synchronous checks passed, add |service_path| to connecting list.
285 pending_requests_.insert(std::make_pair(
286 service_path,
287 ConnectRequest(service_path, profile_path,
288 success_callback, error_callback)));
290 // Connect immediately to 'connectable' networks.
291 // TODO(stevenjb): Shill needs to properly set Connectable for VPN.
292 if (network && network->connectable() && network->type() != shill::kTypeVPN) {
293 CallShillConnect(service_path);
294 return;
297 // Request additional properties to check. VerifyConfiguredAndConnect will
298 // use only these properties, not cached properties, to ensure that they
299 // are up to date after any recent configuration.
300 configuration_handler_->GetProperties(
301 service_path,
302 base::Bind(&NetworkConnectionHandler::VerifyConfiguredAndConnect,
303 AsWeakPtr(), check_error_state),
304 base::Bind(&NetworkConnectionHandler::HandleConfigurationFailure,
305 AsWeakPtr(), service_path));
308 void NetworkConnectionHandler::DisconnectNetwork(
309 const std::string& service_path,
310 const base::Closure& success_callback,
311 const network_handler::ErrorCallback& error_callback) {
312 NET_LOG_USER("DisconnectNetwork", service_path);
313 const NetworkState* network =
314 network_state_handler_->GetNetworkState(service_path);
315 if (!network) {
316 InvokeErrorCallback(service_path, error_callback, kErrorNotFound);
317 return;
319 if (!network->IsConnectedState() && !network->IsConnectingState()) {
320 InvokeErrorCallback(service_path, error_callback, kErrorNotConnected);
321 return;
323 pending_requests_.erase(service_path);
324 CallShillDisconnect(service_path, success_callback, error_callback);
327 bool NetworkConnectionHandler::HasConnectingNetwork(
328 const std::string& service_path) {
329 return pending_requests_.count(service_path) != 0;
332 bool NetworkConnectionHandler::HasPendingConnectRequest() {
333 return pending_requests_.size() > 0;
336 void NetworkConnectionHandler::NetworkListChanged() {
337 CheckAllPendingRequests();
340 void NetworkConnectionHandler::NetworkPropertiesUpdated(
341 const NetworkState* network) {
342 if (HasConnectingNetwork(network->path()))
343 CheckPendingRequest(network->path());
346 NetworkConnectionHandler::ConnectRequest*
347 NetworkConnectionHandler::GetPendingRequest(const std::string& service_path) {
348 std::map<std::string, ConnectRequest>::iterator iter =
349 pending_requests_.find(service_path);
350 return iter != pending_requests_.end() ? &(iter->second) : NULL;
353 // ConnectToNetwork implementation
355 void NetworkConnectionHandler::VerifyConfiguredAndConnect(
356 bool check_error_state,
357 const std::string& service_path,
358 const base::DictionaryValue& service_properties) {
359 NET_LOG_EVENT("VerifyConfiguredAndConnect", service_path);
361 // If 'passphrase_required' is still true, then the 'Passphrase' property
362 // has not been set to a minimum length value.
363 bool passphrase_required = false;
364 service_properties.GetBooleanWithoutPathExpansion(
365 shill::kPassphraseRequiredProperty, &passphrase_required);
366 if (passphrase_required) {
367 ErrorCallbackForPendingRequest(service_path, kErrorPassphraseRequired);
368 return;
371 std::string type, security;
372 service_properties.GetStringWithoutPathExpansion(shill::kTypeProperty, &type);
373 service_properties.GetStringWithoutPathExpansion(
374 shill::kSecurityProperty, &security);
375 bool connectable = false;
376 service_properties.GetBooleanWithoutPathExpansion(
377 shill::kConnectableProperty, &connectable);
379 // In case NetworkState was not available in ConnectToNetwork (e.g. it had
380 // been recently configured), we need to check Connectable again.
381 if (connectable && type != shill::kTypeVPN) {
382 // TODO(stevenjb): Shill needs to properly set Connectable for VPN.
383 CallShillConnect(service_path);
384 return;
387 // Get VPN provider type and host (required for configuration) and ensure
388 // that required VPN non-cert properties are set.
389 const base::DictionaryValue* provider_properties = NULL;
390 std::string vpn_provider_type, vpn_provider_host, vpn_client_cert_id;
391 if (type == shill::kTypeVPN) {
392 // VPN Provider values are read from the "Provider" dictionary, not the
393 // "Provider.Type", etc keys (which are used only to set the values).
394 if (service_properties.GetDictionaryWithoutPathExpansion(
395 shill::kProviderProperty, &provider_properties)) {
396 provider_properties->GetStringWithoutPathExpansion(
397 shill::kTypeProperty, &vpn_provider_type);
398 provider_properties->GetStringWithoutPathExpansion(
399 shill::kHostProperty, &vpn_provider_host);
400 provider_properties->GetStringWithoutPathExpansion(
401 shill::kL2tpIpsecClientCertIdProperty, &vpn_client_cert_id);
403 if (vpn_provider_type.empty() || vpn_provider_host.empty()) {
404 ErrorCallbackForPendingRequest(service_path, kErrorConfigurationRequired);
405 return;
409 std::string guid;
410 service_properties.GetStringWithoutPathExpansion(shill::kGuidProperty, &guid);
411 std::string profile;
412 service_properties.GetStringWithoutPathExpansion(shill::kProfileProperty,
413 &profile);
414 const base::DictionaryValue* user_policy =
415 managed_configuration_handler_->FindPolicyByGuidAndProfile(guid, profile);
417 client_cert::ClientCertConfig cert_config_from_policy;
418 if (user_policy)
419 client_cert::OncToClientCertConfig(*user_policy, &cert_config_from_policy);
421 client_cert::ConfigType client_cert_type = client_cert::CONFIG_TYPE_NONE;
422 if (type == shill::kTypeVPN) {
423 if (vpn_provider_type == shill::kProviderOpenVpn) {
424 client_cert_type = client_cert::CONFIG_TYPE_OPENVPN;
425 } else {
426 // L2TP/IPSec only requires a certificate if one is specified in ONC
427 // or one was configured by the UI. Otherwise it is L2TP/IPSec with
428 // PSK and doesn't require a certificate.
430 // TODO(benchan): Modify shill to specify the authentication type via
431 // the kL2tpIpsecAuthenticationType property, so that Chrome doesn't need
432 // to deduce the authentication type based on the
433 // kL2tpIpsecClientCertIdProperty here (and also in VPNConfigView).
434 if (!vpn_client_cert_id.empty() ||
435 cert_config_from_policy.client_cert_type !=
436 onc::client_cert::kClientCertTypeNone) {
437 client_cert_type = client_cert::CONFIG_TYPE_IPSEC;
440 } else if (type == shill::kTypeWifi && security == shill::kSecurity8021x) {
441 client_cert_type = client_cert::CONFIG_TYPE_EAP;
444 base::DictionaryValue config_properties;
445 if (client_cert_type != client_cert::CONFIG_TYPE_NONE) {
446 // Note: if we get here then a certificate *may* be required, so we want
447 // to ensure that certificates have loaded successfully before attempting
448 // to connect.
450 // User must be logged in to connect to a network requiring a certificate.
451 if (!logged_in_ || !cert_loader_) {
452 NET_LOG_ERROR("User not logged in", "");
453 ErrorCallbackForPendingRequest(service_path, kErrorCertificateRequired);
454 return;
456 // If certificates have not been loaded yet, queue the connect request.
457 if (!certificates_loaded_) {
458 NET_LOG_EVENT("Certificates not loaded", "");
459 QueueConnectRequest(service_path);
460 return;
463 // Check certificate properties from policy.
464 if (cert_config_from_policy.client_cert_type ==
465 onc::client_cert::kPattern) {
466 if (!ClientCertResolver::ResolveCertificatePatternSync(
467 client_cert_type,
468 cert_config_from_policy.pattern,
469 &config_properties)) {
470 ErrorCallbackForPendingRequest(service_path, kErrorCertificateRequired);
471 return;
473 } else if (check_error_state &&
474 !client_cert::IsCertificateConfigured(client_cert_type,
475 service_properties)) {
476 // Network may not be configured.
477 ErrorCallbackForPendingRequest(service_path, kErrorConfigurationRequired);
478 return;
482 if (type == shill::kTypeVPN) {
483 // VPN may require a username, and/or passphrase to be set. (Check after
484 // ensuring that any required certificates are configured).
485 DCHECK(provider_properties);
486 if (VPNRequiresCredentials(
487 service_path, vpn_provider_type, *provider_properties)) {
488 NET_LOG_USER("VPN Requires Credentials", service_path);
489 ErrorCallbackForPendingRequest(service_path, kErrorConfigurationRequired);
490 return;
493 // If it's L2TP/IPsec PSK, there is no properties to configure, so proceed
494 // to connect.
495 if (client_cert_type == client_cert::CONFIG_TYPE_NONE) {
496 CallShillConnect(service_path);
497 return;
501 if (!config_properties.empty()) {
502 NET_LOG_EVENT("Configuring Network", service_path);
503 configuration_handler_->SetProperties(
504 service_path,
505 config_properties,
506 NetworkConfigurationObserver::SOURCE_USER_ACTION,
507 base::Bind(&NetworkConnectionHandler::CallShillConnect,
508 AsWeakPtr(),
509 service_path),
510 base::Bind(&NetworkConnectionHandler::HandleConfigurationFailure,
511 AsWeakPtr(),
512 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 InvokeErrorCallback(service_path,
539 request->error_callback,
540 kErrorCertLoadTimeout);
541 return;
544 NET_LOG_EVENT("Connect Request Queued", service_path);
545 queued_connect_.reset(new ConnectRequest(
546 service_path, request->profile_path,
547 request->success_callback, request->error_callback));
548 pending_requests_.erase(service_path);
550 // Post a delayed task to check to see if certificates have loaded. If they
551 // haven't, and queued_connect_ has not been cleared (e.g. by a successful
552 // connect request), cancel the request and notify the user.
553 base::MessageLoopProxy::current()->PostDelayedTask(
554 FROM_HERE,
555 base::Bind(&NetworkConnectionHandler::CheckCertificatesLoaded,
556 AsWeakPtr()),
557 base::TimeDelta::FromSeconds(kMaxCertLoadTimeSeconds) - dtime);
560 void NetworkConnectionHandler::CheckCertificatesLoaded() {
561 if (certificates_loaded_)
562 return;
563 // If queued_connect_ has been cleared (e.g. another connect request occurred
564 // and wasn't queued), do nothing here.
565 if (!queued_connect_)
566 return;
567 // Otherwise, notify the user.
568 NET_LOG_ERROR("Certificate load timeout", queued_connect_->service_path);
569 InvokeErrorCallback(queued_connect_->service_path,
570 queued_connect_->error_callback,
571 kErrorCertLoadTimeout);
572 queued_connect_.reset();
575 void NetworkConnectionHandler::ConnectToQueuedNetwork() {
576 DCHECK(queued_connect_);
578 // Make a copy of |queued_connect_| parameters, because |queued_connect_|
579 // will get reset at the beginning of |ConnectToNetwork|.
580 std::string service_path = queued_connect_->service_path;
581 base::Closure success_callback = queued_connect_->success_callback;
582 network_handler::ErrorCallback error_callback =
583 queued_connect_->error_callback;
585 NET_LOG_EVENT("Connecting to Queued Network", service_path);
586 ConnectToNetwork(service_path, success_callback, error_callback,
587 false /* check_error_state */);
590 void NetworkConnectionHandler::CallShillConnect(
591 const std::string& service_path) {
592 NET_LOG_EVENT("Sending Connect Request to Shill", service_path);
593 network_state_handler_->ClearLastErrorForNetwork(service_path);
594 DBusThreadManager::Get()->GetShillServiceClient()->Connect(
595 dbus::ObjectPath(service_path),
596 base::Bind(&NetworkConnectionHandler::HandleShillConnectSuccess,
597 AsWeakPtr(), service_path),
598 base::Bind(&NetworkConnectionHandler::HandleShillConnectFailure,
599 AsWeakPtr(), service_path));
602 void NetworkConnectionHandler::HandleConfigurationFailure(
603 const std::string& service_path,
604 const std::string& error_name,
605 scoped_ptr<base::DictionaryValue> error_data) {
606 ConnectRequest* request = GetPendingRequest(service_path);
607 if (!request) {
608 NET_LOG_ERROR("HandleConfigurationFailure called with no pending request.",
609 service_path);
610 return;
612 network_handler::ErrorCallback error_callback = request->error_callback;
613 pending_requests_.erase(service_path);
614 if (!error_callback.is_null())
615 error_callback.Run(kErrorConfigureFailed, error_data.Pass());
618 void NetworkConnectionHandler::HandleShillConnectSuccess(
619 const std::string& service_path) {
620 ConnectRequest* request = GetPendingRequest(service_path);
621 if (!request) {
622 NET_LOG_ERROR("HandleShillConnectSuccess called with no pending request.",
623 service_path);
624 return;
626 request->connect_state = ConnectRequest::CONNECT_STARTED;
627 NET_LOG_EVENT("Connect Request Acknowledged", service_path);
628 // Do not call success_callback here, wait for one of the following
629 // conditions:
630 // * State transitions to a non connecting state indicating success or failure
631 // * Network is no longer in the visible list, indicating failure
632 CheckPendingRequest(service_path);
635 void NetworkConnectionHandler::HandleShillConnectFailure(
636 const std::string& service_path,
637 const std::string& dbus_error_name,
638 const std::string& dbus_error_message) {
639 ConnectRequest* request = GetPendingRequest(service_path);
640 if (!request) {
641 NET_LOG_ERROR("HandleShillConnectFailure called with no pending request.",
642 service_path);
643 return;
645 network_handler::ErrorCallback error_callback = request->error_callback;
646 pending_requests_.erase(service_path);
647 network_handler::ShillErrorCallbackFunction(
648 shill::kErrorConnectFailed, service_path, error_callback,
649 dbus_error_name, dbus_error_message);
652 void NetworkConnectionHandler::CheckPendingRequest(
653 const std::string service_path) {
654 ConnectRequest* request = GetPendingRequest(service_path);
655 DCHECK(request);
656 if (request->connect_state == ConnectRequest::CONNECT_REQUESTED)
657 return; // Request has not started, ignore update
658 const NetworkState* network =
659 network_state_handler_->GetNetworkState(service_path);
660 if (!network)
661 return; // NetworkState may not be be updated yet.
663 if (network->IsConnectingState()) {
664 request->connect_state = ConnectRequest::CONNECT_CONNECTING;
665 return;
667 if (network->IsConnectedState()) {
668 NET_LOG_EVENT("Connect Request Succeeded", service_path);
669 if (!request->profile_path.empty()) {
670 // If a profile path was specified, set it on a successful connection.
671 configuration_handler_->SetNetworkProfile(
672 service_path,
673 request->profile_path,
674 NetworkConfigurationObserver::SOURCE_USER_ACTION,
675 base::Bind(&base::DoNothing),
676 chromeos::network_handler::ErrorCallback());
678 if (!request->success_callback.is_null())
679 request->success_callback.Run();
680 pending_requests_.erase(service_path);
681 return;
683 if (network->connection_state() == shill::kStateIdle &&
684 request->connect_state != ConnectRequest::CONNECT_CONNECTING) {
685 // Connection hasn't started yet, keep waiting.
686 return;
689 // Network is neither connecting or connected; an error occurred.
690 std::string error_name; // 'Canceled' or 'Failed'
691 if (network->connection_state() == shill::kStateIdle &&
692 pending_requests_.size() > 1) {
693 // Another connect request canceled this one.
694 error_name = kErrorConnectCanceled;
695 } else {
696 error_name = shill::kErrorConnectFailed;
697 if (network->connection_state() != shill::kStateFailure) {
698 NET_LOG_ERROR("Unexpected State: " + network->connection_state(),
699 service_path);
703 network_handler::ErrorCallback error_callback = request->error_callback;
704 pending_requests_.erase(service_path);
705 if (error_callback.is_null()) {
706 NET_LOG_ERROR("Connect Error, no callback: " + error_name, service_path);
707 return;
709 InvokeErrorCallback(service_path, error_callback, error_name);
712 void NetworkConnectionHandler::CheckAllPendingRequests() {
713 for (std::map<std::string, ConnectRequest>::iterator iter =
714 pending_requests_.begin(); iter != pending_requests_.end(); ++iter) {
715 CheckPendingRequest(iter->first);
719 void NetworkConnectionHandler::ErrorCallbackForPendingRequest(
720 const std::string& service_path,
721 const std::string& error_name) {
722 ConnectRequest* request = GetPendingRequest(service_path);
723 if (!request) {
724 NET_LOG_ERROR("ErrorCallbackForPendingRequest with no pending request.",
725 service_path);
726 return;
728 // Remove the entry before invoking the callback in case it triggers a retry.
729 network_handler::ErrorCallback error_callback = request->error_callback;
730 pending_requests_.erase(service_path);
731 InvokeErrorCallback(service_path, error_callback, error_name);
734 // Disconnect
736 void NetworkConnectionHandler::CallShillDisconnect(
737 const std::string& service_path,
738 const base::Closure& success_callback,
739 const network_handler::ErrorCallback& error_callback) {
740 NET_LOG_USER("Disconnect Request", service_path);
741 DBusThreadManager::Get()->GetShillServiceClient()->Disconnect(
742 dbus::ObjectPath(service_path),
743 base::Bind(&NetworkConnectionHandler::HandleShillDisconnectSuccess,
744 AsWeakPtr(), service_path, success_callback),
745 base::Bind(&network_handler::ShillErrorCallbackFunction,
746 kErrorShillError, service_path, error_callback));
749 void NetworkConnectionHandler::HandleShillDisconnectSuccess(
750 const std::string& service_path,
751 const base::Closure& success_callback) {
752 NET_LOG_EVENT("Disconnect Request Sent", service_path);
753 if (!success_callback.is_null())
754 success_callback.Run();
757 } // namespace chromeos