Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(128)

Side by Side Diff: chrome/browser/extensions/api/socket/ssl_socket.cc

Issue 10580028: Experimental support for SSL in platform apps sockets. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Rebase. Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 "chrome/browser/extensions/api/socket/ssl_socket.h"
6
7 #include "chrome/browser/extensions/api/api_resource.h"
8 #include "chrome/browser/extensions/api/api_resource_event_notifier.h"
9 #include "net/base/address_list.h"
10 #include "net/base/cert_verifier.h"
11 #include "net/base/host_port_pair.h"
12 #include "net/base/ip_endpoint.h"
13 #include "net/base/net_errors.h"
14 #include "net/base/rand_callback.h"
15 #include "net/base/ssl_config_service.h"
16 #include "net/socket/client_socket_factory.h"
17 #include "net/socket/client_socket_handle.h"
18 #include "net/socket/tcp_client_socket.h"
19
20 // SSLSocket starts out as a TCP socket in SSLSTATE_NONE. When a handshake
21 // request is made, it transitions to SSLSTATE_WAIT. If there are no pending
22 // read or write requests on the TCP socket, an SSL client socket is then
23 // created and asked to perform the handshake. Otherwise, SSLSocket
24 // continues to attempt to start the handshake after every pending read
25 // and write request completes. While in SSLSTATE_WAIT, no new read or
26 // write requests may be issued (and are replied to with an immediate
27 // net::ERR_IO_PENDING).
28 //
29 // If the SSL handshake succeeds, SSLSocket enters SSLSTATE_CONNECTED
30 // and all read and write requests go over the secure channel. If
31 // the SSL handshake fails, SSLSocket enters SSLSTATE_ERROR and no
32 // further read or write requests may be made until the socket is
33 // closed.
34
35 namespace extensions {
36
37 SSLSocket::SSLSocket(extensions::APIResourceEventNotifier* event_notifier)
38 : Socket(event_notifier),
39 ssl_state_(SSLSTATE_NONE) {
40 }
41
42 // For testing.
43 SSLSocket::SSLSocket(net::TCPClientSocket* tcp_client_socket,
44 APIResourceEventNotifier* event_notifier)
45 : Socket(event_notifier),
46 socket_(tcp_client_socket),
47 ssl_state_(SSLSTATE_NONE) {
48 }
49
50 // static
51 SSLSocket* SSLSocket::CreateSocketForTesting(
52 net::TCPClientSocket* tcp_client_socket,
53 APIResourceEventNotifier* event_notifier) {
54 return new SSLSocket(tcp_client_socket, event_notifier);
55 }
56
57 SSLSocket::~SSLSocket() {
58 if (is_connected_) {
59 Disconnect();
60 }
61 }
62
63 void SSLSocket::Connect(const std::string& address,
64 int port,
65 const CompletionCallback& callback) {
66 DCHECK(!callback.is_null());
67
68 if (!connect_callback_.is_null()) {
69 callback.Run(net::ERR_CONNECTION_FAILED);
70 return;
71 }
72 connect_callback_ = callback;
73
74 int result = net::ERR_CONNECTION_FAILED;
75 do {
76 if (is_connected_)
77 break;
78
79 net::AddressList address_list;
80 if (!StringAndPortToAddressList(address, port, &address_list)) {
81 result = net::ERR_ADDRESS_INVALID;
82 break;
83 }
84
85 socket_.reset(new net::TCPClientSocket(address_list, NULL,
86 net::NetLog::Source()));
87 connect_callback_ = callback;
88 result = socket_->Connect(base::Bind(
89 &SSLSocket::OnConnectComplete, base::Unretained(this)));
90 } while (false);
91
92 if (result != net::ERR_IO_PENDING)
93 OnConnectComplete(result);
94 }
95
96 void SSLSocket::PerformSSLHandshake(const std::string& ssl_hostname,
97 int ssl_port,
98 const CompletionCallback& callback) {
99 DCHECK(!callback.is_null());
100
101 if (ssl_state_ == SSLSTATE_WAIT) {
102 callback.Run(net::ERR_IO_PENDING);
103 return;
104 } else if (ssl_state_ == SSLSTATE_ERROR) {
105 callback.Run(net::ERR_FAILED);
106 return;
107 } else if (ssl_state_ == SSLSTATE_CONNECTED) {
108 callback.Run(net::ERR_FAILED);
109 return;
110 }
111 DCHECK(ssl_state_ == SSLSTATE_NONE);
112
113 handshake_callback_ = callback;
114 ssl_state_ = SSLSTATE_WAIT;
115 ssl_port_ = ssl_port;
116 ssl_hostname_ = ssl_hostname;
117
118 AttemptSSLHandshake();
119 }
120
121 void SSLSocket::AttemptSSLHandshake() {
122 DCHECK(ssl_state_ == SSLSTATE_WAIT);
123
124 // We have to wait until outstanding I/O requests are
125 // complete before we perform the SSL handshake.
126 if (!read_callback_.is_null()) {
127 VLOG(1) << "AttemptSSLHandshake aborting (pending callback).";
128 return;
129 }
130
131 if (!write_queue_empty()) {
132 VLOG(1) << "AttemptSSLHandshake aborting (pending writes).";
133 return;
134 }
135
136 if (!socket_.get() || !socket_->IsConnected()) {
137 OnHandshakeComplete(net::ERR_SOCKET_NOT_CONNECTED);
138 return;
139 }
140
141 VLOG(2) << "AttemptSSLHandshake running handshake.";
142
143 // see remoting/jingle_glue/ssl_socket_adapter.cc
144 ssl_socket_.reset();
145 cert_verifier_.reset(net::CertVerifier::CreateDefault());
146
147 // We'll use the default configuration to avoid issues wrt
148 // thread-safety and SSLConfigService.
149 net::SSLConfig ssl_config;
Ryan Sleevi 2012/07/09 20:55:45 This is not a good pattern. You should use the Pro
150 net::SSLClientSocketContext context;
151 context.cert_verifier = cert_verifier_.get();
152
153 // ClientSocketHandle::set_socket takes ownership of the socket...
154 net::ClientSocketHandle* socket_handle = new net::ClientSocketHandle();
155 socket_handle->set_socket(socket_.release());
156
157 // ... and the SSL socket takes ownership of the socket handle.
158 ssl_socket_.reset(
159 net::ClientSocketFactory::GetDefaultFactory()->CreateSSLClientSocket(
160 socket_handle,
161 net::HostPortPair(ssl_hostname_, ssl_port_),
162 ssl_config,
163 context));
164
165 int result = ssl_socket_->Connect(base::Bind(
166 &SSLSocket::OnHandshakeComplete, base::Unretained(this)));
167
168 if (result != net::ERR_IO_PENDING) {
169 OnHandshakeComplete(result);
170 }
171 }
172
173 void SSLSocket::Disconnect() {
174 if (ssl_socket_.get()) {
175 ssl_socket_->Disconnect();
176 } else if (socket_.get()) {
177 socket_->Disconnect();
178 }
179
180 ssl_state_ = SSLSTATE_NONE;
181 is_connected_ = false;
182 }
183
184 int SSLSocket::Bind(const std::string& address, int port) {
185 // TODO(penghuang): Supports bind for tcp?
186 return net::ERR_FAILED;
187 }
188
189 void SSLSocket::Read(int count,
190 const ReadCompletionCallback& callback) {
191 DCHECK(!callback.is_null());
192
193 if (!read_callback_.is_null() || ssl_state_ == SSLSTATE_WAIT) {
194 callback.Run(net::ERR_IO_PENDING, NULL);
195 return;
196 } else if (ssl_state_ == SSLSTATE_ERROR) {
197 callback.Run(net::ERR_FAILED, NULL);
198 return;
199 } else {
200 read_callback_ = callback;
201 }
202
203 int result = net::ERR_FAILED;
204 scoped_refptr<net::IOBuffer> io_buffer;
205 do {
206 if (count < 0) {
207 result = net::ERR_INVALID_ARGUMENT;
208 break;
209 }
210
211 if (ssl_state_ == SSLSTATE_CONNECTED) {
212 if (!ssl_socket_.get() || !ssl_socket_->IsConnected()) {
213 result = net::ERR_SOCKET_NOT_CONNECTED;
214 break;
215 }
216 DVLOG(2) << "Reading from SSL socket.";
217 io_buffer = new net::IOBuffer(count);
218 result = ssl_socket_->Read(io_buffer.get(), count,
219 base::Bind(&SSLSocket::OnReadComplete, base::Unretained(this),
220 io_buffer));
221 } else {
222 if (!socket_.get() || !socket_->IsConnected()) {
223 result = net::ERR_SOCKET_NOT_CONNECTED;
224 break;
225 }
226 DVLOG(2) << "Reading from normal socket.";
227 io_buffer = new net::IOBuffer(count);
228 result = socket_->Read(io_buffer.get(), count,
229 base::Bind(&SSLSocket::OnReadComplete, base::Unretained(this),
230 io_buffer));
231 }
232 } while (false);
233
234 if (result != net::ERR_IO_PENDING)
235 OnReadComplete(io_buffer, result);
236 }
237
238 void SSLSocket::RecvFrom(int count,
239 const RecvFromCompletionCallback& callback) {
240 callback.Run(net::ERR_FAILED, NULL, NULL, 0);
241 }
242
243 void SSLSocket::SendTo(scoped_refptr<net::IOBuffer> io_buffer,
244 int byte_count,
245 const std::string& address,
246 int port,
247 const CompletionCallback& callback) {
248 callback.Run(net::ERR_FAILED);
249 }
250
251 bool SSLSocket::SetKeepAlive(bool enable, int delay) {
252 if (!socket_.get())
253 return false;
254 return socket_->SetKeepAlive(enable, delay);
255 }
256
257 bool SSLSocket::SetNoDelay(bool no_delay) {
258 if (!socket_.get())
259 return false;
260 return socket_->SetNoDelay(no_delay);
261 }
262
263 int SSLSocket::WriteImpl(net::IOBuffer* io_buffer,
264 int io_buffer_size,
265 const net::CompletionCallback& callback) {
266 if (ssl_state_ == SSLSTATE_CONNECTED) {
267 if (!ssl_socket_.get() || !ssl_socket_->IsConnected())
268 return net::ERR_SOCKET_NOT_CONNECTED;
269 DVLOG(2) << "Writing " << io_buffer_size << "B to SSL socket.";
270 return ssl_socket_->Write(io_buffer, io_buffer_size, callback);
271 } else if (ssl_state_ == SSLSTATE_NONE) {
272 if (!socket_.get() || !socket_->IsConnected())
273 return net::ERR_SOCKET_NOT_CONNECTED;
274 DVLOG(2) << "Writing " << io_buffer_size << "B to normal socket.";
275 return socket_->Write(io_buffer, io_buffer_size, callback);
276 } else if (ssl_state_ == SSLSTATE_WAIT && socket_.get()) {
277 // Write dregs out to the insecure socket. We'll complete the handshake
278 // once the write queue empties.
279 if (!socket_.get() || !socket_->IsConnected())
280 return net::ERR_SOCKET_NOT_CONNECTED;
281 DVLOG(2) << "Writing " << io_buffer_size
282 << "B to normal socket (in SSLSTATE_WAIT).";
283 return socket_->Write(io_buffer, io_buffer_size, callback);
284 } else {
285 VLOG(1) << "Bad state for writing.";
286 return net::ERR_FAILED;
287 }
288 }
289
290 void SSLSocket::OnConnectComplete(int result) {
291 DCHECK(!connect_callback_.is_null());
292 DCHECK(!is_connected_);
293 is_connected_ = result == net::OK;
294 connect_callback_.Run(result);
295 connect_callback_.Reset();
296 }
297
298 void SSLSocket::OnHandshakeComplete(int result) {
299 DCHECK(!handshake_callback_.is_null());
300 DCHECK(ssl_state_ == SSLSTATE_WAIT);
301 ssl_state_ = result == net::OK ? SSLSTATE_CONNECTED : SSLSTATE_ERROR;
302 handshake_callback_.Run(result);
303 handshake_callback_.Reset();
304 }
305
306 void SSLSocket::OnReadComplete(scoped_refptr<net::IOBuffer> io_buffer,
307 int result) {
308 DCHECK(!read_callback_.is_null());
309 read_callback_.Run(result, io_buffer);
310 read_callback_.Reset();
311 DVLOG(2) << "OnReadComplete in state " << ssl_state_;
312 if (ssl_state_ == SSLSTATE_WAIT) {
313 AttemptSSLHandshake();
314 }
315 }
316
317 void SSLSocket::OnWriteComplete(int result) {
318 Socket::OnWriteComplete(result);
319 DVLOG(2) << "OnWriteComplete in state " << ssl_state_;
320 if (ssl_state_ == SSLSTATE_WAIT) {
321 AttemptSSLHandshake();
322 }
323 }
324
325 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698