OLD | NEW |
| (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 "content/browser/renderer_host/pepper_tcp_socket.h" | |
6 | |
7 #include <string.h> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/bind_helpers.h" | |
11 #include "base/compiler_specific.h" | |
12 #include "base/logging.h" | |
13 #include "base/string_util.h" | |
14 #include "content/browser/renderer_host/pepper_message_filter.h" | |
15 #include "content/public/browser/browser_thread.h" | |
16 #include "net/base/cert_verifier.h" | |
17 #include "net/base/host_port_pair.h" | |
18 #include "net/base/host_resolver.h" | |
19 #include "net/base/io_buffer.h" | |
20 #include "net/base/ip_endpoint.h" | |
21 #include "net/base/net_errors.h" | |
22 #include "net/base/single_request_host_resolver.h" | |
23 #include "net/base/x509_certificate.h" | |
24 #include "net/socket/client_socket_factory.h" | |
25 #include "net/socket/client_socket_handle.h" | |
26 #include "net/socket/ssl_client_socket.h" | |
27 #include "net/socket/tcp_client_socket.h" | |
28 #include "ppapi/proxy/ppapi_messages.h" | |
29 #include "ppapi/shared_impl/private/net_address_private_impl.h" | |
30 #include "ppapi/shared_impl/private/ppb_x509_certificate_private_shared.h" | |
31 #include "ppapi/shared_impl/private/tcp_socket_private_impl.h" | |
32 | |
33 using content::BrowserThread; | |
34 using ppapi::NetAddressPrivateImpl; | |
35 | |
36 PepperTCPSocket::PepperTCPSocket( | |
37 PepperMessageFilter* manager, | |
38 int32 routing_id, | |
39 uint32 plugin_dispatcher_id, | |
40 uint32 socket_id) | |
41 : manager_(manager), | |
42 routing_id_(routing_id), | |
43 plugin_dispatcher_id_(plugin_dispatcher_id), | |
44 socket_id_(socket_id), | |
45 connection_state_(BEFORE_CONNECT), | |
46 end_of_file_reached_(false) { | |
47 DCHECK(manager); | |
48 } | |
49 | |
50 PepperTCPSocket::PepperTCPSocket( | |
51 PepperMessageFilter* manager, | |
52 int32 routing_id, | |
53 uint32 plugin_dispatcher_id, | |
54 uint32 socket_id, | |
55 net::StreamSocket* socket) | |
56 : manager_(manager), | |
57 routing_id_(routing_id), | |
58 plugin_dispatcher_id_(plugin_dispatcher_id), | |
59 socket_id_(socket_id), | |
60 connection_state_(CONNECTED), | |
61 end_of_file_reached_(false), | |
62 socket_(socket) { | |
63 DCHECK(manager); | |
64 } | |
65 | |
66 PepperTCPSocket::~PepperTCPSocket() { | |
67 // Make sure no further callbacks from socket_. | |
68 if (socket_.get()) | |
69 socket_->Disconnect(); | |
70 } | |
71 | |
72 void PepperTCPSocket::Connect(const std::string& host, uint16_t port) { | |
73 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
74 | |
75 if (connection_state_ != BEFORE_CONNECT) { | |
76 SendConnectACKError(); | |
77 return; | |
78 } | |
79 | |
80 connection_state_ = CONNECT_IN_PROGRESS; | |
81 net::HostResolver::RequestInfo request_info(net::HostPortPair(host, port)); | |
82 resolver_.reset(new net::SingleRequestHostResolver( | |
83 manager_->GetHostResolver())); | |
84 int result = resolver_->Resolve( | |
85 request_info, &address_list_, | |
86 base::Bind(&PepperTCPSocket::OnResolveCompleted, base::Unretained(this)), | |
87 net::BoundNetLog()); | |
88 if (result != net::ERR_IO_PENDING) | |
89 OnResolveCompleted(result); | |
90 } | |
91 | |
92 void PepperTCPSocket::ConnectWithNetAddress( | |
93 const PP_NetAddress_Private& net_addr) { | |
94 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
95 | |
96 if (connection_state_ != BEFORE_CONNECT || | |
97 !NetAddressPrivateImpl::NetAddressToAddressList(net_addr, | |
98 &address_list_)) { | |
99 SendConnectACKError(); | |
100 return; | |
101 } | |
102 | |
103 connection_state_ = CONNECT_IN_PROGRESS; | |
104 StartConnect(address_list_); | |
105 } | |
106 | |
107 void PepperTCPSocket::SSLHandshake( | |
108 const std::string& server_name, | |
109 uint16_t server_port, | |
110 const std::vector<std::vector<char> >& trusted_certs, | |
111 const std::vector<std::vector<char> >& untrusted_certs) { | |
112 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
113 | |
114 // Allow to do SSL handshake only if currently the socket has been connected | |
115 // and there isn't pending read or write. | |
116 // IsConnected() includes the state that SSL handshake has been finished and | |
117 // therefore isn't suitable here. | |
118 if (connection_state_ != CONNECTED || read_buffer_.get() || | |
119 write_buffer_.get()) { | |
120 SendSSLHandshakeACK(false); | |
121 return; | |
122 } | |
123 | |
124 connection_state_ = SSL_HANDSHAKE_IN_PROGRESS; | |
125 // TODO(raymes,rsleevi): Use trusted/untrusted certificates when connecting. | |
126 | |
127 net::ClientSocketHandle* handle = new net::ClientSocketHandle(); | |
128 handle->set_socket(socket_.release()); | |
129 net::ClientSocketFactory* factory = | |
130 net::ClientSocketFactory::GetDefaultFactory(); | |
131 net::HostPortPair host_port_pair(server_name, server_port); | |
132 net::SSLClientSocketContext ssl_context; | |
133 ssl_context.cert_verifier = manager_->GetCertVerifier(); | |
134 socket_.reset(factory->CreateSSLClientSocket( | |
135 handle, host_port_pair, manager_->ssl_config(), ssl_context)); | |
136 if (!socket_.get()) { | |
137 LOG(WARNING) << "Failed to create an SSL client socket."; | |
138 OnSSLHandshakeCompleted(net::ERR_UNEXPECTED); | |
139 return; | |
140 } | |
141 | |
142 int result = socket_->Connect( | |
143 base::Bind(&PepperTCPSocket::OnSSLHandshakeCompleted, | |
144 base::Unretained(this))); | |
145 if (result != net::ERR_IO_PENDING) | |
146 OnSSLHandshakeCompleted(result); | |
147 } | |
148 | |
149 void PepperTCPSocket::Read(int32 bytes_to_read) { | |
150 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
151 | |
152 if (!IsConnected() || end_of_file_reached_ || read_buffer_.get() || | |
153 bytes_to_read <= 0) { | |
154 SendReadACKError(); | |
155 return; | |
156 } | |
157 | |
158 if (bytes_to_read > ppapi::TCPSocketPrivateImpl::kMaxReadSize) { | |
159 NOTREACHED(); | |
160 bytes_to_read = ppapi::TCPSocketPrivateImpl::kMaxReadSize; | |
161 } | |
162 | |
163 read_buffer_ = new net::IOBuffer(bytes_to_read); | |
164 int result = socket_->Read(read_buffer_, bytes_to_read, | |
165 base::Bind(&PepperTCPSocket::OnReadCompleted, | |
166 base::Unretained(this))); | |
167 if (result != net::ERR_IO_PENDING) | |
168 OnReadCompleted(result); | |
169 } | |
170 | |
171 void PepperTCPSocket::Write(const std::string& data) { | |
172 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
173 | |
174 if (!IsConnected() || write_buffer_.get() || data.empty()) { | |
175 SendWriteACKError(); | |
176 return; | |
177 } | |
178 | |
179 int data_size = data.size(); | |
180 if (data_size > ppapi::TCPSocketPrivateImpl::kMaxWriteSize) { | |
181 NOTREACHED(); | |
182 data_size = ppapi::TCPSocketPrivateImpl::kMaxWriteSize; | |
183 } | |
184 | |
185 write_buffer_ = new net::IOBuffer(data_size); | |
186 memcpy(write_buffer_->data(), data.c_str(), data_size); | |
187 int result = socket_->Write(write_buffer_, data.size(), | |
188 base::Bind(&PepperTCPSocket::OnWriteCompleted, | |
189 base::Unretained(this))); | |
190 if (result != net::ERR_IO_PENDING) | |
191 OnWriteCompleted(result); | |
192 } | |
193 | |
194 void PepperTCPSocket::StartConnect(const net::AddressList& addresses) { | |
195 DCHECK(connection_state_ == CONNECT_IN_PROGRESS); | |
196 | |
197 socket_.reset( | |
198 new net::TCPClientSocket(addresses, NULL, net::NetLog::Source())); | |
199 int result = socket_->Connect( | |
200 base::Bind(&PepperTCPSocket::OnConnectCompleted, | |
201 base::Unretained(this))); | |
202 if (result != net::ERR_IO_PENDING) | |
203 OnConnectCompleted(result); | |
204 } | |
205 | |
206 void PepperTCPSocket::SendConnectACKError() { | |
207 manager_->Send(new PpapiMsg_PPBTCPSocket_ConnectACK( | |
208 routing_id_, plugin_dispatcher_id_, socket_id_, false, | |
209 NetAddressPrivateImpl::kInvalidNetAddress, | |
210 NetAddressPrivateImpl::kInvalidNetAddress)); | |
211 } | |
212 | |
213 // static | |
214 bool PepperTCPSocket::GetCertificateFields( | |
215 const net::X509Certificate& cert, | |
216 ppapi::PPB_X509Certificate_Fields* fields) { | |
217 const net::CertPrincipal& issuer = cert.issuer(); | |
218 fields->SetField(PP_X509CERTIFICATE_PRIVATE_ISSUER_COMMON_NAME, | |
219 new base::StringValue(issuer.common_name)); | |
220 fields->SetField(PP_X509CERTIFICATE_PRIVATE_ISSUER_LOCALITY_NAME, | |
221 new base::StringValue(issuer.locality_name)); | |
222 fields->SetField(PP_X509CERTIFICATE_PRIVATE_ISSUER_STATE_OR_PROVINCE_NAME, | |
223 new base::StringValue(issuer.state_or_province_name)); | |
224 fields->SetField(PP_X509CERTIFICATE_PRIVATE_ISSUER_COUNTRY_NAME, | |
225 new base::StringValue(issuer.country_name)); | |
226 fields->SetField(PP_X509CERTIFICATE_PRIVATE_ISSUER_ORGANIZATION_NAME, | |
227 new base::StringValue(JoinString(issuer.organization_names, '\n'))); | |
228 fields->SetField(PP_X509CERTIFICATE_PRIVATE_ISSUER_ORGANIZATION_UNIT_NAME, | |
229 new base::StringValue(JoinString(issuer.organization_unit_names, '\n'))); | |
230 | |
231 const net::CertPrincipal& subject = cert.subject(); | |
232 fields->SetField(PP_X509CERTIFICATE_PRIVATE_SUBJECT_COMMON_NAME, | |
233 new base::StringValue(subject.common_name)); | |
234 fields->SetField(PP_X509CERTIFICATE_PRIVATE_SUBJECT_LOCALITY_NAME, | |
235 new base::StringValue(subject.locality_name)); | |
236 fields->SetField(PP_X509CERTIFICATE_PRIVATE_SUBJECT_STATE_OR_PROVINCE_NAME, | |
237 new base::StringValue(subject.state_or_province_name)); | |
238 fields->SetField(PP_X509CERTIFICATE_PRIVATE_SUBJECT_COUNTRY_NAME, | |
239 new base::StringValue(subject.country_name)); | |
240 fields->SetField(PP_X509CERTIFICATE_PRIVATE_SUBJECT_ORGANIZATION_NAME, | |
241 new base::StringValue(JoinString(subject.organization_names, '\n'))); | |
242 fields->SetField(PP_X509CERTIFICATE_PRIVATE_SUBJECT_ORGANIZATION_UNIT_NAME, | |
243 new base::StringValue(JoinString(subject.organization_unit_names, '\n'))); | |
244 | |
245 const std::string& serial_number = cert.serial_number(); | |
246 fields->SetField(PP_X509CERTIFICATE_PRIVATE_SERIAL_NUMBER, | |
247 base::BinaryValue::CreateWithCopiedBuffer(serial_number.data(), | |
248 serial_number.length())); | |
249 fields->SetField(PP_X509CERTIFICATE_PRIVATE_VALIDITY_NOT_BEFORE, | |
250 base::Value::CreateDoubleValue(cert.valid_start().ToDoubleT())); | |
251 fields->SetField(PP_X509CERTIFICATE_PRIVATE_VALIDITY_NOT_AFTER, | |
252 base::Value::CreateDoubleValue(cert.valid_expiry().ToDoubleT())); | |
253 std::string der; | |
254 net::X509Certificate::GetDEREncoded(cert.os_cert_handle(), &der); | |
255 fields->SetField(PP_X509CERTIFICATE_PRIVATE_RAW, | |
256 base::BinaryValue::CreateWithCopiedBuffer(der.data(), der.length())); | |
257 return true; | |
258 } | |
259 | |
260 // static | |
261 bool PepperTCPSocket::GetCertificateFields( | |
262 const char* der, | |
263 uint32_t length, | |
264 ppapi::PPB_X509Certificate_Fields* fields) { | |
265 scoped_refptr<net::X509Certificate> cert = | |
266 net::X509Certificate::CreateFromBytes(der, length); | |
267 if (!cert.get()) | |
268 return false; | |
269 return GetCertificateFields(*cert, fields); | |
270 } | |
271 | |
272 void PepperTCPSocket::SendReadACKError() { | |
273 manager_->Send(new PpapiMsg_PPBTCPSocket_ReadACK( | |
274 routing_id_, plugin_dispatcher_id_, socket_id_, false, std::string())); | |
275 } | |
276 | |
277 void PepperTCPSocket::SendWriteACKError() { | |
278 manager_->Send(new PpapiMsg_PPBTCPSocket_WriteACK( | |
279 routing_id_, plugin_dispatcher_id_, socket_id_, false, 0)); | |
280 } | |
281 | |
282 void PepperTCPSocket::SendSSLHandshakeACK(bool succeeded) { | |
283 ppapi::PPB_X509Certificate_Fields certificate_fields; | |
284 if (succeeded) { | |
285 // Our socket is guaranteed to be an SSL socket if we get here. | |
286 net::SSLClientSocket* ssl_socket = | |
287 static_cast<net::SSLClientSocket*>(socket_.get()); | |
288 net::SSLInfo ssl_info; | |
289 ssl_socket->GetSSLInfo(&ssl_info); | |
290 if (ssl_info.cert.get()) | |
291 GetCertificateFields(*ssl_info.cert, &certificate_fields); | |
292 } | |
293 manager_->Send(new PpapiMsg_PPBTCPSocket_SSLHandshakeACK( | |
294 routing_id_, | |
295 plugin_dispatcher_id_, | |
296 socket_id_, | |
297 succeeded, | |
298 certificate_fields)); | |
299 } | |
300 | |
301 void PepperTCPSocket::OnResolveCompleted(int result) { | |
302 DCHECK(connection_state_ == CONNECT_IN_PROGRESS); | |
303 | |
304 if (result != net::OK) { | |
305 SendConnectACKError(); | |
306 connection_state_ = BEFORE_CONNECT; | |
307 return; | |
308 } | |
309 | |
310 StartConnect(address_list_); | |
311 } | |
312 | |
313 void PepperTCPSocket::OnConnectCompleted(int result) { | |
314 DCHECK(connection_state_ == CONNECT_IN_PROGRESS && socket_.get()); | |
315 | |
316 if (result != net::OK) { | |
317 SendConnectACKError(); | |
318 connection_state_ = BEFORE_CONNECT; | |
319 } else { | |
320 net::IPEndPoint ip_end_point_local; | |
321 net::IPEndPoint ip_end_point_remote; | |
322 PP_NetAddress_Private local_addr = | |
323 NetAddressPrivateImpl::kInvalidNetAddress; | |
324 PP_NetAddress_Private remote_addr = | |
325 NetAddressPrivateImpl::kInvalidNetAddress; | |
326 | |
327 if (socket_->GetLocalAddress(&ip_end_point_local) != net::OK || | |
328 !NetAddressPrivateImpl::IPEndPointToNetAddress(ip_end_point_local, | |
329 &local_addr) || | |
330 socket_->GetPeerAddress(&ip_end_point_remote) != net::OK || | |
331 !NetAddressPrivateImpl::IPEndPointToNetAddress(ip_end_point_remote, | |
332 &remote_addr)) { | |
333 SendConnectACKError(); | |
334 connection_state_ = BEFORE_CONNECT; | |
335 } else { | |
336 manager_->Send(new PpapiMsg_PPBTCPSocket_ConnectACK( | |
337 routing_id_, plugin_dispatcher_id_, socket_id_, true, | |
338 local_addr, remote_addr)); | |
339 connection_state_ = CONNECTED; | |
340 } | |
341 } | |
342 } | |
343 | |
344 void PepperTCPSocket::OnSSLHandshakeCompleted(int result) { | |
345 DCHECK(connection_state_ == SSL_HANDSHAKE_IN_PROGRESS); | |
346 | |
347 bool succeeded = result == net::OK; | |
348 SendSSLHandshakeACK(succeeded); | |
349 connection_state_ = succeeded ? SSL_CONNECTED : SSL_HANDSHAKE_FAILED; | |
350 } | |
351 | |
352 void PepperTCPSocket::OnReadCompleted(int result) { | |
353 DCHECK(read_buffer_.get()); | |
354 | |
355 if (result > 0) { | |
356 manager_->Send(new PpapiMsg_PPBTCPSocket_ReadACK( | |
357 routing_id_, plugin_dispatcher_id_, socket_id_, true, | |
358 std::string(read_buffer_->data(), result))); | |
359 } else if (result == 0) { | |
360 end_of_file_reached_ = true; | |
361 manager_->Send(new PpapiMsg_PPBTCPSocket_ReadACK( | |
362 routing_id_, plugin_dispatcher_id_, socket_id_, true, std::string())); | |
363 } else { | |
364 SendReadACKError(); | |
365 } | |
366 read_buffer_ = NULL; | |
367 } | |
368 | |
369 void PepperTCPSocket::OnWriteCompleted(int result) { | |
370 DCHECK(write_buffer_.get()); | |
371 | |
372 if (result >= 0) { | |
373 manager_->Send(new PpapiMsg_PPBTCPSocket_WriteACK( | |
374 routing_id_, plugin_dispatcher_id_, socket_id_, true, result)); | |
375 } else { | |
376 SendWriteACKError(); | |
377 } | |
378 write_buffer_ = NULL; | |
379 } | |
380 | |
381 bool PepperTCPSocket::IsConnected() const { | |
382 return connection_state_ == CONNECTED || connection_state_ == SSL_CONNECTED; | |
383 } | |
OLD | NEW |