Disable TabDragController tests that fail with a real compositor.
[chromium-blink-merge.git] / ppapi / proxy / tcp_socket_resource_base.cc
blobfff2da3cf8ae69e990b334bc9444a481b8673cc5
1 // Copyright 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 "ppapi/proxy/tcp_socket_resource_base.h"
7 #include <cstring>
9 #include "base/bind.h"
10 #include "base/logging.h"
11 #include "ppapi/c/pp_bool.h"
12 #include "ppapi/c/pp_errors.h"
13 #include "ppapi/proxy/error_conversion.h"
14 #include "ppapi/proxy/ppapi_messages.h"
15 #include "ppapi/shared_impl/ppapi_globals.h"
16 #include "ppapi/shared_impl/private/ppb_x509_certificate_private_shared.h"
17 #include "ppapi/shared_impl/socket_option_data.h"
18 #include "ppapi/shared_impl/var.h"
19 #include "ppapi/shared_impl/var_tracker.h"
20 #include "ppapi/thunk/enter.h"
21 #include "ppapi/thunk/ppb_x509_certificate_private_api.h"
23 namespace ppapi {
24 namespace proxy {
26 const int32_t TCPSocketResourceBase::kMaxReadSize = 1024 * 1024;
27 const int32_t TCPSocketResourceBase::kMaxWriteSize = 1024 * 1024;
28 const int32_t TCPSocketResourceBase::kMaxSendBufferSize =
29 1024 * TCPSocketResourceBase::kMaxWriteSize;
30 const int32_t TCPSocketResourceBase::kMaxReceiveBufferSize =
31 1024 * TCPSocketResourceBase::kMaxReadSize;
33 TCPSocketResourceBase::TCPSocketResourceBase(Connection connection,
34 PP_Instance instance,
35 TCPSocketVersion version)
36 : PluginResource(connection, instance),
37 state_(TCPSocketState::INITIAL),
38 read_buffer_(NULL),
39 bytes_to_read_(-1),
40 accepted_tcp_socket_(NULL),
41 version_(version) {
42 local_addr_.size = 0;
43 memset(local_addr_.data, 0,
44 arraysize(local_addr_.data) * sizeof(*local_addr_.data));
45 remote_addr_.size = 0;
46 memset(remote_addr_.data, 0,
47 arraysize(remote_addr_.data) * sizeof(*remote_addr_.data));
50 TCPSocketResourceBase::TCPSocketResourceBase(
51 Connection connection,
52 PP_Instance instance,
53 TCPSocketVersion version,
54 const PP_NetAddress_Private& local_addr,
55 const PP_NetAddress_Private& remote_addr)
56 : PluginResource(connection, instance),
57 state_(TCPSocketState::CONNECTED),
58 read_buffer_(NULL),
59 bytes_to_read_(-1),
60 local_addr_(local_addr),
61 remote_addr_(remote_addr),
62 accepted_tcp_socket_(NULL),
63 version_(version) {
66 TCPSocketResourceBase::~TCPSocketResourceBase() {
67 CloseImpl();
70 int32_t TCPSocketResourceBase::BindImpl(
71 const PP_NetAddress_Private* addr,
72 scoped_refptr<TrackedCallback> callback) {
73 if (!addr)
74 return PP_ERROR_BADARGUMENT;
75 if (state_.IsPending(TCPSocketState::BIND))
76 return PP_ERROR_INPROGRESS;
77 if (!state_.IsValidTransition(TCPSocketState::BIND))
78 return PP_ERROR_FAILED;
80 bind_callback_ = callback;
81 state_.SetPendingTransition(TCPSocketState::BIND);
83 Call<PpapiPluginMsg_TCPSocket_BindReply>(
84 BROWSER,
85 PpapiHostMsg_TCPSocket_Bind(*addr),
86 base::Bind(&TCPSocketResourceBase::OnPluginMsgBindReply,
87 base::Unretained(this)),
88 callback);
89 return PP_OK_COMPLETIONPENDING;
92 int32_t TCPSocketResourceBase::ConnectImpl(
93 const char* host,
94 uint16_t port,
95 scoped_refptr<TrackedCallback> callback) {
96 if (!host)
97 return PP_ERROR_BADARGUMENT;
98 if (state_.IsPending(TCPSocketState::CONNECT))
99 return PP_ERROR_INPROGRESS;
100 if (!state_.IsValidTransition(TCPSocketState::CONNECT))
101 return PP_ERROR_FAILED;
103 connect_callback_ = callback;
104 state_.SetPendingTransition(TCPSocketState::CONNECT);
106 Call<PpapiPluginMsg_TCPSocket_ConnectReply>(
107 BROWSER,
108 PpapiHostMsg_TCPSocket_Connect(host, port),
109 base::Bind(&TCPSocketResourceBase::OnPluginMsgConnectReply,
110 base::Unretained(this)),
111 callback);
112 return PP_OK_COMPLETIONPENDING;
115 int32_t TCPSocketResourceBase::ConnectWithNetAddressImpl(
116 const PP_NetAddress_Private* addr,
117 scoped_refptr<TrackedCallback> callback) {
118 if (!addr)
119 return PP_ERROR_BADARGUMENT;
120 if (state_.IsPending(TCPSocketState::CONNECT))
121 return PP_ERROR_INPROGRESS;
122 if (!state_.IsValidTransition(TCPSocketState::CONNECT))
123 return PP_ERROR_FAILED;
125 connect_callback_ = callback;
126 state_.SetPendingTransition(TCPSocketState::CONNECT);
128 Call<PpapiPluginMsg_TCPSocket_ConnectReply>(
129 BROWSER,
130 PpapiHostMsg_TCPSocket_ConnectWithNetAddress(*addr),
131 base::Bind(&TCPSocketResourceBase::OnPluginMsgConnectReply,
132 base::Unretained(this)),
133 callback);
134 return PP_OK_COMPLETIONPENDING;
137 PP_Bool TCPSocketResourceBase::GetLocalAddressImpl(
138 PP_NetAddress_Private* local_addr) {
139 if (!state_.IsBound() || !local_addr)
140 return PP_FALSE;
141 *local_addr = local_addr_;
142 return PP_TRUE;
145 PP_Bool TCPSocketResourceBase::GetRemoteAddressImpl(
146 PP_NetAddress_Private* remote_addr) {
147 if (!state_.IsConnected() || !remote_addr)
148 return PP_FALSE;
149 *remote_addr = remote_addr_;
150 return PP_TRUE;
153 int32_t TCPSocketResourceBase::SSLHandshakeImpl(
154 const char* server_name,
155 uint16_t server_port,
156 scoped_refptr<TrackedCallback> callback) {
157 if (!server_name)
158 return PP_ERROR_BADARGUMENT;
160 if (state_.IsPending(TCPSocketState::SSL_CONNECT) ||
161 TrackedCallback::IsPending(read_callback_) ||
162 TrackedCallback::IsPending(write_callback_)) {
163 return PP_ERROR_INPROGRESS;
165 if (!state_.IsValidTransition(TCPSocketState::SSL_CONNECT))
166 return PP_ERROR_FAILED;
168 ssl_handshake_callback_ = callback;
169 state_.SetPendingTransition(TCPSocketState::SSL_CONNECT);
171 Call<PpapiPluginMsg_TCPSocket_SSLHandshakeReply>(
172 BROWSER,
173 PpapiHostMsg_TCPSocket_SSLHandshake(server_name,
174 server_port,
175 trusted_certificates_,
176 untrusted_certificates_),
177 base::Bind(&TCPSocketResourceBase::OnPluginMsgSSLHandshakeReply,
178 base::Unretained(this)),
179 callback);
180 return PP_OK_COMPLETIONPENDING;
183 PP_Resource TCPSocketResourceBase::GetServerCertificateImpl() {
184 if (!server_certificate_.get())
185 return 0;
186 return server_certificate_->GetReference();
189 PP_Bool TCPSocketResourceBase::AddChainBuildingCertificateImpl(
190 PP_Resource certificate,
191 PP_Bool trusted) {
192 // TODO(raymes): The plumbing for this functionality is implemented but the
193 // certificates aren't yet used for the connection, so just return false for
194 // now.
195 return PP_FALSE;
197 thunk::EnterResourceNoLock<thunk::PPB_X509Certificate_Private_API>
198 enter_cert(certificate, true);
199 if (enter_cert.failed())
200 return PP_FALSE;
202 PP_Var der_var = enter_cert.object()->GetField(
203 PP_X509CERTIFICATE_PRIVATE_RAW);
204 ArrayBufferVar* der_array_buffer = ArrayBufferVar::FromPPVar(der_var);
205 PP_Bool success = PP_FALSE;
206 if (der_array_buffer) {
207 const char* der_bytes = static_cast<const char*>(der_array_buffer->Map());
208 uint32_t der_length = der_array_buffer->ByteLength();
209 std::vector<char> der(der_bytes, der_bytes + der_length);
210 if (PP_ToBool(trusted))
211 trusted_certificates_.push_back(der);
212 else
213 untrusted_certificates_.push_back(der);
214 success = PP_TRUE;
216 PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(der_var);
217 return success;
220 int32_t TCPSocketResourceBase::ReadImpl(
221 char* buffer,
222 int32_t bytes_to_read,
223 scoped_refptr<TrackedCallback> callback) {
224 if (!buffer || bytes_to_read <= 0)
225 return PP_ERROR_BADARGUMENT;
227 if (!state_.IsConnected())
228 return PP_ERROR_FAILED;
229 if (TrackedCallback::IsPending(read_callback_) ||
230 state_.IsPending(TCPSocketState::SSL_CONNECT))
231 return PP_ERROR_INPROGRESS;
232 read_buffer_ = buffer;
233 bytes_to_read_ = std::min(bytes_to_read, kMaxReadSize);
234 read_callback_ = callback;
236 Call<PpapiPluginMsg_TCPSocket_ReadReply>(
237 BROWSER,
238 PpapiHostMsg_TCPSocket_Read(bytes_to_read_),
239 base::Bind(&TCPSocketResourceBase::OnPluginMsgReadReply,
240 base::Unretained(this)),
241 callback);
242 return PP_OK_COMPLETIONPENDING;
245 int32_t TCPSocketResourceBase::WriteImpl(
246 const char* buffer,
247 int32_t bytes_to_write,
248 scoped_refptr<TrackedCallback> callback) {
249 if (!buffer || bytes_to_write <= 0)
250 return PP_ERROR_BADARGUMENT;
252 if (!state_.IsConnected())
253 return PP_ERROR_FAILED;
254 if (TrackedCallback::IsPending(write_callback_) ||
255 state_.IsPending(TCPSocketState::SSL_CONNECT))
256 return PP_ERROR_INPROGRESS;
258 if (bytes_to_write > kMaxWriteSize)
259 bytes_to_write = kMaxWriteSize;
261 write_callback_ = callback;
263 Call<PpapiPluginMsg_TCPSocket_WriteReply>(
264 BROWSER,
265 PpapiHostMsg_TCPSocket_Write(std::string(buffer, bytes_to_write)),
266 base::Bind(&TCPSocketResourceBase::OnPluginMsgWriteReply,
267 base::Unretained(this)),
268 callback);
269 return PP_OK_COMPLETIONPENDING;
272 int32_t TCPSocketResourceBase::ListenImpl(
273 int32_t backlog,
274 scoped_refptr<TrackedCallback> callback) {
275 if (backlog <= 0)
276 return PP_ERROR_BADARGUMENT;
277 if (state_.IsPending(TCPSocketState::LISTEN))
278 return PP_ERROR_INPROGRESS;
279 if (!state_.IsValidTransition(TCPSocketState::LISTEN))
280 return PP_ERROR_FAILED;
282 listen_callback_ = callback;
283 state_.SetPendingTransition(TCPSocketState::LISTEN);
285 Call<PpapiPluginMsg_TCPSocket_ListenReply>(
286 BROWSER,
287 PpapiHostMsg_TCPSocket_Listen(backlog),
288 base::Bind(&TCPSocketResourceBase::OnPluginMsgListenReply,
289 base::Unretained(this)),
290 callback);
291 return PP_OK_COMPLETIONPENDING;
294 int32_t TCPSocketResourceBase::AcceptImpl(
295 PP_Resource* accepted_tcp_socket,
296 scoped_refptr<TrackedCallback> callback) {
297 if (!accepted_tcp_socket)
298 return PP_ERROR_BADARGUMENT;
299 if (TrackedCallback::IsPending(accept_callback_))
300 return PP_ERROR_INPROGRESS;
301 if (state_.state() != TCPSocketState::LISTENING)
302 return PP_ERROR_FAILED;
304 accept_callback_ = callback;
305 accepted_tcp_socket_ = accepted_tcp_socket;
307 Call<PpapiPluginMsg_TCPSocket_AcceptReply>(
308 BROWSER,
309 PpapiHostMsg_TCPSocket_Accept(),
310 base::Bind(&TCPSocketResourceBase::OnPluginMsgAcceptReply,
311 base::Unretained(this)),
312 callback);
313 return PP_OK_COMPLETIONPENDING;
316 void TCPSocketResourceBase::CloseImpl() {
317 if (state_.state() == TCPSocketState::CLOSED)
318 return;
320 state_.DoTransition(TCPSocketState::CLOSE, true);
322 Post(BROWSER, PpapiHostMsg_TCPSocket_Close());
324 PostAbortIfNecessary(&bind_callback_);
325 PostAbortIfNecessary(&connect_callback_);
326 PostAbortIfNecessary(&ssl_handshake_callback_);
327 PostAbortIfNecessary(&read_callback_);
328 PostAbortIfNecessary(&write_callback_);
329 PostAbortIfNecessary(&listen_callback_);
330 PostAbortIfNecessary(&accept_callback_);
331 read_buffer_ = NULL;
332 bytes_to_read_ = -1;
333 server_certificate_ = NULL;
334 accepted_tcp_socket_ = NULL;
337 int32_t TCPSocketResourceBase::SetOptionImpl(
338 PP_TCPSocket_Option name,
339 const PP_Var& value,
340 scoped_refptr<TrackedCallback> callback) {
341 SocketOptionData option_data;
342 switch (name) {
343 case PP_TCPSOCKET_OPTION_NO_DELAY: {
344 if (!state_.IsConnected())
345 return PP_ERROR_FAILED;
347 if (value.type != PP_VARTYPE_BOOL)
348 return PP_ERROR_BADARGUMENT;
349 option_data.SetBool(PP_ToBool(value.value.as_bool));
350 break;
352 case PP_TCPSOCKET_OPTION_SEND_BUFFER_SIZE:
353 case PP_TCPSOCKET_OPTION_RECV_BUFFER_SIZE: {
354 if (!state_.IsConnected())
355 return PP_ERROR_FAILED;
357 if (value.type != PP_VARTYPE_INT32)
358 return PP_ERROR_BADARGUMENT;
359 option_data.SetInt32(value.value.as_int);
360 break;
362 default: {
363 NOTREACHED();
364 return PP_ERROR_BADARGUMENT;
368 set_option_callbacks_.push(callback);
370 Call<PpapiPluginMsg_TCPSocket_SetOptionReply>(
371 BROWSER,
372 PpapiHostMsg_TCPSocket_SetOption(name, option_data),
373 base::Bind(&TCPSocketResourceBase::OnPluginMsgSetOptionReply,
374 base::Unretained(this)),
375 callback);
376 return PP_OK_COMPLETIONPENDING;
379 void TCPSocketResourceBase::PostAbortIfNecessary(
380 scoped_refptr<TrackedCallback>* callback) {
381 if (TrackedCallback::IsPending(*callback))
382 (*callback)->PostAbort();
385 void TCPSocketResourceBase::OnPluginMsgBindReply(
386 const ResourceMessageReplyParams& params,
387 const PP_NetAddress_Private& local_addr) {
388 // It is possible that CloseImpl() has been called. We don't want to update
389 // class members in this case.
390 if (!state_.IsPending(TCPSocketState::BIND))
391 return;
393 DCHECK(TrackedCallback::IsPending(bind_callback_));
394 if (params.result() == PP_OK) {
395 local_addr_ = local_addr;
396 state_.CompletePendingTransition(true);
397 } else {
398 state_.CompletePendingTransition(false);
400 RunCallback(bind_callback_, params.result());
403 void TCPSocketResourceBase::OnPluginMsgConnectReply(
404 const ResourceMessageReplyParams& params,
405 const PP_NetAddress_Private& local_addr,
406 const PP_NetAddress_Private& remote_addr) {
407 // It is possible that CloseImpl() has been called. We don't want to update
408 // class members in this case.
409 if (!state_.IsPending(TCPSocketState::CONNECT))
410 return;
412 DCHECK(TrackedCallback::IsPending(connect_callback_));
413 if (params.result() == PP_OK) {
414 local_addr_ = local_addr;
415 remote_addr_ = remote_addr;
416 state_.CompletePendingTransition(true);
417 } else {
418 if (version_ == TCP_SOCKET_VERSION_1_1_OR_ABOVE) {
419 state_.CompletePendingTransition(false);
420 } else {
421 // In order to maintain backward compatibility, allow to connect the
422 // socket again.
423 state_ = TCPSocketState(TCPSocketState::INITIAL);
426 RunCallback(connect_callback_, params.result());
429 void TCPSocketResourceBase::OnPluginMsgSSLHandshakeReply(
430 const ResourceMessageReplyParams& params,
431 const PPB_X509Certificate_Fields& certificate_fields) {
432 // It is possible that CloseImpl() has been called. We don't want to
433 // update class members in this case.
434 if (!state_.IsPending(TCPSocketState::SSL_CONNECT))
435 return;
437 DCHECK(TrackedCallback::IsPending(ssl_handshake_callback_));
438 if (params.result() == PP_OK) {
439 state_.CompletePendingTransition(true);
440 server_certificate_ = new PPB_X509Certificate_Private_Shared(
441 OBJECT_IS_PROXY,
442 pp_instance(),
443 certificate_fields);
444 } else {
445 state_.CompletePendingTransition(false);
447 RunCallback(ssl_handshake_callback_, params.result());
450 void TCPSocketResourceBase::OnPluginMsgReadReply(
451 const ResourceMessageReplyParams& params,
452 const std::string& data) {
453 // It is possible that CloseImpl() has been called. We shouldn't access the
454 // buffer in that case. The user may have released it.
455 if (!state_.IsConnected() || !TrackedCallback::IsPending(read_callback_) ||
456 !read_buffer_) {
457 return;
460 const bool succeeded = params.result() == PP_OK;
461 if (succeeded) {
462 CHECK_LE(static_cast<int32_t>(data.size()), bytes_to_read_);
463 if (!data.empty())
464 memmove(read_buffer_, data.c_str(), data.size());
466 read_buffer_ = NULL;
467 bytes_to_read_ = -1;
469 RunCallback(read_callback_,
470 succeeded ? static_cast<int32_t>(data.size()) : params.result());
473 void TCPSocketResourceBase::OnPluginMsgWriteReply(
474 const ResourceMessageReplyParams& params) {
475 if (!state_.IsConnected() || !TrackedCallback::IsPending(write_callback_))
476 return;
477 RunCallback(write_callback_, params.result());
480 void TCPSocketResourceBase::OnPluginMsgListenReply(
481 const ResourceMessageReplyParams& params) {
482 if (!state_.IsPending(TCPSocketState::LISTEN))
483 return;
485 DCHECK(TrackedCallback::IsPending(listen_callback_));
486 state_.CompletePendingTransition(params.result() == PP_OK);
488 RunCallback(listen_callback_, params.result());
491 void TCPSocketResourceBase::OnPluginMsgAcceptReply(
492 const ResourceMessageReplyParams& params,
493 int pending_host_id,
494 const PP_NetAddress_Private& local_addr,
495 const PP_NetAddress_Private& remote_addr) {
496 // It is possible that CloseImpl() has been called. We shouldn't access the
497 // output parameter in that case. The user may have released it.
498 if (state_.state() != TCPSocketState::LISTENING ||
499 !TrackedCallback::IsPending(accept_callback_) || !accepted_tcp_socket_) {
500 return;
503 if (params.result() == PP_OK) {
504 *accepted_tcp_socket_ = CreateAcceptedSocket(pending_host_id, local_addr,
505 remote_addr);
507 accepted_tcp_socket_ = NULL;
508 RunCallback(accept_callback_, params.result());
511 void TCPSocketResourceBase::OnPluginMsgSetOptionReply(
512 const ResourceMessageReplyParams& params) {
513 if (set_option_callbacks_.empty()) {
514 NOTREACHED();
515 return;
517 scoped_refptr<TrackedCallback> callback = set_option_callbacks_.front();
518 set_option_callbacks_.pop();
519 if (TrackedCallback::IsPending(callback))
520 RunCallback(callback, params.result());
523 void TCPSocketResourceBase::RunCallback(scoped_refptr<TrackedCallback> callback,
524 int32_t pp_result) {
525 callback->Run(ConvertNetworkAPIErrorForCompatibility(
526 pp_result, version_ == TCP_SOCKET_VERSION_PRIVATE));
529 } // namespace ppapi
530 } // namespace proxy