Add ability to change display settings to chrome.systemInfo.display
[chromium-blink-merge.git] / ppapi / shared_impl / tcp_socket_shared.cc
blob8799c49f0dda6ee66fa08c9a186a2e38ac7e6f73
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"
7 #include <string.h>
9 #include <algorithm>
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"
23 namespace ppapi {
25 const int32_t TCPSocketShared::kMaxReadSize = 1024 * 1024;
26 const int32_t TCPSocketShared::kMaxWriteSize = 1024 * 1024;
28 TCPSocketShared::TCPSocketShared(ResourceObjectType resource_type,
29 uint32 socket_id)
30 : resource_type_(resource_type) {
31 Init(socket_id);
34 TCPSocketShared::~TCPSocketShared() {
37 void TCPSocketShared::OnConnectCompleted(
38 bool succeeded,
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_)) {
43 NOTREACHED();
44 return;
47 if (succeeded) {
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(
56 bool succeeded,
57 const PPB_X509Certificate_Fields& certificate_fields) {
58 if (connection_state_ != CONNECTED ||
59 !TrackedCallback::IsPending(ssl_handshake_callback_)) {
60 NOTREACHED();
61 return;
64 if (succeeded) {
65 connection_state_ = SSL_CONNECTED;
66 server_certificate_ = new PPB_X509Certificate_Private_Shared(
67 resource_type_,
68 GetOwnerResource()->pp_instance(),
69 certificate_fields);
70 ssl_handshake_callback_->Run(PP_OK);
71 } else {
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);
76 DisconnectImpl();
77 GetOwnerResource()->Release();
81 void TCPSocketShared::OnReadCompleted(bool succeeded,
82 const std::string& data) {
83 if (!TrackedCallback::IsPending(read_callback_) || !read_buffer_) {
84 NOTREACHED();
85 return;
88 if (succeeded) {
89 CHECK_LE(static_cast<int32_t>(data.size()), bytes_to_read_);
90 if (!data.empty())
91 memcpy(read_buffer_, data.c_str(), data.size());
93 read_buffer_ = NULL;
94 bytes_to_read_ = -1;
96 read_callback_->Run(
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)) {
105 NOTREACHED();
106 return;
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_)) {
115 NOTREACHED();
116 return;
119 set_option_callback_->Run(succeeded ? PP_OK : PP_ERROR_FAILED);
122 int32_t TCPSocketShared::ConnectImpl(const char* host,
123 uint16_t port,
124 scoped_refptr<TrackedCallback> callback) {
125 if (!host)
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) {
141 if (!addr)
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)
157 return PP_FALSE;
159 *local_addr = local_addr_;
160 return PP_TRUE;
163 PP_Bool TCPSocketShared::GetRemoteAddressImpl(
164 PP_NetAddress_Private* remote_addr) {
165 if (!IsConnected() || !remote_addr)
166 return PP_FALSE;
168 *remote_addr = remote_addr_;
169 return PP_TRUE;
172 int32_t TCPSocketShared::SSLHandshakeImpl(
173 const char* server_name,
174 uint16_t server_port,
175 scoped_refptr<TrackedCallback> callback) {
176 if (!server_name)
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())
196 return 0;
197 return server_certificate_->GetReference();
200 PP_Bool TCPSocketShared::AddChainBuildingCertificateImpl(
201 PP_Resource certificate,
202 PP_Bool trusted) {
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
205 // now.
206 return PP_FALSE;
208 thunk::EnterResourceNoLock<thunk::PPB_X509Certificate_Private_API>
209 enter_cert(certificate, true);
210 if (enter_cert.failed())
211 return PP_FALSE;
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);
223 else
224 untrusted_certificates_.push_back(der);
225 success = PP_TRUE;
227 PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(der_var);
228 return success;
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;
237 if (!IsConnected())
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;
257 if (!IsConnected())
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)
275 return;
277 connection_state_ = DISCONNECTED;
279 SendDisconnect();
280 socket_id_ = 0;
282 PostAbortIfNecessary(&connect_callback_);
283 PostAbortIfNecessary(&ssl_handshake_callback_);
284 PostAbortIfNecessary(&read_callback_);
285 PostAbortIfNecessary(&write_callback_);
286 PostAbortIfNecessary(&set_option_callback_);
287 read_buffer_ = NULL;
288 bytes_to_read_ = -1;
289 server_certificate_ = NULL;
292 int32_t TCPSocketShared::SetOptionImpl(
293 PP_TCPSocketOption_Private name,
294 const PP_Var& value,
295 scoped_refptr<TrackedCallback> callback) {
296 if (!IsConnected())
297 return PP_ERROR_FAILED;
298 if (TrackedCallback::IsPending(set_option_callback_))
299 return PP_ERROR_INPROGRESS;
301 set_option_callback_ = callback;
303 switch (name) {
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;
309 default:
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;
318 read_buffer_ = NULL;
319 bytes_to_read_ = -1;
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();
339 } // namespace ppapi