1// Copyright (c) 2012 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.
4
5#include "net/socket/client_socket_factory.h"
6
7#include "base/lazy_instance.h"
8#include "base/thread_task_runner_handle.h"
9#include "base/threading/sequenced_worker_pool.h"
10#include "build/build_config.h"
11#include "net/cert/cert_database.h"
12#include "net/socket/client_socket_handle.h"
13#if defined(USE_OPENSSL)
14#include "net/socket/ssl_client_socket_openssl.h"
15#elif defined(USE_NSS) || defined(OS_MACOSX) || defined(OS_WIN)
16#include "net/socket/ssl_client_socket_nss.h"
17#endif
18#include "net/socket/tcp_client_socket.h"
19#include "net/udp/udp_client_socket.h"
20
21namespace net {
22
23class X509Certificate;
24
25namespace {
26
27// ChromeOS and Linux may require interaction with smart cards or TPMs, which
28// may cause NSS functions to block for upwards of several seconds. To avoid
29// blocking all activity on the current task runner, such as network or IPC
30// traffic, run NSS SSL functions on a dedicated thread.
31#if defined(OS_CHROMEOS) || defined(OS_LINUX)
32bool g_use_dedicated_nss_thread = true;
33#else
34bool g_use_dedicated_nss_thread = false;
35#endif
36
37class DefaultClientSocketFactory : public ClientSocketFactory,
38                                   public CertDatabase::Observer {
39 public:
40  DefaultClientSocketFactory() {
41    if (g_use_dedicated_nss_thread) {
42      // Use a single thread for the worker pool.
43      worker_pool_ = new base::SequencedWorkerPool(1, "NSS SSL Thread");
44      nss_thread_task_runner_ =
45          worker_pool_->GetSequencedTaskRunnerWithShutdownBehavior(
46              worker_pool_->GetSequenceToken(),
47              base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
48    }
49
50    CertDatabase::GetInstance()->AddObserver(this);
51  }
52
53  virtual ~DefaultClientSocketFactory() {
54    // Note: This code never runs, as the factory is defined as a Leaky
55    // singleton.
56    CertDatabase::GetInstance()->RemoveObserver(this);
57  }
58
59  virtual void OnCertAdded(const X509Certificate* cert) OVERRIDE {
60    ClearSSLSessionCache();
61  }
62
63  virtual void OnCACertChanged(const X509Certificate* cert) OVERRIDE {
64    // Per wtc, we actually only need to flush when trust is reduced.
65    // Always flush now because OnCACertChanged does not tell us this.
66    // See comments in ClientSocketPoolManager::OnCACertChanged.
67    ClearSSLSessionCache();
68  }
69
70  virtual scoped_ptr<DatagramClientSocket> CreateDatagramClientSocket(
71      DatagramSocket::BindType bind_type,
72      const RandIntCallback& rand_int_cb,
73      NetLog* net_log,
74      const NetLog::Source& source) OVERRIDE {
75    return scoped_ptr<DatagramClientSocket>(
76        new UDPClientSocket(bind_type, rand_int_cb, net_log, source));
77  }
78
79  virtual scoped_ptr<StreamSocket> CreateTransportClientSocket(
80      const AddressList& addresses,
81      NetLog* net_log,
82      const NetLog::Source& source) OVERRIDE {
83    return scoped_ptr<StreamSocket>(
84        new TCPClientSocket(addresses, net_log, source));
85  }
86
87  virtual scoped_ptr<SSLClientSocket> CreateSSLClientSocket(
88      scoped_ptr<ClientSocketHandle> transport_socket,
89      const HostPortPair& host_and_port,
90      const SSLConfig& ssl_config,
91      const SSLClientSocketContext& context) OVERRIDE {
92    // nss_thread_task_runner_ may be NULL if g_use_dedicated_nss_thread is
93    // false or if the dedicated NSS thread failed to start. If so, cause NSS
94    // functions to execute on the current task runner.
95    //
96    // Note: The current task runner is obtained on each call due to unit
97    // tests, which may create and tear down the current thread's TaskRunner
98    // between each test. Because the DefaultClientSocketFactory is leaky, it
99    // may span multiple tests, and thus the current task runner may change
100    // from call to call.
101    scoped_refptr<base::SequencedTaskRunner> nss_task_runner(
102        nss_thread_task_runner_);
103    if (!nss_task_runner.get())
104      nss_task_runner = base::ThreadTaskRunnerHandle::Get();
105
106#if defined(USE_OPENSSL)
107    return scoped_ptr<SSLClientSocket>(
108        new SSLClientSocketOpenSSL(transport_socket.Pass(), host_and_port,
109                                   ssl_config, context));
110#elif defined(USE_NSS) || defined(OS_MACOSX) || defined(OS_WIN)
111    return scoped_ptr<SSLClientSocket>(
112        new SSLClientSocketNSS(nss_task_runner.get(),
113                               transport_socket.Pass(),
114                               host_and_port,
115                               ssl_config,
116                               context));
117#else
118    NOTIMPLEMENTED();
119    return scoped_ptr<SSLClientSocket>();
120#endif
121  }
122
123  virtual void ClearSSLSessionCache() OVERRIDE {
124    SSLClientSocket::ClearSessionCache();
125  }
126
127 private:
128  scoped_refptr<base::SequencedWorkerPool> worker_pool_;
129  scoped_refptr<base::SequencedTaskRunner> nss_thread_task_runner_;
130};
131
132static base::LazyInstance<DefaultClientSocketFactory>::Leaky
133    g_default_client_socket_factory = LAZY_INSTANCE_INITIALIZER;
134
135}  // namespace
136
137// static
138ClientSocketFactory* ClientSocketFactory::GetDefaultFactory() {
139  return g_default_client_socket_factory.Pointer();
140}
141
142}  // namespace net
143