| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ppapi/shared_impl/tcp_socket_shared.h" | 5 #include "ppapi/proxy/tcp_socket_base_resource.h" |
| 6 | 6 |
| 7 #include <string.h> | 7 #include <cstring> |
| 8 | 8 |
| 9 #include <algorithm> | |
| 10 | |
| 11 #include "base/basictypes.h" | |
| 12 #include "base/bind.h" | |
| 13 #include "base/logging.h" | |
| 14 #include "ppapi/c/pp_bool.h" | |
| 15 #include "ppapi/c/pp_completion_callback.h" | |
| 16 #include "ppapi/c/pp_errors.h" | 9 #include "ppapi/c/pp_errors.h" |
| 17 #include "ppapi/shared_impl/ppapi_globals.h" | 10 #include "ppapi/proxy/ppapi_messages.h" |
| 18 #include "ppapi/shared_impl/private/ppb_x509_certificate_private_shared.h" | 11 #include "ppapi/shared_impl/private/ppb_x509_certificate_private_shared.h" |
| 19 #include "ppapi/shared_impl/socket_option_data.h" | 12 #include "ppapi/shared_impl/socket_option_data.h" |
| 13 #include "ppapi/shared_impl/var.h" |
| 20 #include "ppapi/shared_impl/var_tracker.h" | 14 #include "ppapi/shared_impl/var_tracker.h" |
| 21 #include "ppapi/shared_impl/var.h" | |
| 22 #include "ppapi/thunk/enter.h" | 15 #include "ppapi/thunk/enter.h" |
| 23 #include "ppapi/thunk/ppb_x509_certificate_private_api.h" | |
| 24 | 16 |
| 25 namespace ppapi { | 17 namespace ppapi { |
| 18 namespace proxy { |
| 26 | 19 |
| 27 const int32_t TCPSocketShared::kMaxReadSize = 1024 * 1024; | 20 namespace { |
| 28 const int32_t TCPSocketShared::kMaxWriteSize = 1024 * 1024; | |
| 29 const int32_t TCPSocketShared::kMaxSendBufferSize = | |
| 30 1024 * TCPSocketShared::kMaxWriteSize; | |
| 31 const int32_t TCPSocketShared::kMaxReceiveBufferSize = | |
| 32 1024 * TCPSocketShared::kMaxReadSize; | |
| 33 | 21 |
| 34 TCPSocketShared::TCPSocketShared(ResourceObjectType resource_type, | 22 int32_t ConvertPPError(int32_t pp_error, bool private_api) { |
| 35 uint32 socket_id) | 23 // The private API doesn't return network-specific error codes or |
| 36 : resource_type_(resource_type) { | 24 // PP_ERROR_NOACCESS. In order to preserve the behavior, we convert those to |
| 37 Init(socket_id); | 25 // PP_ERROR_FAILED. |
| 38 } | 26 if (private_api && |
| 39 | 27 (pp_error <= PP_ERROR_CONNECTION_CLOSED || |
| 40 TCPSocketShared::~TCPSocketShared() { | 28 pp_error == PP_ERROR_NOACCESS)) { |
| 41 } | 29 return PP_ERROR_FAILED; |
| 42 | |
| 43 void TCPSocketShared::OnConnectCompleted( | |
| 44 int32_t result, | |
| 45 const PP_NetAddress_Private& local_addr, | |
| 46 const PP_NetAddress_Private& remote_addr) { | |
| 47 // It is possible that |connect_callback_| is pending while | |
| 48 // |connection_state_| is not BEFORE_CONNECT: DisconnectImpl() has been | |
| 49 // called, but a ConnectCompleted notification came earlier than the task to | |
| 50 // abort |connect_callback_|. We don't want to update |connection_state_| or | |
| 51 // other members in that case. | |
| 52 if (connection_state_ != BEFORE_CONNECT || | |
| 53 !TrackedCallback::IsPending(connect_callback_)) { | |
| 54 return; | |
| 55 } | 30 } |
| 56 | |
| 57 result = OverridePPError(result); | |
| 58 if (result == PP_OK) { | |
| 59 local_addr_ = local_addr; | |
| 60 remote_addr_ = remote_addr; | |
| 61 connection_state_ = CONNECTED; | |
| 62 } | |
| 63 connect_callback_->Run(result); | |
| 64 } | |
| 65 | |
| 66 void TCPSocketShared::OnSSLHandshakeCompleted( | |
| 67 bool succeeded, | |
| 68 const PPB_X509Certificate_Fields& certificate_fields) { | |
| 69 // It is possible that |ssl_handshake_callback_| is pending while | |
| 70 // |connection_state_| is not CONNECT: DisconnectImpl() has been | |
| 71 // called, but a SSLHandshakeCompleted notification came earlier than the task | |
| 72 // to abort |ssl_handshake_callback_|. We don't want to update | |
| 73 // |connection_state_| or other members in that case. | |
| 74 if (connection_state_ != CONNECTED || | |
| 75 !TrackedCallback::IsPending(ssl_handshake_callback_)) { | |
| 76 return; | |
| 77 } | |
| 78 | |
| 79 if (succeeded) { | |
| 80 connection_state_ = SSL_CONNECTED; | |
| 81 server_certificate_ = new PPB_X509Certificate_Private_Shared( | |
| 82 resource_type_, | |
| 83 GetOwnerResource()->pp_instance(), | |
| 84 certificate_fields); | |
| 85 ssl_handshake_callback_->Run(PP_OK); | |
| 86 } else { | |
| 87 // The resource might be released in the callback so we need to hold | |
| 88 // a reference so we can Disconnect() first. | |
| 89 GetOwnerResource()->AddRef(); | |
| 90 ssl_handshake_callback_->Run(PP_ERROR_FAILED); | |
| 91 DisconnectImpl(); | |
| 92 GetOwnerResource()->Release(); | |
| 93 } | |
| 94 } | |
| 95 | |
| 96 void TCPSocketShared::OnReadCompleted(int32_t result, | |
| 97 const std::string& data) { | |
| 98 // It is possible that |read_callback_| is pending while |read_buffer_| is | |
| 99 // NULL: DisconnectImpl() has been called, but a ReadCompleted notification | |
| 100 // came earlier than the task to abort |read_callback_|. We shouldn't access | |
| 101 // the buffer in that case. The user may have released it. | |
| 102 if (!TrackedCallback::IsPending(read_callback_) || !read_buffer_) | |
| 103 return; | |
| 104 | |
| 105 result = OverridePPError(result); | |
| 106 bool succeeded = result == PP_OK; | |
| 107 if (succeeded) { | |
| 108 CHECK_LE(static_cast<int32_t>(data.size()), bytes_to_read_); | |
| 109 if (!data.empty()) | |
| 110 memcpy(read_buffer_, data.c_str(), data.size()); | |
| 111 } | |
| 112 read_buffer_ = NULL; | |
| 113 bytes_to_read_ = -1; | |
| 114 | |
| 115 read_callback_->Run( | |
| 116 succeeded ? static_cast<int32_t>(data.size()) : result); | |
| 117 } | |
| 118 | |
| 119 void TCPSocketShared::OnWriteCompleted(int32_t result) { | |
| 120 if (!TrackedCallback::IsPending(write_callback_)) | |
| 121 return; | |
| 122 | |
| 123 result = OverridePPError(result); | |
| 124 write_callback_->Run(result); | |
| 125 } | |
| 126 | |
| 127 void TCPSocketShared::OnSetOptionCompleted(int32_t result) { | |
| 128 if (set_option_callbacks_.empty()) { | |
| 129 NOTREACHED(); | |
| 130 return; | |
| 131 } | |
| 132 | |
| 133 result = OverridePPError(result); | |
| 134 scoped_refptr<TrackedCallback> callback = set_option_callbacks_.front(); | |
| 135 set_option_callbacks_.pop(); | |
| 136 | |
| 137 if (TrackedCallback::IsPending(callback)) | |
| 138 callback->Run(result); | |
| 139 } | |
| 140 | |
| 141 int32_t TCPSocketShared::OverridePPError(int32_t pp_error) { | |
| 142 return pp_error; | 31 return pp_error; |
| 143 } | 32 } |
| 144 | 33 |
| 145 int32_t TCPSocketShared::ConnectImpl(const char* host, | 34 } // namespace |
| 146 uint16_t port, | 35 |
| 147 scoped_refptr<TrackedCallback> callback) { | 36 const int32_t TCPSocketBaseResource::kMaxReadSize = 1024 * 1024; |
| 37 const int32_t TCPSocketBaseResource::kMaxWriteSize = 1024 * 1024; |
| 38 const int32_t TCPSocketBaseResource::kMaxSendBufferSize = |
| 39 1024 * TCPSocketBaseResource::kMaxWriteSize; |
| 40 const int32_t TCPSocketBaseResource::kMaxReceiveBufferSize = |
| 41 1024 * TCPSocketBaseResource::kMaxReadSize; |
| 42 |
| 43 TCPSocketBaseResource::TCPSocketBaseResource(Connection connection, |
| 44 PP_Instance instance, |
| 45 bool private_api) |
| 46 : PluginResource(connection, instance), |
| 47 connection_state_(BEFORE_CONNECT), |
| 48 read_buffer_(NULL), |
| 49 bytes_to_read_(-1), |
| 50 private_api_(private_api) { |
| 51 local_addr_.size = 0; |
| 52 memset(local_addr_.data, 0, |
| 53 arraysize(local_addr_.data) * sizeof(*local_addr_.data)); |
| 54 remote_addr_.size = 0; |
| 55 memset(remote_addr_.data, 0, |
| 56 arraysize(remote_addr_.data) * sizeof(*remote_addr_.data)); |
| 57 } |
| 58 |
| 59 TCPSocketBaseResource::TCPSocketBaseResource( |
| 60 Connection connection, |
| 61 PP_Instance instance, |
| 62 bool private_api, |
| 63 const PP_NetAddress_Private& local_addr, |
| 64 const PP_NetAddress_Private& remote_addr) |
| 65 : PluginResource(connection, instance), |
| 66 connection_state_(CONNECTED), |
| 67 read_buffer_(NULL), |
| 68 bytes_to_read_(-1), |
| 69 private_api_(private_api) { |
| 70 local_addr_ = local_addr_; |
| 71 remote_addr_ = remote_addr_; |
| 72 } |
| 73 |
| 74 TCPSocketBaseResource::~TCPSocketBaseResource() { |
| 75 } |
| 76 |
| 77 int32_t TCPSocketBaseResource::ConnectImpl( |
| 78 const char* host, |
| 79 uint16_t port, |
| 80 scoped_refptr<TrackedCallback> callback) { |
| 148 if (!host) | 81 if (!host) |
| 149 return PP_ERROR_BADARGUMENT; | 82 return PP_ERROR_BADARGUMENT; |
| 150 if (connection_state_ != BEFORE_CONNECT) | 83 if (connection_state_ != BEFORE_CONNECT) |
| 151 return PP_ERROR_FAILED; | 84 return PP_ERROR_FAILED; |
| 152 if (TrackedCallback::IsPending(connect_callback_)) | 85 if (TrackedCallback::IsPending(connect_callback_)) |
| 153 return PP_ERROR_INPROGRESS; // Can only have one pending request. | 86 return PP_ERROR_INPROGRESS; // Can only have one pending request. |
| 154 | 87 |
| 155 connect_callback_ = callback; | 88 connect_callback_ = callback; |
| 156 // Send the request, the browser will call us back via ConnectACK. | 89 |
| 157 SendConnect(host, port); | 90 Call<PpapiPluginMsg_TCPSocket_ConnectReply>( |
| 91 BROWSER, |
| 92 PpapiHostMsg_TCPSocket_Connect(host, port), |
| 93 base::Bind(&TCPSocketBaseResource::OnPluginMsgConnectReply, |
| 94 base::Unretained(this))); |
| 158 return PP_OK_COMPLETIONPENDING; | 95 return PP_OK_COMPLETIONPENDING; |
| 159 } | 96 } |
| 160 | 97 |
| 161 int32_t TCPSocketShared::ConnectWithNetAddressImpl( | 98 int32_t TCPSocketBaseResource::ConnectWithNetAddressImpl( |
| 162 const PP_NetAddress_Private* addr, | 99 const PP_NetAddress_Private* addr, |
| 163 scoped_refptr<TrackedCallback> callback) { | 100 scoped_refptr<TrackedCallback> callback) { |
| 164 if (!addr) | 101 if (!addr) |
| 165 return PP_ERROR_BADARGUMENT; | 102 return PP_ERROR_BADARGUMENT; |
| 166 if (connection_state_ != BEFORE_CONNECT) | 103 if (connection_state_ != BEFORE_CONNECT) |
| 167 return PP_ERROR_FAILED; | 104 return PP_ERROR_FAILED; |
| 168 if (TrackedCallback::IsPending(connect_callback_)) | 105 if (TrackedCallback::IsPending(connect_callback_)) |
| 169 return PP_ERROR_INPROGRESS; // Can only have one pending request. | 106 return PP_ERROR_INPROGRESS; // Can only have one pending request. |
| 170 | 107 |
| 171 connect_callback_ = callback; | 108 connect_callback_ = callback; |
| 172 // Send the request, the browser will call us back via ConnectACK. | 109 |
| 173 SendConnectWithNetAddress(*addr); | 110 Call<PpapiPluginMsg_TCPSocket_ConnectReply>( |
| 111 BROWSER, |
| 112 PpapiHostMsg_TCPSocket_ConnectWithNetAddress(*addr), |
| 113 base::Bind(&TCPSocketBaseResource::OnPluginMsgConnectReply, |
| 114 base::Unretained(this))); |
| 174 return PP_OK_COMPLETIONPENDING; | 115 return PP_OK_COMPLETIONPENDING; |
| 175 } | 116 } |
| 176 | 117 |
| 177 PP_Bool TCPSocketShared::GetLocalAddressImpl( | 118 PP_Bool TCPSocketBaseResource::GetLocalAddressImpl( |
| 178 PP_NetAddress_Private* local_addr) { | 119 PP_NetAddress_Private* local_addr) { |
| 179 if (!IsConnected() || !local_addr) | 120 if (!IsConnected() || !local_addr) |
| 180 return PP_FALSE; | 121 return PP_FALSE; |
| 181 | |
| 182 *local_addr = local_addr_; | 122 *local_addr = local_addr_; |
| 183 return PP_TRUE; | 123 return PP_TRUE; |
| 184 } | 124 } |
| 185 | 125 |
| 186 PP_Bool TCPSocketShared::GetRemoteAddressImpl( | 126 PP_Bool TCPSocketBaseResource::GetRemoteAddressImpl( |
| 187 PP_NetAddress_Private* remote_addr) { | 127 PP_NetAddress_Private* remote_addr) { |
| 188 if (!IsConnected() || !remote_addr) | 128 if (!IsConnected() || !remote_addr) |
| 189 return PP_FALSE; | 129 return PP_FALSE; |
| 190 | |
| 191 *remote_addr = remote_addr_; | 130 *remote_addr = remote_addr_; |
| 192 return PP_TRUE; | 131 return PP_TRUE; |
| 193 } | 132 } |
| 194 | 133 |
| 195 int32_t TCPSocketShared::SSLHandshakeImpl( | 134 int32_t TCPSocketBaseResource::SSLHandshakeImpl( |
| 196 const char* server_name, | 135 const char* server_name, |
| 197 uint16_t server_port, | 136 uint16_t server_port, |
| 198 scoped_refptr<TrackedCallback> callback) { | 137 scoped_refptr<TrackedCallback> callback) { |
| 199 if (!server_name) | 138 if (!server_name) |
| 200 return PP_ERROR_BADARGUMENT; | 139 return PP_ERROR_BADARGUMENT; |
| 201 | 140 |
| 202 if (connection_state_ != CONNECTED) | 141 if (connection_state_ != CONNECTED) |
| 203 return PP_ERROR_FAILED; | 142 return PP_ERROR_FAILED; |
| 204 if (TrackedCallback::IsPending(ssl_handshake_callback_) || | 143 if (TrackedCallback::IsPending(ssl_handshake_callback_) || |
| 205 TrackedCallback::IsPending(read_callback_) || | 144 TrackedCallback::IsPending(read_callback_) || |
| 206 TrackedCallback::IsPending(write_callback_)) | 145 TrackedCallback::IsPending(write_callback_)) { |
| 207 return PP_ERROR_INPROGRESS; | 146 return PP_ERROR_INPROGRESS; |
| 147 } |
| 208 | 148 |
| 209 ssl_handshake_callback_ = callback; | 149 ssl_handshake_callback_ = callback; |
| 210 | 150 |
| 211 // Send the request, the browser will call us back via SSLHandshakeACK. | 151 Call<PpapiPluginMsg_TCPSocket_SSLHandshakeReply>( |
| 212 SendSSLHandshake(server_name, server_port, trusted_certificates_, | 152 BROWSER, |
| 213 untrusted_certificates_); | 153 PpapiHostMsg_TCPSocket_SSLHandshake(server_name, |
| 154 server_port, |
| 155 trusted_certificates_, |
| 156 untrusted_certificates_), |
| 157 base::Bind(&TCPSocketBaseResource::OnPluginMsgSSLHandshakeReply, |
| 158 base::Unretained(this))); |
| 214 return PP_OK_COMPLETIONPENDING; | 159 return PP_OK_COMPLETIONPENDING; |
| 215 } | 160 } |
| 216 | 161 |
| 217 PP_Resource TCPSocketShared::GetServerCertificateImpl() { | 162 PP_Resource TCPSocketBaseResource::GetServerCertificateImpl() { |
| 218 if (!server_certificate_.get()) | 163 if (!server_certificate_.get()) |
| 219 return 0; | 164 return 0; |
| 220 return server_certificate_->GetReference(); | 165 return server_certificate_->GetReference(); |
| 221 } | 166 } |
| 222 | 167 |
| 223 PP_Bool TCPSocketShared::AddChainBuildingCertificateImpl( | 168 PP_Bool TCPSocketBaseResource::AddChainBuildingCertificateImpl( |
| 224 PP_Resource certificate, | 169 PP_Resource certificate, |
| 225 PP_Bool trusted) { | 170 PP_Bool trusted) { |
| 226 // TODO(raymes): The plumbing for this functionality is implemented but the | 171 // TODO(raymes): The plumbing for this functionality is implemented but the |
| 227 // certificates aren't yet used for the connection, so just return false for | 172 // certificates aren't yet used for the connection, so just return false for |
| 228 // now. | 173 // now. |
| 229 return PP_FALSE; | 174 return PP_FALSE; |
| 230 | 175 |
| 231 thunk::EnterResourceNoLock<thunk::PPB_X509Certificate_Private_API> | 176 thunk::EnterResourceNoLock<thunk::PPB_X509Certificate_Private_API> |
| 232 enter_cert(certificate, true); | 177 enter_cert(certificate, true); |
| 233 if (enter_cert.failed()) | 178 if (enter_cert.failed()) |
| (...skipping 10 matching lines...) Expand all Loading... |
| 244 if (PP_ToBool(trusted)) | 189 if (PP_ToBool(trusted)) |
| 245 trusted_certificates_.push_back(der); | 190 trusted_certificates_.push_back(der); |
| 246 else | 191 else |
| 247 untrusted_certificates_.push_back(der); | 192 untrusted_certificates_.push_back(der); |
| 248 success = PP_TRUE; | 193 success = PP_TRUE; |
| 249 } | 194 } |
| 250 PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(der_var); | 195 PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(der_var); |
| 251 return success; | 196 return success; |
| 252 } | 197 } |
| 253 | 198 |
| 254 int32_t TCPSocketShared::ReadImpl(char* buffer, | 199 int32_t TCPSocketBaseResource::ReadImpl( |
| 255 int32_t bytes_to_read, | 200 char* buffer, |
| 256 scoped_refptr<TrackedCallback> callback) { | 201 int32_t bytes_to_read, |
| 202 scoped_refptr<TrackedCallback> callback) { |
| 257 if (!buffer || bytes_to_read <= 0) | 203 if (!buffer || bytes_to_read <= 0) |
| 258 return PP_ERROR_BADARGUMENT; | 204 return PP_ERROR_BADARGUMENT; |
| 259 | 205 |
| 260 if (!IsConnected()) | 206 if (!IsConnected()) |
| 261 return PP_ERROR_FAILED; | 207 return PP_ERROR_FAILED; |
| 262 if (TrackedCallback::IsPending(read_callback_) || | 208 if (TrackedCallback::IsPending(read_callback_) || |
| 263 TrackedCallback::IsPending(ssl_handshake_callback_)) | 209 TrackedCallback::IsPending(ssl_handshake_callback_)) |
| 264 return PP_ERROR_INPROGRESS; | 210 return PP_ERROR_INPROGRESS; |
| 265 read_buffer_ = buffer; | 211 read_buffer_ = buffer; |
| 266 bytes_to_read_ = std::min(bytes_to_read, kMaxReadSize); | 212 bytes_to_read_ = std::min(bytes_to_read, kMaxReadSize); |
| 267 read_callback_ = callback; | 213 read_callback_ = callback; |
| 268 | 214 |
| 269 // Send the request, the browser will call us back via ReadACK. | 215 Call<PpapiPluginMsg_TCPSocket_ReadReply>( |
| 270 SendRead(bytes_to_read_); | 216 BROWSER, |
| 217 PpapiHostMsg_TCPSocket_Read(bytes_to_read), |
| 218 base::Bind(&TCPSocketBaseResource::OnPluginMsgReadReply, |
| 219 base::Unretained(this))); |
| 271 return PP_OK_COMPLETIONPENDING; | 220 return PP_OK_COMPLETIONPENDING; |
| 272 } | 221 } |
| 273 | 222 |
| 274 int32_t TCPSocketShared::WriteImpl(const char* buffer, | 223 int32_t TCPSocketBaseResource::WriteImpl( |
| 275 int32_t bytes_to_write, | 224 const char* buffer, |
| 276 scoped_refptr<TrackedCallback> callback) { | 225 int32_t bytes_to_write, |
| 226 scoped_refptr<TrackedCallback> callback) { |
| 277 if (!buffer || bytes_to_write <= 0) | 227 if (!buffer || bytes_to_write <= 0) |
| 278 return PP_ERROR_BADARGUMENT; | 228 return PP_ERROR_BADARGUMENT; |
| 279 | 229 |
| 280 if (!IsConnected()) | 230 if (!IsConnected()) |
| 281 return PP_ERROR_FAILED; | 231 return PP_ERROR_FAILED; |
| 282 if (TrackedCallback::IsPending(write_callback_) || | 232 if (TrackedCallback::IsPending(write_callback_) || |
| 283 TrackedCallback::IsPending(ssl_handshake_callback_)) | 233 TrackedCallback::IsPending(ssl_handshake_callback_)) |
| 284 return PP_ERROR_INPROGRESS; | 234 return PP_ERROR_INPROGRESS; |
| 285 | 235 |
| 286 if (bytes_to_write > kMaxWriteSize) | 236 if (bytes_to_write > kMaxWriteSize) |
| 287 bytes_to_write = kMaxWriteSize; | 237 bytes_to_write = kMaxWriteSize; |
| 288 | 238 |
| 289 write_callback_ = callback; | 239 write_callback_ = callback; |
| 290 | 240 |
| 291 // Send the request, the browser will call us back via WriteACK. | 241 Call<PpapiPluginMsg_TCPSocket_WriteReply>( |
| 292 SendWrite(std::string(buffer, bytes_to_write)); | 242 BROWSER, |
| 243 PpapiHostMsg_TCPSocket_Write(std::string(buffer, bytes_to_write)), |
| 244 base::Bind(&TCPSocketBaseResource::OnPluginMsgWriteReply, |
| 245 base::Unretained(this))); |
| 293 return PP_OK_COMPLETIONPENDING; | 246 return PP_OK_COMPLETIONPENDING; |
| 294 } | 247 } |
| 295 | 248 |
| 296 void TCPSocketShared::DisconnectImpl() { | 249 void TCPSocketBaseResource::DisconnectImpl() { |
| 297 if (connection_state_ == DISCONNECTED) | 250 if (connection_state_ == DISCONNECTED) |
| 298 return; | 251 return; |
| 299 | 252 |
| 300 connection_state_ = DISCONNECTED; | 253 connection_state_ = DISCONNECTED; |
| 301 | 254 |
| 302 SendDisconnect(); | 255 Post(BROWSER, PpapiHostMsg_TCPSocket_Disconnect()); |
| 303 socket_id_ = 0; | |
| 304 | 256 |
| 305 PostAbortIfNecessary(&connect_callback_); | 257 PostAbortIfNecessary(&connect_callback_); |
| 306 PostAbortIfNecessary(&ssl_handshake_callback_); | 258 PostAbortIfNecessary(&ssl_handshake_callback_); |
| 307 PostAbortIfNecessary(&read_callback_); | 259 PostAbortIfNecessary(&read_callback_); |
| 308 PostAbortIfNecessary(&write_callback_); | 260 PostAbortIfNecessary(&write_callback_); |
| 309 read_buffer_ = NULL; | 261 read_buffer_ = NULL; |
| 310 bytes_to_read_ = -1; | 262 bytes_to_read_ = -1; |
| 311 server_certificate_ = NULL; | 263 server_certificate_ = NULL; |
| 312 } | 264 } |
| 313 | 265 |
| 314 int32_t TCPSocketShared::SetOptionImpl( | 266 int32_t TCPSocketBaseResource::SetOptionImpl( |
| 315 PP_TCPSocket_Option name, | 267 PP_TCPSocket_Option name, |
| 316 const PP_Var& value, | 268 const PP_Var& value, |
| 317 scoped_refptr<TrackedCallback> callback) { | 269 scoped_refptr<TrackedCallback> callback) { |
| 318 if (!IsConnected()) | 270 if (!IsConnected()) |
| 319 return PP_ERROR_FAILED; | 271 return PP_ERROR_FAILED; |
| 320 | 272 |
| 321 SocketOptionData option_data; | 273 SocketOptionData option_data; |
| 322 switch (name) { | 274 switch (name) { |
| 323 case PP_TCPSOCKET_OPTION_NO_DELAY: { | 275 case PP_TCPSOCKET_OPTION_NO_DELAY: { |
| 324 if (value.type != PP_VARTYPE_BOOL) | 276 if (value.type != PP_VARTYPE_BOOL) |
| 325 return PP_ERROR_BADARGUMENT; | 277 return PP_ERROR_BADARGUMENT; |
| 326 option_data.SetBool(PP_ToBool(value.value.as_bool)); | 278 option_data.SetBool(PP_ToBool(value.value.as_bool)); |
| 327 break; | 279 break; |
| 328 } | 280 } |
| 329 case PP_TCPSOCKET_OPTION_SEND_BUFFER_SIZE: | 281 case PP_TCPSOCKET_OPTION_SEND_BUFFER_SIZE: |
| 330 case PP_TCPSOCKET_OPTION_RECV_BUFFER_SIZE: { | 282 case PP_TCPSOCKET_OPTION_RECV_BUFFER_SIZE: { |
| 331 if (value.type != PP_VARTYPE_INT32) | 283 if (value.type != PP_VARTYPE_INT32) |
| 332 return PP_ERROR_BADARGUMENT; | 284 return PP_ERROR_BADARGUMENT; |
| 333 option_data.SetInt32(value.value.as_int); | 285 option_data.SetInt32(value.value.as_int); |
| 334 break; | 286 break; |
| 335 } | 287 } |
| 336 default: { | 288 default: { |
| 337 NOTREACHED(); | 289 NOTREACHED(); |
| 338 return PP_ERROR_BADARGUMENT; | 290 return PP_ERROR_BADARGUMENT; |
| 339 } | 291 } |
| 340 } | 292 } |
| 341 | 293 |
| 342 set_option_callbacks_.push(callback); | 294 set_option_callbacks_.push(callback); |
| 343 SendSetOption(name, option_data); | 295 |
| 296 Call<PpapiPluginMsg_TCPSocket_SetOptionReply>( |
| 297 BROWSER, |
| 298 PpapiHostMsg_TCPSocket_SetOption(name, option_data), |
| 299 base::Bind(&TCPSocketBaseResource::OnPluginMsgSetOptionReply, |
| 300 base::Unretained(this))); |
| 344 return PP_OK_COMPLETIONPENDING; | 301 return PP_OK_COMPLETIONPENDING; |
| 345 } | 302 } |
| 346 | 303 |
| 347 void TCPSocketShared::Init(uint32 socket_id) { | 304 bool TCPSocketBaseResource::IsConnected() const { |
| 348 DCHECK(socket_id != 0); | |
| 349 socket_id_ = socket_id; | |
| 350 connection_state_ = BEFORE_CONNECT; | |
| 351 read_buffer_ = NULL; | |
| 352 bytes_to_read_ = -1; | |
| 353 | |
| 354 local_addr_.size = 0; | |
| 355 memset(local_addr_.data, 0, | |
| 356 arraysize(local_addr_.data) * sizeof(*local_addr_.data)); | |
| 357 remote_addr_.size = 0; | |
| 358 memset(remote_addr_.data, 0, | |
| 359 arraysize(remote_addr_.data) * sizeof(*remote_addr_.data)); | |
| 360 } | |
| 361 | |
| 362 bool TCPSocketShared::IsConnected() const { | |
| 363 return connection_state_ == CONNECTED || connection_state_ == SSL_CONNECTED; | 305 return connection_state_ == CONNECTED || connection_state_ == SSL_CONNECTED; |
| 364 } | 306 } |
| 365 | 307 |
| 366 void TCPSocketShared::PostAbortIfNecessary( | 308 void TCPSocketBaseResource::PostAbortIfNecessary( |
| 367 scoped_refptr<TrackedCallback>* callback) { | 309 scoped_refptr<TrackedCallback>* callback) { |
| 368 if (TrackedCallback::IsPending(*callback)) | 310 if (TrackedCallback::IsPending(*callback)) |
| 369 (*callback)->PostAbort(); | 311 (*callback)->PostAbort(); |
| 370 } | 312 } |
| 371 | 313 |
| 314 void TCPSocketBaseResource::OnPluginMsgConnectReply( |
| 315 const ResourceMessageReplyParams& params, |
| 316 const PP_NetAddress_Private& local_addr, |
| 317 const PP_NetAddress_Private& remote_addr) { |
| 318 // It is possible that |connect_callback_| is pending while |
| 319 // |connection_state_| is not BEFORE_CONNECT: DisconnectImpl() has been |
| 320 // called, but a ConnectCompleted notification came earlier than the task to |
| 321 // abort |connect_callback_|. We don't want to update |connection_state_| or |
| 322 // other members in that case. |
| 323 if (connection_state_ != BEFORE_CONNECT || |
| 324 !TrackedCallback::IsPending(connect_callback_)) { |
| 325 return; |
| 326 } |
| 327 |
| 328 if (params.result() == PP_OK) { |
| 329 local_addr_ = local_addr; |
| 330 remote_addr_ = remote_addr; |
| 331 connection_state_ = CONNECTED; |
| 332 } |
| 333 RunCallback(connect_callback_, params.result()); |
| 334 } |
| 335 |
| 336 void TCPSocketBaseResource::OnPluginMsgSSLHandshakeReply( |
| 337 const ResourceMessageReplyParams& params, |
| 338 const PPB_X509Certificate_Fields& certificate_fields) { |
| 339 // It is possible that |ssl_handshake_callback_| is pending while |
| 340 // |connection_state_| is not CONNECT: DisconnectImpl() has been |
| 341 // called, but a SSLHandshakeCompleted notification came earlier than the task |
| 342 // to abort |ssl_handshake_callback_|. We don't want to update |
| 343 // |connection_state_| or other members in that case. |
| 344 if (connection_state_ != CONNECTED || |
| 345 !TrackedCallback::IsPending(ssl_handshake_callback_)) { |
| 346 return; |
| 347 } |
| 348 |
| 349 if (params.result() == PP_OK) { |
| 350 connection_state_ = SSL_CONNECTED; |
| 351 server_certificate_ = new PPB_X509Certificate_Private_Shared( |
| 352 OBJECT_IS_PROXY, |
| 353 pp_instance(), |
| 354 certificate_fields); |
| 355 RunCallback(ssl_handshake_callback_, params.result()); |
| 356 } else { |
| 357 // The resource might be released in the callback so we need to hold |
| 358 // a reference so we can Disconnect() first. |
| 359 AddRef(); |
| 360 RunCallback(ssl_handshake_callback_, params.result()); |
| 361 DisconnectImpl(); |
| 362 Release(); |
| 363 } |
| 364 } |
| 365 |
| 366 void TCPSocketBaseResource::OnPluginMsgReadReply( |
| 367 const ResourceMessageReplyParams& params, |
| 368 const std::string& data) { |
| 369 // It is possible that |read_callback_| is pending while |read_buffer_| is |
| 370 // NULL: DisconnectImpl() has been called, but a ReadCompleted notification |
| 371 // came earlier than the task to abort |read_callback_|. We shouldn't access |
| 372 // the buffer in that case. The user may have released it. |
| 373 if (!TrackedCallback::IsPending(read_callback_) || !read_buffer_) |
| 374 return; |
| 375 |
| 376 const bool succeeded = params.result() == PP_OK; |
| 377 if (succeeded) { |
| 378 CHECK_LE(static_cast<int32_t>(data.size()), bytes_to_read_); |
| 379 if (!data.empty()) |
| 380 memcpy(read_buffer_, data.c_str(), data.size()); |
| 381 } |
| 382 read_buffer_ = NULL; |
| 383 bytes_to_read_ = -1; |
| 384 |
| 385 read_callback_->Run( |
| 386 succeeded ? |
| 387 static_cast<int32_t>(data.size()) : |
| 388 ConvertPPError(params.result(), private_api_)); |
| 389 } |
| 390 |
| 391 void TCPSocketBaseResource::OnPluginMsgWriteReply( |
| 392 const ResourceMessageReplyParams& params) { |
| 393 if (!TrackedCallback::IsPending(write_callback_)) |
| 394 return; |
| 395 RunCallback(write_callback_, params.result()); |
| 396 } |
| 397 |
| 398 void TCPSocketBaseResource::OnPluginMsgSetOptionReply( |
| 399 const ResourceMessageReplyParams& params) { |
| 400 if (set_option_callbacks_.empty()) { |
| 401 NOTREACHED(); |
| 402 return; |
| 403 } |
| 404 scoped_refptr<TrackedCallback> callback = set_option_callbacks_.front(); |
| 405 set_option_callbacks_.pop(); |
| 406 if (TrackedCallback::IsPending(callback)) |
| 407 RunCallback(callback, params.result()); |
| 408 } |
| 409 |
| 410 void TCPSocketBaseResource::RunCallback(scoped_refptr<TrackedCallback> callback, |
| 411 int32_t pp_result) { |
| 412 callback->Run(ConvertPPError(pp_result, private_api_)); |
| 413 } |
| 414 |
| 372 } // namespace ppapi | 415 } // namespace ppapi |
| 416 } // namespace proxy |
| OLD | NEW |