Fixed incorrect call of updateContextMenuActionItems.
[chromium-blink-merge.git] / chromeos / network / network_connection_handler.cc
blob79e4ea2d0758f56d8665ca8b192ba373c3112dce
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 base::Bind(&NetworkConnectionHandler::CallShillConnect,
507 AsWeakPtr(),
508 service_path),
509 base::Bind(&NetworkConnectionHandler::HandleConfigurationFailure,
510 AsWeakPtr(),
511 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 InvokeErrorCallback(service_path,
538 request->error_callback,
539 kErrorCertLoadTimeout);
540 return;
543 NET_LOG_EVENT("Connect Request Queued", service_path);
544 queued_connect_.reset(new ConnectRequest(
545 service_path, request->profile_path,
546 request->success_callback, request->error_callback));
547 pending_requests_.erase(service_path);
549 // Post a delayed task to check to see if certificates have loaded. If they
550 // haven't, and queued_connect_ has not been cleared (e.g. by a successful
551 // connect request), cancel the request and notify the user.
552 base::MessageLoopProxy::current()->PostDelayedTask(
553 FROM_HERE,
554 base::Bind(&NetworkConnectionHandler::CheckCertificatesLoaded,
555 AsWeakPtr()),
556 base::TimeDelta::FromSeconds(kMaxCertLoadTimeSeconds) - dtime);
559 void NetworkConnectionHandler::CheckCertificatesLoaded() {
560 if (certificates_loaded_)
561 return;
562 // If queued_connect_ has been cleared (e.g. another connect request occurred
563 // and wasn't queued), do nothing here.
564 if (!queued_connect_)
565 return;
566 // Otherwise, notify the user.
567 NET_LOG_ERROR("Certificate load timeout", queued_connect_->service_path);
568 InvokeErrorCallback(queued_connect_->service_path,
569 queued_connect_->error_callback,
570 kErrorCertLoadTimeout);
571 queued_connect_.reset();
574 void NetworkConnectionHandler::ConnectToQueuedNetwork() {
575 DCHECK(queued_connect_);
577 // Make a copy of |queued_connect_| parameters, because |queued_connect_|
578 // will get reset at the beginning of |ConnectToNetwork|.
579 std::string service_path = queued_connect_->service_path;
580 base::Closure success_callback = queued_connect_->success_callback;
581 network_handler::ErrorCallback error_callback =
582 queued_connect_->error_callback;
584 NET_LOG_EVENT("Connecting to Queued Network", service_path);
585 ConnectToNetwork(service_path, success_callback, error_callback,
586 false /* check_error_state */);
589 void NetworkConnectionHandler::CallShillConnect(
590 const std::string& service_path) {
591 NET_LOG_EVENT("Sending Connect Request to Shill", service_path);
592 network_state_handler_->ClearLastErrorForNetwork(service_path);
593 DBusThreadManager::Get()->GetShillServiceClient()->Connect(
594 dbus::ObjectPath(service_path),
595 base::Bind(&NetworkConnectionHandler::HandleShillConnectSuccess,
596 AsWeakPtr(), service_path),
597 base::Bind(&NetworkConnectionHandler::HandleShillConnectFailure,
598 AsWeakPtr(), service_path));
601 void NetworkConnectionHandler::HandleConfigurationFailure(
602 const std::string& service_path,
603 const std::string& error_name,
604 scoped_ptr<base::DictionaryValue> error_data) {
605 ConnectRequest* request = GetPendingRequest(service_path);
606 if (!request) {
607 NET_LOG_ERROR("HandleConfigurationFailure called with no pending request.",
608 service_path);
609 return;
611 network_handler::ErrorCallback error_callback = request->error_callback;
612 pending_requests_.erase(service_path);
613 if (!error_callback.is_null())
614 error_callback.Run(kErrorConfigureFailed, error_data.Pass());
617 void NetworkConnectionHandler::HandleShillConnectSuccess(
618 const std::string& service_path) {
619 ConnectRequest* request = GetPendingRequest(service_path);
620 if (!request) {
621 NET_LOG_ERROR("HandleShillConnectSuccess called with no pending request.",
622 service_path);
623 return;
625 request->connect_state = ConnectRequest::CONNECT_STARTED;
626 NET_LOG_EVENT("Connect Request Acknowledged", service_path);
627 // Do not call success_callback here, wait for one of the following
628 // conditions:
629 // * State transitions to a non connecting state indicating success or failure
630 // * Network is no longer in the visible list, indicating failure
631 CheckPendingRequest(service_path);
634 void NetworkConnectionHandler::HandleShillConnectFailure(
635 const std::string& service_path,
636 const std::string& dbus_error_name,
637 const std::string& dbus_error_message) {
638 ConnectRequest* request = GetPendingRequest(service_path);
639 if (!request) {
640 NET_LOG_ERROR("HandleShillConnectFailure called with no pending request.",
641 service_path);
642 return;
644 network_handler::ErrorCallback error_callback = request->error_callback;
645 pending_requests_.erase(service_path);
646 network_handler::ShillErrorCallbackFunction(
647 shill::kErrorConnectFailed, service_path, error_callback,
648 dbus_error_name, dbus_error_message);
651 void NetworkConnectionHandler::CheckPendingRequest(
652 const std::string service_path) {
653 ConnectRequest* request = GetPendingRequest(service_path);
654 DCHECK(request);
655 if (request->connect_state == ConnectRequest::CONNECT_REQUESTED)
656 return; // Request has not started, ignore update
657 const NetworkState* network =
658 network_state_handler_->GetNetworkState(service_path);
659 if (!network)
660 return; // NetworkState may not be be updated yet.
662 if (network->IsConnectingState()) {
663 request->connect_state = ConnectRequest::CONNECT_CONNECTING;
664 return;
666 if (network->IsConnectedState()) {
667 NET_LOG_EVENT("Connect Request Succeeded", service_path);
668 if (!request->profile_path.empty()) {
669 // If a profile path was specified, set it on a successful connection.
670 configuration_handler_->SetNetworkProfile(
671 service_path,
672 request->profile_path,
673 base::Bind(&base::DoNothing),
674 chromeos::network_handler::ErrorCallback());
676 if (!request->success_callback.is_null())
677 request->success_callback.Run();
678 pending_requests_.erase(service_path);
679 return;
681 if (network->connection_state() == shill::kStateIdle &&
682 request->connect_state != ConnectRequest::CONNECT_CONNECTING) {
683 // Connection hasn't started yet, keep waiting.
684 return;
687 // Network is neither connecting or connected; an error occurred.
688 std::string error_name; // 'Canceled' or 'Failed'
689 if (network->connection_state() == shill::kStateIdle &&
690 pending_requests_.size() > 1) {
691 // Another connect request canceled this one.
692 error_name = kErrorConnectCanceled;
693 } else {
694 error_name = shill::kErrorConnectFailed;
695 if (network->connection_state() != shill::kStateFailure) {
696 NET_LOG_ERROR("Unexpected State: " + network->connection_state(),
697 service_path);
701 network_handler::ErrorCallback error_callback = request->error_callback;
702 pending_requests_.erase(service_path);
703 if (error_callback.is_null()) {
704 NET_LOG_ERROR("Connect Error, no callback: " + error_name, service_path);
705 return;
707 InvokeErrorCallback(service_path, error_callback, error_name);
710 void NetworkConnectionHandler::CheckAllPendingRequests() {
711 for (std::map<std::string, ConnectRequest>::iterator iter =
712 pending_requests_.begin(); iter != pending_requests_.end(); ++iter) {
713 CheckPendingRequest(iter->first);
717 void NetworkConnectionHandler::ErrorCallbackForPendingRequest(
718 const std::string& service_path,
719 const std::string& error_name) {
720 ConnectRequest* request = GetPendingRequest(service_path);
721 if (!request) {
722 NET_LOG_ERROR("ErrorCallbackForPendingRequest with no pending request.",
723 service_path);
724 return;
726 // Remove the entry before invoking the callback in case it triggers a retry.
727 network_handler::ErrorCallback error_callback = request->error_callback;
728 pending_requests_.erase(service_path);
729 InvokeErrorCallback(service_path, error_callback, error_name);
732 // Disconnect
734 void NetworkConnectionHandler::CallShillDisconnect(
735 const std::string& service_path,
736 const base::Closure& success_callback,
737 const network_handler::ErrorCallback& error_callback) {
738 NET_LOG_USER("Disconnect Request", service_path);
739 DBusThreadManager::Get()->GetShillServiceClient()->Disconnect(
740 dbus::ObjectPath(service_path),
741 base::Bind(&NetworkConnectionHandler::HandleShillDisconnectSuccess,
742 AsWeakPtr(), service_path, success_callback),
743 base::Bind(&network_handler::ShillErrorCallbackFunction,
744 kErrorShillError, service_path, error_callback));
747 void NetworkConnectionHandler::HandleShillDisconnectSuccess(
748 const std::string& service_path,
749 const base::Closure& success_callback) {
750 NET_LOG_EVENT("Disconnect Request Sent", service_path);
751 if (!success_callback.is_null())
752 success_callback.Run();
755 } // namespace chromeos