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/shared_impl/tcp_socket_shared.h"
11 #include "base/basictypes.h"
12 #include "base/bind.h"
13 #include "base/logging.h"
14 #include "ppapi/c/pp_completion_callback.h"
15 #include "ppapi/c/pp_errors.h"
16 #include "ppapi/shared_impl/ppapi_globals.h"
17 #include "ppapi/shared_impl/private/ppb_x509_certificate_private_shared.h"
18 #include "ppapi/shared_impl/var_tracker.h"
19 #include "ppapi/shared_impl/var.h"
20 #include "ppapi/thunk/enter.h"
21 #include "ppapi/thunk/ppb_x509_certificate_private_api.h"
25 const int32_t TCPSocketShared::kMaxReadSize
= 1024 * 1024;
26 const int32_t TCPSocketShared::kMaxWriteSize
= 1024 * 1024;
28 TCPSocketShared::TCPSocketShared(ResourceObjectType resource_type
,
30 : resource_type_(resource_type
) {
34 TCPSocketShared::~TCPSocketShared() {
37 void TCPSocketShared::OnConnectCompleted(
39 const PP_NetAddress_Private
& local_addr
,
40 const PP_NetAddress_Private
& remote_addr
) {
41 if (connection_state_
!= BEFORE_CONNECT
||
42 !TrackedCallback::IsPending(connect_callback_
)) {
48 local_addr_
= local_addr
;
49 remote_addr_
= remote_addr
;
50 connection_state_
= CONNECTED
;
52 connect_callback_
->Run(succeeded
? PP_OK
: PP_ERROR_FAILED
);
55 void TCPSocketShared::OnSSLHandshakeCompleted(
57 const PPB_X509Certificate_Fields
& certificate_fields
) {
58 if (connection_state_
!= CONNECTED
||
59 !TrackedCallback::IsPending(ssl_handshake_callback_
)) {
65 connection_state_
= SSL_CONNECTED
;
66 server_certificate_
= new PPB_X509Certificate_Private_Shared(
68 GetOwnerResource()->pp_instance(),
70 ssl_handshake_callback_
->Run(PP_OK
);
72 // The resource might be released in the callback so we need to hold
73 // a reference so we can Disconnect() first.
74 GetOwnerResource()->AddRef();
75 ssl_handshake_callback_
->Run(PP_ERROR_FAILED
);
77 GetOwnerResource()->Release();
81 void TCPSocketShared::OnReadCompleted(bool succeeded
,
82 const std::string
& data
) {
83 if (!TrackedCallback::IsPending(read_callback_
) || !read_buffer_
) {
89 CHECK_LE(static_cast<int32_t>(data
.size()), bytes_to_read_
);
91 memcpy(read_buffer_
, data
.c_str(), data
.size());
97 succeeded
? static_cast<int32_t>(data
.size()) :
98 static_cast<int32_t>(PP_ERROR_FAILED
));
101 void TCPSocketShared::OnWriteCompleted(bool succeeded
,
102 int32_t bytes_written
) {
103 if (!TrackedCallback::IsPending(write_callback_
) ||
104 (succeeded
&& bytes_written
< 0)) {
109 write_callback_
->Run(
110 succeeded
? bytes_written
: static_cast<int32_t>(PP_ERROR_FAILED
));
113 void TCPSocketShared::OnSetOptionCompleted(bool succeeded
) {
114 if (!TrackedCallback::IsPending(set_option_callback_
)) {
119 set_option_callback_
->Run(succeeded
? PP_OK
: PP_ERROR_FAILED
);
122 int32_t TCPSocketShared::ConnectImpl(const char* host
,
124 scoped_refptr
<TrackedCallback
> callback
) {
126 return PP_ERROR_BADARGUMENT
;
127 if (connection_state_
!= BEFORE_CONNECT
)
128 return PP_ERROR_FAILED
;
129 if (TrackedCallback::IsPending(connect_callback_
))
130 return PP_ERROR_INPROGRESS
; // Can only have one pending request.
132 connect_callback_
= callback
;
133 // Send the request, the browser will call us back via ConnectACK.
134 SendConnect(host
, port
);
135 return PP_OK_COMPLETIONPENDING
;
138 int32_t TCPSocketShared::ConnectWithNetAddressImpl(
139 const PP_NetAddress_Private
* addr
,
140 scoped_refptr
<TrackedCallback
> callback
) {
142 return PP_ERROR_BADARGUMENT
;
143 if (connection_state_
!= BEFORE_CONNECT
)
144 return PP_ERROR_FAILED
;
145 if (TrackedCallback::IsPending(connect_callback_
))
146 return PP_ERROR_INPROGRESS
; // Can only have one pending request.
148 connect_callback_
= callback
;
149 // Send the request, the browser will call us back via ConnectACK.
150 SendConnectWithNetAddress(*addr
);
151 return PP_OK_COMPLETIONPENDING
;
154 PP_Bool
TCPSocketShared::GetLocalAddressImpl(
155 PP_NetAddress_Private
* local_addr
) {
156 if (!IsConnected() || !local_addr
)
159 *local_addr
= local_addr_
;
163 PP_Bool
TCPSocketShared::GetRemoteAddressImpl(
164 PP_NetAddress_Private
* remote_addr
) {
165 if (!IsConnected() || !remote_addr
)
168 *remote_addr
= remote_addr_
;
172 int32_t TCPSocketShared::SSLHandshakeImpl(
173 const char* server_name
,
174 uint16_t server_port
,
175 scoped_refptr
<TrackedCallback
> callback
) {
177 return PP_ERROR_BADARGUMENT
;
179 if (connection_state_
!= CONNECTED
)
180 return PP_ERROR_FAILED
;
181 if (TrackedCallback::IsPending(ssl_handshake_callback_
) ||
182 TrackedCallback::IsPending(read_callback_
) ||
183 TrackedCallback::IsPending(write_callback_
))
184 return PP_ERROR_INPROGRESS
;
186 ssl_handshake_callback_
= callback
;
188 // Send the request, the browser will call us back via SSLHandshakeACK.
189 SendSSLHandshake(server_name
, server_port
, trusted_certificates_
,
190 untrusted_certificates_
);
191 return PP_OK_COMPLETIONPENDING
;
194 PP_Resource
TCPSocketShared::GetServerCertificateImpl() {
195 if (!server_certificate_
.get())
197 return server_certificate_
->GetReference();
200 PP_Bool
TCPSocketShared::AddChainBuildingCertificateImpl(
201 PP_Resource certificate
,
203 // TODO(raymes): The plumbing for this functionality is implemented but the
204 // certificates aren't yet used for the connection, so just return false for
208 thunk::EnterResourceNoLock
<thunk::PPB_X509Certificate_Private_API
>
209 enter_cert(certificate
, true);
210 if (enter_cert
.failed())
213 PP_Var der_var
= enter_cert
.object()->GetField(
214 PP_X509CERTIFICATE_PRIVATE_RAW
);
215 ArrayBufferVar
* der_array_buffer
= ArrayBufferVar::FromPPVar(der_var
);
216 PP_Bool success
= PP_FALSE
;
217 if (der_array_buffer
) {
218 const char* der_bytes
= static_cast<const char*>(der_array_buffer
->Map());
219 uint32_t der_length
= der_array_buffer
->ByteLength();
220 std::vector
<char> der(der_bytes
, der_bytes
+ der_length
);
221 if (PP_ToBool(trusted
))
222 trusted_certificates_
.push_back(der
);
224 untrusted_certificates_
.push_back(der
);
227 PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(der_var
);
231 int32_t TCPSocketShared::ReadImpl(char* buffer
,
232 int32_t bytes_to_read
,
233 scoped_refptr
<TrackedCallback
> callback
) {
234 if (!buffer
|| bytes_to_read
<= 0)
235 return PP_ERROR_BADARGUMENT
;
238 return PP_ERROR_FAILED
;
239 if (TrackedCallback::IsPending(read_callback_
) ||
240 TrackedCallback::IsPending(ssl_handshake_callback_
))
241 return PP_ERROR_INPROGRESS
;
242 read_buffer_
= buffer
;
243 bytes_to_read_
= std::min(bytes_to_read
, kMaxReadSize
);
244 read_callback_
= callback
;
246 // Send the request, the browser will call us back via ReadACK.
247 SendRead(bytes_to_read_
);
248 return PP_OK_COMPLETIONPENDING
;
251 int32_t TCPSocketShared::WriteImpl(const char* buffer
,
252 int32_t bytes_to_write
,
253 scoped_refptr
<TrackedCallback
> callback
) {
254 if (!buffer
|| bytes_to_write
<= 0)
255 return PP_ERROR_BADARGUMENT
;
258 return PP_ERROR_FAILED
;
259 if (TrackedCallback::IsPending(write_callback_
) ||
260 TrackedCallback::IsPending(ssl_handshake_callback_
))
261 return PP_ERROR_INPROGRESS
;
263 if (bytes_to_write
> kMaxWriteSize
)
264 bytes_to_write
= kMaxWriteSize
;
266 write_callback_
= callback
;
268 // Send the request, the browser will call us back via WriteACK.
269 SendWrite(std::string(buffer
, bytes_to_write
));
270 return PP_OK_COMPLETIONPENDING
;
273 void TCPSocketShared::DisconnectImpl() {
274 if (connection_state_
== DISCONNECTED
)
277 connection_state_
= DISCONNECTED
;
282 PostAbortIfNecessary(&connect_callback_
);
283 PostAbortIfNecessary(&ssl_handshake_callback_
);
284 PostAbortIfNecessary(&read_callback_
);
285 PostAbortIfNecessary(&write_callback_
);
286 PostAbortIfNecessary(&set_option_callback_
);
289 server_certificate_
= NULL
;
292 int32_t TCPSocketShared::SetOptionImpl(
293 PP_TCPSocketOption_Private name
,
295 scoped_refptr
<TrackedCallback
> callback
) {
297 return PP_ERROR_FAILED
;
298 if (TrackedCallback::IsPending(set_option_callback_
))
299 return PP_ERROR_INPROGRESS
;
301 set_option_callback_
= callback
;
304 case PP_TCPSOCKETOPTION_NO_DELAY
:
305 if (value
.type
!= PP_VARTYPE_BOOL
)
306 return PP_ERROR_BADARGUMENT
;
307 SendSetBoolOption(name
, PP_ToBool(value
.value
.as_bool
));
308 return PP_OK_COMPLETIONPENDING
;
310 return PP_ERROR_BADARGUMENT
;
314 void TCPSocketShared::Init(uint32 socket_id
) {
315 DCHECK(socket_id
!= 0);
316 socket_id_
= socket_id
;
317 connection_state_
= BEFORE_CONNECT
;
321 local_addr_
.size
= 0;
322 memset(local_addr_
.data
, 0,
323 arraysize(local_addr_
.data
) * sizeof(*local_addr_
.data
));
324 remote_addr_
.size
= 0;
325 memset(remote_addr_
.data
, 0,
326 arraysize(remote_addr_
.data
) * sizeof(*remote_addr_
.data
));
329 bool TCPSocketShared::IsConnected() const {
330 return connection_state_
== CONNECTED
|| connection_state_
== SSL_CONNECTED
;
333 void TCPSocketShared::PostAbortIfNecessary(
334 scoped_refptr
<TrackedCallback
>* callback
) {
335 if (TrackedCallback::IsPending(*callback
))
336 (*callback
)->PostAbort();