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.
4
5 #include "ppapi/proxy/udp_socket_resource_base.h"
6
7 #include <algorithm>
8 #include <cstring>
9
10 #include "base/logging.h"
11 #include "ppapi/c/pp_bool.h"
12 #include "ppapi/c/pp_completion_callback.h"
13 #include "ppapi/c/pp_errors.h"
14 #include "ppapi/proxy/error_conversion.h"
15 #include "ppapi/proxy/ppapi_messages.h"
16 #include "ppapi/shared_impl/socket_option_data.h"
17 #include "ppapi/thunk/enter.h"
18 #include "ppapi/thunk/resource_creation_api.h"
19
20 namespace ppapi {
21 namespace proxy {
22
23 const int32_t UDPSocketResourceBase::kMaxReadSize = 1024 * 1024;
24 const int32_t UDPSocketResourceBase::kMaxWriteSize = 1024 * 1024;
25 const int32_t UDPSocketResourceBase::kMaxSendBufferSize =
26 1024 * UDPSocketResourceBase::kMaxWriteSize;
27 const int32_t UDPSocketResourceBase::kMaxReceiveBufferSize =
28 1024 * UDPSocketResourceBase::kMaxReadSize;
29
30
UDPSocketResourceBase(Connection connection,PP_Instance instance,bool private_api)31 UDPSocketResourceBase::UDPSocketResourceBase(Connection connection,
32 PP_Instance instance,
33 bool private_api)
34 : PluginResource(connection, instance),
35 private_api_(private_api),
36 bound_(false),
37 closed_(false),
38 read_buffer_(NULL),
39 bytes_to_read_(-1) {
40 recvfrom_addr_.size = 0;
41 memset(recvfrom_addr_.data, 0,
42 arraysize(recvfrom_addr_.data) * sizeof(*recvfrom_addr_.data));
43 bound_addr_.size = 0;
44 memset(bound_addr_.data, 0,
45 arraysize(bound_addr_.data) * sizeof(*bound_addr_.data));
46
47 if (private_api)
48 SendCreate(BROWSER, PpapiHostMsg_UDPSocket_CreatePrivate());
49 else
50 SendCreate(BROWSER, PpapiHostMsg_UDPSocket_Create());
51 }
52
~UDPSocketResourceBase()53 UDPSocketResourceBase::~UDPSocketResourceBase() {
54 }
55
SetOptionImpl(PP_UDPSocket_Option name,const PP_Var & value,scoped_refptr<TrackedCallback> callback)56 int32_t UDPSocketResourceBase::SetOptionImpl(
57 PP_UDPSocket_Option name,
58 const PP_Var& value,
59 scoped_refptr<TrackedCallback> callback) {
60 if (closed_)
61 return PP_ERROR_FAILED;
62
63 SocketOptionData option_data;
64 switch (name) {
65 case PP_UDPSOCKET_OPTION_ADDRESS_REUSE:
66 case PP_UDPSOCKET_OPTION_BROADCAST: {
67 if (bound_)
68 return PP_ERROR_FAILED;
69 if (value.type != PP_VARTYPE_BOOL)
70 return PP_ERROR_BADARGUMENT;
71 option_data.SetBool(PP_ToBool(value.value.as_bool));
72 break;
73 }
74 case PP_UDPSOCKET_OPTION_SEND_BUFFER_SIZE:
75 case PP_UDPSOCKET_OPTION_RECV_BUFFER_SIZE: {
76 if (!bound_)
77 return PP_ERROR_FAILED;
78 if (value.type != PP_VARTYPE_INT32)
79 return PP_ERROR_BADARGUMENT;
80 option_data.SetInt32(value.value.as_int);
81 break;
82 }
83 default: {
84 NOTREACHED();
85 return PP_ERROR_BADARGUMENT;
86 }
87 }
88
89 Call<PpapiPluginMsg_UDPSocket_SetOptionReply>(
90 BROWSER,
91 PpapiHostMsg_UDPSocket_SetOption(name, option_data),
92 base::Bind(&UDPSocketResourceBase::OnPluginMsgSetOptionReply,
93 base::Unretained(this),
94 callback),
95 callback);
96 return PP_OK_COMPLETIONPENDING;
97 }
98
BindImpl(const PP_NetAddress_Private * addr,scoped_refptr<TrackedCallback> callback)99 int32_t UDPSocketResourceBase::BindImpl(
100 const PP_NetAddress_Private* addr,
101 scoped_refptr<TrackedCallback> callback) {
102 if (!addr)
103 return PP_ERROR_BADARGUMENT;
104 if (bound_ || closed_)
105 return PP_ERROR_FAILED;
106 if (TrackedCallback::IsPending(bind_callback_))
107 return PP_ERROR_INPROGRESS;
108
109 bind_callback_ = callback;
110
111 // Send the request, the browser will call us back via BindReply.
112 Call<PpapiPluginMsg_UDPSocket_BindReply>(
113 BROWSER,
114 PpapiHostMsg_UDPSocket_Bind(*addr),
115 base::Bind(&UDPSocketResourceBase::OnPluginMsgBindReply,
116 base::Unretained(this)),
117 callback);
118 return PP_OK_COMPLETIONPENDING;
119 }
120
GetBoundAddressImpl(PP_NetAddress_Private * addr)121 PP_Bool UDPSocketResourceBase::GetBoundAddressImpl(
122 PP_NetAddress_Private* addr) {
123 if (!addr || !bound_ || closed_)
124 return PP_FALSE;
125
126 *addr = bound_addr_;
127 return PP_TRUE;
128 }
129
RecvFromImpl(char * buffer,int32_t num_bytes,PP_Resource * addr,scoped_refptr<TrackedCallback> callback)130 int32_t UDPSocketResourceBase::RecvFromImpl(
131 char* buffer,
132 int32_t num_bytes,
133 PP_Resource* addr,
134 scoped_refptr<TrackedCallback> callback) {
135 if (!buffer || num_bytes <= 0)
136 return PP_ERROR_BADARGUMENT;
137 if (!bound_)
138 return PP_ERROR_FAILED;
139 if (TrackedCallback::IsPending(recvfrom_callback_))
140 return PP_ERROR_INPROGRESS;
141
142 read_buffer_ = buffer;
143 bytes_to_read_ = std::min(num_bytes, kMaxReadSize);
144 recvfrom_callback_ = callback;
145
146 // Send the request, the browser will call us back via RecvFromReply.
147 Call<PpapiPluginMsg_UDPSocket_RecvFromReply>(
148 BROWSER,
149 PpapiHostMsg_UDPSocket_RecvFrom(bytes_to_read_),
150 base::Bind(&UDPSocketResourceBase::OnPluginMsgRecvFromReply,
151 base::Unretained(this), addr),
152 callback);
153 return PP_OK_COMPLETIONPENDING;
154 }
155
GetRecvFromAddressImpl(PP_NetAddress_Private * addr)156 PP_Bool UDPSocketResourceBase::GetRecvFromAddressImpl(
157 PP_NetAddress_Private* addr) {
158 if (!addr)
159 return PP_FALSE;
160 *addr = recvfrom_addr_;
161 return PP_TRUE;
162 }
163
SendToImpl(const char * buffer,int32_t num_bytes,const PP_NetAddress_Private * addr,scoped_refptr<TrackedCallback> callback)164 int32_t UDPSocketResourceBase::SendToImpl(
165 const char* buffer,
166 int32_t num_bytes,
167 const PP_NetAddress_Private* addr,
168 scoped_refptr<TrackedCallback> callback) {
169 if (!buffer || num_bytes <= 0 || !addr)
170 return PP_ERROR_BADARGUMENT;
171 if (!bound_)
172 return PP_ERROR_FAILED;
173 if (TrackedCallback::IsPending(sendto_callback_))
174 return PP_ERROR_INPROGRESS;
175
176 if (num_bytes > kMaxWriteSize)
177 num_bytes = kMaxWriteSize;
178
179 sendto_callback_ = callback;
180
181 // Send the request, the browser will call us back via SendToReply.
182 Call<PpapiPluginMsg_UDPSocket_SendToReply>(
183 BROWSER,
184 PpapiHostMsg_UDPSocket_SendTo(std::string(buffer, num_bytes), *addr),
185 base::Bind(&UDPSocketResourceBase::OnPluginMsgSendToReply,
186 base::Unretained(this)),
187 callback);
188 return PP_OK_COMPLETIONPENDING;
189 }
190
CloseImpl()191 void UDPSocketResourceBase::CloseImpl() {
192 if(closed_)
193 return;
194
195 bound_ = false;
196 closed_ = true;
197
198 Post(BROWSER, PpapiHostMsg_UDPSocket_Close());
199
200 PostAbortIfNecessary(&bind_callback_);
201 PostAbortIfNecessary(&recvfrom_callback_);
202 PostAbortIfNecessary(&sendto_callback_);
203
204 read_buffer_ = NULL;
205 bytes_to_read_ = -1;
206 }
207
PostAbortIfNecessary(scoped_refptr<TrackedCallback> * callback)208 void UDPSocketResourceBase::PostAbortIfNecessary(
209 scoped_refptr<TrackedCallback>* callback) {
210 if (TrackedCallback::IsPending(*callback))
211 (*callback)->PostAbort();
212 }
213
OnPluginMsgSetOptionReply(scoped_refptr<TrackedCallback> callback,const ResourceMessageReplyParams & params)214 void UDPSocketResourceBase::OnPluginMsgSetOptionReply(
215 scoped_refptr<TrackedCallback> callback,
216 const ResourceMessageReplyParams& params) {
217 if (TrackedCallback::IsPending(callback))
218 RunCallback(callback, params.result());
219 }
220
OnPluginMsgBindReply(const ResourceMessageReplyParams & params,const PP_NetAddress_Private & bound_addr)221 void UDPSocketResourceBase::OnPluginMsgBindReply(
222 const ResourceMessageReplyParams& params,
223 const PP_NetAddress_Private& bound_addr) {
224 // It is possible that |bind_callback_| is pending while |closed_| is true:
225 // CloseImpl() has been called, but a BindReply came earlier than the task to
226 // abort |bind_callback_|. We don't want to update |bound_| or |bound_addr_|
227 // in that case.
228 if (!TrackedCallback::IsPending(bind_callback_) || closed_)
229 return;
230
231 if (params.result() == PP_OK)
232 bound_ = true;
233 bound_addr_ = bound_addr;
234 RunCallback(bind_callback_, params.result());
235 }
236
OnPluginMsgRecvFromReply(PP_Resource * output_addr,const ResourceMessageReplyParams & params,const std::string & data,const PP_NetAddress_Private & addr)237 void UDPSocketResourceBase::OnPluginMsgRecvFromReply(
238 PP_Resource* output_addr,
239 const ResourceMessageReplyParams& params,
240 const std::string& data,
241 const PP_NetAddress_Private& addr) {
242 // It is possible that |recvfrom_callback_| is pending while |read_buffer_| is
243 // NULL: CloseImpl() has been called, but a RecvFromReply came earlier than
244 // the task to abort |recvfrom_callback_|. We shouldn't access the buffer in
245 // that case. The user may have released it.
246 if (!TrackedCallback::IsPending(recvfrom_callback_) || !read_buffer_)
247 return;
248
249 int32_t result = params.result();
250 if (result == PP_OK && output_addr) {
251 thunk::EnterResourceCreationNoLock enter(pp_instance());
252 if (enter.succeeded()) {
253 *output_addr = enter.functions()->CreateNetAddressFromNetAddressPrivate(
254 pp_instance(), addr);
255 } else {
256 result = PP_ERROR_FAILED;
257 }
258 }
259
260 if (result == PP_OK) {
261 CHECK_LE(static_cast<int32_t>(data.size()), bytes_to_read_);
262 if (!data.empty())
263 memcpy(read_buffer_, data.c_str(), data.size());
264 }
265
266 read_buffer_ = NULL;
267 bytes_to_read_ = -1;
268 recvfrom_addr_ = addr;
269
270 if (result == PP_OK)
271 RunCallback(recvfrom_callback_, static_cast<int32_t>(data.size()));
272 else
273 RunCallback(recvfrom_callback_, result);
274 }
275
OnPluginMsgSendToReply(const ResourceMessageReplyParams & params,int32_t bytes_written)276 void UDPSocketResourceBase::OnPluginMsgSendToReply(
277 const ResourceMessageReplyParams& params,
278 int32_t bytes_written) {
279 if (!TrackedCallback::IsPending(sendto_callback_))
280 return;
281
282 if (params.result() == PP_OK)
283 RunCallback(sendto_callback_, bytes_written);
284 else
285 RunCallback(sendto_callback_, params.result());
286 }
287
RunCallback(scoped_refptr<TrackedCallback> callback,int32_t pp_result)288 void UDPSocketResourceBase::RunCallback(scoped_refptr<TrackedCallback> callback,
289 int32_t pp_result) {
290 callback->Run(ConvertNetworkAPIErrorForCompatibility(pp_result,
291 private_api_));
292 }
293
294 } // namespace proxy
295 } // namespace ppapi
296