| // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "net/socket/client_socket_factory.h" | 
 |  | 
 | #include "base/lazy_instance.h" | 
 | #include "base/thread_task_runner_handle.h" | 
 | #include "base/threading/sequenced_worker_pool.h" | 
 | #include "build/build_config.h" | 
 | #include "net/cert/cert_database.h" | 
 | #include "net/socket/client_socket_handle.h" | 
 | #if defined(USE_OPENSSL) | 
 | #include "net/socket/ssl_client_socket_openssl.h" | 
 | #elif defined(USE_NSS) || defined(OS_MACOSX) || defined(OS_WIN) | 
 | #include "net/socket/ssl_client_socket_nss.h" | 
 | #endif | 
 | #include "net/socket/tcp_client_socket.h" | 
 | #include "net/udp/udp_client_socket.h" | 
 |  | 
 | namespace net { | 
 |  | 
 | class X509Certificate; | 
 |  | 
 | namespace { | 
 |  | 
 | // ChromeOS and Linux may require interaction with smart cards or TPMs, which | 
 | // may cause NSS functions to block for upwards of several seconds. To avoid | 
 | // blocking all activity on the current task runner, such as network or IPC | 
 | // traffic, run NSS SSL functions on a dedicated thread. | 
 | #if defined(OS_CHROMEOS) || defined(OS_LINUX) | 
 | bool g_use_dedicated_nss_thread = true; | 
 | #else | 
 | bool g_use_dedicated_nss_thread = false; | 
 | #endif | 
 |  | 
 | class DefaultClientSocketFactory : public ClientSocketFactory, | 
 |                                    public CertDatabase::Observer { | 
 |  public: | 
 |   DefaultClientSocketFactory() { | 
 |     if (g_use_dedicated_nss_thread) { | 
 |       // Use a single thread for the worker pool. | 
 |       worker_pool_ = new base::SequencedWorkerPool(1, "NSS SSL Thread"); | 
 |       nss_thread_task_runner_ = | 
 |           worker_pool_->GetSequencedTaskRunnerWithShutdownBehavior( | 
 |               worker_pool_->GetSequenceToken(), | 
 |               base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN); | 
 |     } | 
 |  | 
 |     CertDatabase::GetInstance()->AddObserver(this); | 
 |   } | 
 |  | 
 |   ~DefaultClientSocketFactory() override { | 
 |     // Note: This code never runs, as the factory is defined as a Leaky | 
 |     // singleton. | 
 |     CertDatabase::GetInstance()->RemoveObserver(this); | 
 |   } | 
 |  | 
 |   void OnCertAdded(const X509Certificate* cert) override { | 
 |     ClearSSLSessionCache(); | 
 |   } | 
 |  | 
 |   void OnCACertChanged(const X509Certificate* cert) override { | 
 |     // Per wtc, we actually only need to flush when trust is reduced. | 
 |     // Always flush now because OnCACertChanged does not tell us this. | 
 |     // See comments in ClientSocketPoolManager::OnCACertChanged. | 
 |     ClearSSLSessionCache(); | 
 |   } | 
 |  | 
 |   scoped_ptr<DatagramClientSocket> CreateDatagramClientSocket( | 
 |       DatagramSocket::BindType bind_type, | 
 |       const RandIntCallback& rand_int_cb, | 
 |       NetLog* net_log, | 
 |       const NetLog::Source& source) override { | 
 |     return scoped_ptr<DatagramClientSocket>( | 
 |         new UDPClientSocket(bind_type, rand_int_cb, net_log, source)); | 
 |   } | 
 |  | 
 |   scoped_ptr<StreamSocket> CreateTransportClientSocket( | 
 |       const AddressList& addresses, | 
 |       NetLog* net_log, | 
 |       const NetLog::Source& source) override { | 
 |     return scoped_ptr<StreamSocket>( | 
 |         new TCPClientSocket(addresses, net_log, source)); | 
 |   } | 
 |  | 
 |   scoped_ptr<SSLClientSocket> CreateSSLClientSocket( | 
 |       scoped_ptr<ClientSocketHandle> transport_socket, | 
 |       const HostPortPair& host_and_port, | 
 |       const SSLConfig& ssl_config, | 
 |       const SSLClientSocketContext& context) override { | 
 |     // nss_thread_task_runner_ may be NULL if g_use_dedicated_nss_thread is | 
 |     // false or if the dedicated NSS thread failed to start. If so, cause NSS | 
 |     // functions to execute on the current task runner. | 
 |     // | 
 |     // Note: The current task runner is obtained on each call due to unit | 
 |     // tests, which may create and tear down the current thread's TaskRunner | 
 |     // between each test. Because the DefaultClientSocketFactory is leaky, it | 
 |     // may span multiple tests, and thus the current task runner may change | 
 |     // from call to call. | 
 |     scoped_refptr<base::SequencedTaskRunner> nss_task_runner( | 
 |         nss_thread_task_runner_); | 
 |     if (!nss_task_runner.get()) | 
 |       nss_task_runner = base::ThreadTaskRunnerHandle::Get(); | 
 |  | 
 | #if defined(USE_OPENSSL) | 
 |     return scoped_ptr<SSLClientSocket>( | 
 |         new SSLClientSocketOpenSSL(transport_socket.Pass(), host_and_port, | 
 |                                    ssl_config, context)); | 
 | #elif defined(USE_NSS) || defined(OS_MACOSX) || defined(OS_WIN) | 
 |     return scoped_ptr<SSLClientSocket>( | 
 |         new SSLClientSocketNSS(nss_task_runner.get(), | 
 |                                transport_socket.Pass(), | 
 |                                host_and_port, | 
 |                                ssl_config, | 
 |                                context)); | 
 | #else | 
 |     NOTIMPLEMENTED(); | 
 |     return scoped_ptr<SSLClientSocket>(); | 
 | #endif | 
 |   } | 
 |  | 
 |   void ClearSSLSessionCache() override { SSLClientSocket::ClearSessionCache(); } | 
 |  | 
 |  private: | 
 |   scoped_refptr<base::SequencedWorkerPool> worker_pool_; | 
 |   scoped_refptr<base::SequencedTaskRunner> nss_thread_task_runner_; | 
 | }; | 
 |  | 
 | static base::LazyInstance<DefaultClientSocketFactory>::Leaky | 
 |     g_default_client_socket_factory = LAZY_INSTANCE_INITIALIZER; | 
 |  | 
 | }  // namespace | 
 |  | 
 | // static | 
 | ClientSocketFactory* ClientSocketFactory::GetDefaultFactory() { | 
 |   return g_default_client_socket_factory.Pointer(); | 
 | } | 
 |  | 
 | }  // namespace net |