OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 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 "ppapi/shared_impl/private/tcp_socket_private_impl.h" | |
6 | |
7 #include <string.h> | |
8 | |
9 #include <algorithm> | |
10 | |
11 #include "base/basictypes.h" | |
12 #include "base/bind.h" | |
13 #include "base/logging.h" | |
14 #include "base/message_loop.h" | |
15 #include "ppapi/c/pp_completion_callback.h" | |
16 #include "ppapi/c/pp_errors.h" | |
17 | |
18 namespace ppapi { | |
19 | |
20 namespace { | |
21 | |
22 void AbortCallback(PP_CompletionCallback callback) { | |
23 PP_RunCompletionCallback(&callback, PP_ERROR_ABORTED); | |
24 } | |
25 | |
26 } // namespace | |
27 | |
28 const int32_t TCPSocketPrivateImpl::kMaxReadSize = 1024 * 1024; | |
29 const int32_t TCPSocketPrivateImpl::kMaxWriteSize = 1024 * 1024; | |
30 | |
31 TCPSocketPrivateImpl::TCPSocketPrivateImpl(PP_Instance instance, | |
32 uint32 socket_id) | |
33 : Resource(instance) { | |
34 Init(socket_id); | |
35 } | |
36 | |
37 TCPSocketPrivateImpl::TCPSocketPrivateImpl(const HostResource& resource, | |
38 uint32 socket_id) | |
39 : Resource(resource) { | |
40 Init(socket_id); | |
41 } | |
42 | |
43 TCPSocketPrivateImpl::~TCPSocketPrivateImpl() { | |
44 } | |
45 | |
46 thunk::PPB_TCPSocket_Private_API* | |
47 TCPSocketPrivateImpl::AsPPB_TCPSocket_Private_API() { | |
48 return this; | |
49 } | |
50 | |
51 int32_t TCPSocketPrivateImpl::Connect(const char* host, | |
52 uint16_t port, | |
53 PP_CompletionCallback callback) { | |
54 if (!host) | |
55 return PP_ERROR_BADARGUMENT; | |
56 if (!callback.func) | |
57 return PP_ERROR_BLOCKS_MAIN_THREAD; | |
58 if (connection_state_ != BEFORE_CONNECT) | |
59 return PP_ERROR_FAILED; | |
60 if (connect_callback_.func) | |
61 return PP_ERROR_INPROGRESS; // Can only have one pending request. | |
62 | |
63 connect_callback_ = callback; | |
64 // Send the request, the browser will call us back via ConnectACK. | |
65 SendConnect(host, port); | |
66 return PP_OK_COMPLETIONPENDING; | |
67 } | |
68 | |
69 int32_t TCPSocketPrivateImpl::ConnectWithNetAddress( | |
70 const PP_NetAddress_Private* addr, | |
71 PP_CompletionCallback callback) { | |
72 if (!addr) | |
73 return PP_ERROR_BADARGUMENT; | |
74 if (!callback.func) | |
75 return PP_ERROR_BLOCKS_MAIN_THREAD; | |
76 if (connection_state_ != BEFORE_CONNECT) | |
77 return PP_ERROR_FAILED; | |
78 if (connect_callback_.func) | |
79 return PP_ERROR_INPROGRESS; // Can only have one pending request. | |
80 | |
81 connect_callback_ = callback; | |
82 // Send the request, the browser will call us back via ConnectACK. | |
83 SendConnectWithNetAddress(*addr); | |
84 return PP_OK_COMPLETIONPENDING; | |
85 } | |
86 | |
87 PP_Bool TCPSocketPrivateImpl::GetLocalAddress( | |
88 PP_NetAddress_Private* local_addr) { | |
89 if (!IsConnected() || !local_addr) | |
90 return PP_FALSE; | |
91 | |
92 *local_addr = local_addr_; | |
93 return PP_TRUE; | |
94 } | |
95 | |
96 PP_Bool TCPSocketPrivateImpl::GetRemoteAddress( | |
97 PP_NetAddress_Private* remote_addr) { | |
98 if (!IsConnected() || !remote_addr) | |
99 return PP_FALSE; | |
100 | |
101 *remote_addr = remote_addr_; | |
102 return PP_TRUE; | |
103 } | |
104 | |
105 int32_t TCPSocketPrivateImpl::SSLHandshake(const char* server_name, | |
106 uint16_t server_port, | |
107 PP_CompletionCallback callback) { | |
108 if (!server_name) | |
109 return PP_ERROR_BADARGUMENT; | |
110 if (!callback.func) | |
111 return PP_ERROR_BLOCKS_MAIN_THREAD; | |
112 | |
113 if (connection_state_ != CONNECTED) | |
114 return PP_ERROR_FAILED; | |
115 if (ssl_handshake_callback_.func || read_callback_.func || | |
116 write_callback_.func) | |
117 return PP_ERROR_INPROGRESS; | |
118 | |
119 ssl_handshake_callback_ = callback; | |
120 | |
121 // Send the request, the browser will call us back via SSLHandshakeACK. | |
122 SendSSLHandshake(server_name, server_port); | |
123 return PP_OK_COMPLETIONPENDING; | |
124 } | |
125 | |
126 int32_t TCPSocketPrivateImpl::Read(char* buffer, | |
127 int32_t bytes_to_read, | |
128 PP_CompletionCallback callback) { | |
129 if (!buffer || bytes_to_read <= 0) | |
130 return PP_ERROR_BADARGUMENT; | |
131 if (!callback.func) | |
132 return PP_ERROR_BLOCKS_MAIN_THREAD; | |
133 | |
134 if (!IsConnected()) | |
135 return PP_ERROR_FAILED; | |
136 if (read_callback_.func || ssl_handshake_callback_.func) | |
137 return PP_ERROR_INPROGRESS; | |
138 // TODO(dmichael): use some other strategy for determining if an | |
139 // operation is in progress | |
140 read_buffer_ = buffer; | |
141 bytes_to_read_ = std::min(bytes_to_read, kMaxReadSize); | |
142 read_callback_ = callback; | |
143 | |
144 // Send the request, the browser will call us back via ReadACK. | |
145 SendRead(bytes_to_read_); | |
146 return PP_OK_COMPLETIONPENDING; | |
147 } | |
148 | |
149 int32_t TCPSocketPrivateImpl::Write(const char* buffer, | |
150 int32_t bytes_to_write, | |
151 PP_CompletionCallback callback) { | |
152 if (!buffer || bytes_to_write <= 0) | |
153 return PP_ERROR_BADARGUMENT; | |
154 if (!callback.func) | |
155 return PP_ERROR_BLOCKS_MAIN_THREAD; | |
156 | |
157 if (!IsConnected()) | |
158 return PP_ERROR_FAILED; | |
159 if (write_callback_.func || ssl_handshake_callback_.func) | |
160 return PP_ERROR_INPROGRESS; | |
161 | |
162 if (bytes_to_write > kMaxWriteSize) | |
163 bytes_to_write = kMaxWriteSize; | |
164 | |
165 write_callback_ = callback; | |
166 | |
167 // Send the request, the browser will call us back via WriteACK. | |
168 SendWrite(std::string(buffer, bytes_to_write)); | |
169 return PP_OK_COMPLETIONPENDING; | |
170 } | |
171 | |
172 void TCPSocketPrivateImpl::Disconnect() { | |
173 if (connection_state_ == DISCONNECTED) | |
174 return; | |
175 | |
176 connection_state_ = DISCONNECTED; | |
177 | |
178 SendDisconnect(); | |
179 socket_id_ = 0; | |
180 | |
181 PostAbortAndClearIfNecessary(&connect_callback_); | |
182 PostAbortAndClearIfNecessary(&ssl_handshake_callback_); | |
183 PostAbortAndClearIfNecessary(&read_callback_); | |
184 PostAbortAndClearIfNecessary(&write_callback_); | |
185 read_buffer_ = NULL; | |
186 bytes_to_read_ = -1; | |
187 } | |
188 | |
189 void TCPSocketPrivateImpl::OnConnectCompleted( | |
190 bool succeeded, | |
191 const PP_NetAddress_Private& local_addr, | |
192 const PP_NetAddress_Private& remote_addr) { | |
193 if (connection_state_ != BEFORE_CONNECT || !connect_callback_.func) { | |
194 NOTREACHED(); | |
195 return; | |
196 } | |
197 | |
198 if (succeeded) { | |
199 local_addr_ = local_addr; | |
200 remote_addr_ = remote_addr; | |
201 connection_state_ = CONNECTED; | |
202 } | |
203 PP_RunAndClearCompletionCallback(&connect_callback_, | |
204 succeeded ? PP_OK : PP_ERROR_FAILED); | |
205 } | |
206 | |
207 void TCPSocketPrivateImpl::OnSSLHandshakeCompleted(bool succeeded) { | |
208 if (connection_state_ != CONNECTED || !ssl_handshake_callback_.func) { | |
209 NOTREACHED(); | |
210 return; | |
211 } | |
212 | |
213 if (succeeded) { | |
214 connection_state_ = SSL_CONNECTED; | |
215 PP_RunAndClearCompletionCallback(&ssl_handshake_callback_, PP_OK); | |
216 } else { | |
217 PP_RunAndClearCompletionCallback(&ssl_handshake_callback_, PP_ERROR_FAILED); | |
218 Disconnect(); | |
219 } | |
220 } | |
221 | |
222 void TCPSocketPrivateImpl::OnReadCompleted(bool succeeded, | |
223 const std::string& data) { | |
224 if (!read_callback_.func || !read_buffer_) { | |
225 NOTREACHED(); | |
226 return; | |
227 } | |
228 | |
229 if (succeeded) { | |
230 CHECK_LE(static_cast<int32_t>(data.size()), bytes_to_read_); | |
231 if (!data.empty()) | |
232 memcpy(read_buffer_, data.c_str(), data.size()); | |
233 } | |
234 read_buffer_ = NULL; | |
235 bytes_to_read_ = -1; | |
236 | |
237 PP_RunAndClearCompletionCallback( | |
238 &read_callback_, | |
239 succeeded ? static_cast<int32_t>(data.size()) : | |
240 static_cast<int32_t>(PP_ERROR_FAILED)); | |
241 } | |
242 | |
243 void TCPSocketPrivateImpl::OnWriteCompleted(bool succeeded, | |
244 int32_t bytes_written) { | |
245 if (!write_callback_.func || (succeeded && bytes_written < 0)) { | |
246 NOTREACHED(); | |
247 return; | |
248 } | |
249 | |
250 PP_RunAndClearCompletionCallback( | |
251 &write_callback_, | |
252 succeeded ? bytes_written : static_cast<int32_t>(PP_ERROR_FAILED)); | |
253 } | |
254 | |
255 void TCPSocketPrivateImpl::Init(uint32 socket_id) { | |
256 DCHECK(socket_id != 0); | |
257 socket_id_ = socket_id; | |
258 connection_state_ = BEFORE_CONNECT; | |
259 connect_callback_ = PP_BlockUntilComplete(); | |
260 ssl_handshake_callback_ = PP_BlockUntilComplete(); | |
261 read_callback_ = PP_BlockUntilComplete(); | |
262 write_callback_ = PP_BlockUntilComplete(); | |
263 read_buffer_ = NULL; | |
264 bytes_to_read_ = -1; | |
265 | |
266 local_addr_.size = 0; | |
267 memset(local_addr_.data, 0, | |
268 arraysize(local_addr_.data) * sizeof(*local_addr_.data)); | |
269 remote_addr_.size = 0; | |
270 memset(remote_addr_.data, 0, | |
271 arraysize(remote_addr_.data) * sizeof(*remote_addr_.data)); | |
272 } | |
273 | |
274 bool TCPSocketPrivateImpl::IsConnected() const { | |
275 return connection_state_ == CONNECTED || connection_state_ == SSL_CONNECTED; | |
276 } | |
277 | |
278 void TCPSocketPrivateImpl::PostAbortAndClearIfNecessary( | |
279 PP_CompletionCallback* callback) { | |
280 DCHECK(callback); | |
281 | |
282 if (callback->func) { | |
283 MessageLoop::current()->PostTask(FROM_HERE, | |
284 base::Bind(&AbortCallback, *callback)); | |
285 *callback = PP_BlockUntilComplete(); | |
286 } | |
287 } | |
288 | |
289 } // namespace ppapi | |
OLD | NEW |