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/proxy/udp_socket_resource_base.h"
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"
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;
31 UDPSocketResourceBase::UDPSocketResourceBase(Connection connection,
34 : PluginResource(connection, instance),
35 private_api_(private_api),
40 recvfrom_addr_.size = 0;
41 memset(recvfrom_addr_.data, 0,
42 arraysize(recvfrom_addr_.data) * sizeof(*recvfrom_addr_.data));
44 memset(bound_addr_.data, 0,
45 arraysize(bound_addr_.data) * sizeof(*bound_addr_.data));
48 SendCreate(BROWSER, PpapiHostMsg_UDPSocket_CreatePrivate());
50 SendCreate(BROWSER, PpapiHostMsg_UDPSocket_Create());
53 UDPSocketResourceBase::~UDPSocketResourceBase() {
56 int32_t UDPSocketResourceBase::SetOptionImpl(
57 PP_UDPSocket_Option name,
59 scoped_refptr<TrackedCallback> callback) {
61 return PP_ERROR_FAILED;
63 SocketOptionData option_data;
65 case PP_UDPSOCKET_OPTION_ADDRESS_REUSE:
66 case PP_UDPSOCKET_OPTION_BROADCAST: {
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));
74 case PP_UDPSOCKET_OPTION_SEND_BUFFER_SIZE:
75 case PP_UDPSOCKET_OPTION_RECV_BUFFER_SIZE: {
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);
85 return PP_ERROR_BADARGUMENT;
89 Call<PpapiPluginMsg_UDPSocket_SetOptionReply>(
91 PpapiHostMsg_UDPSocket_SetOption(name, option_data),
92 base::Bind(&UDPSocketResourceBase::OnPluginMsgSetOptionReply,
93 base::Unretained(this),
95 return PP_OK_COMPLETIONPENDING;
98 int32_t UDPSocketResourceBase::BindImpl(
99 const PP_NetAddress_Private* addr,
100 scoped_refptr<TrackedCallback> callback) {
102 return PP_ERROR_BADARGUMENT;
103 if (bound_ || closed_)
104 return PP_ERROR_FAILED;
105 if (TrackedCallback::IsPending(bind_callback_))
106 return PP_ERROR_INPROGRESS;
108 bind_callback_ = callback;
110 // Send the request, the browser will call us back via BindReply.
111 Call<PpapiPluginMsg_UDPSocket_BindReply>(
113 PpapiHostMsg_UDPSocket_Bind(*addr),
114 base::Bind(&UDPSocketResourceBase::OnPluginMsgBindReply,
115 base::Unretained(this)));
116 return PP_OK_COMPLETIONPENDING;
119 PP_Bool UDPSocketResourceBase::GetBoundAddressImpl(
120 PP_NetAddress_Private* addr) {
121 if (!addr || !bound_ || closed_)
128 int32_t UDPSocketResourceBase::RecvFromImpl(
132 scoped_refptr<TrackedCallback> callback) {
133 if (!buffer || num_bytes <= 0)
134 return PP_ERROR_BADARGUMENT;
136 return PP_ERROR_FAILED;
137 if (TrackedCallback::IsPending(recvfrom_callback_))
138 return PP_ERROR_INPROGRESS;
140 read_buffer_ = buffer;
141 bytes_to_read_ = std::min(num_bytes, kMaxReadSize);
142 recvfrom_callback_ = callback;
144 // Send the request, the browser will call us back via RecvFromReply.
145 Call<PpapiPluginMsg_UDPSocket_RecvFromReply>(
147 PpapiHostMsg_UDPSocket_RecvFrom(bytes_to_read_),
148 base::Bind(&UDPSocketResourceBase::OnPluginMsgRecvFromReply,
149 base::Unretained(this), addr));
150 return PP_OK_COMPLETIONPENDING;
153 PP_Bool UDPSocketResourceBase::GetRecvFromAddressImpl(
154 PP_NetAddress_Private* addr) {
157 *addr = recvfrom_addr_;
161 int32_t UDPSocketResourceBase::SendToImpl(
164 const PP_NetAddress_Private* addr,
165 scoped_refptr<TrackedCallback> callback) {
166 if (!buffer || num_bytes <= 0 || !addr)
167 return PP_ERROR_BADARGUMENT;
169 return PP_ERROR_FAILED;
170 if (TrackedCallback::IsPending(sendto_callback_))
171 return PP_ERROR_INPROGRESS;
173 if (num_bytes > kMaxWriteSize)
174 num_bytes = kMaxWriteSize;
176 sendto_callback_ = callback;
178 // Send the request, the browser will call us back via SendToReply.
179 Call<PpapiPluginMsg_UDPSocket_SendToReply>(
181 PpapiHostMsg_UDPSocket_SendTo(std::string(buffer, num_bytes), *addr),
182 base::Bind(&UDPSocketResourceBase::OnPluginMsgSendToReply,
183 base::Unretained(this)));
184 return PP_OK_COMPLETIONPENDING;
187 void UDPSocketResourceBase::CloseImpl() {
194 Post(BROWSER, PpapiHostMsg_UDPSocket_Close());
196 PostAbortIfNecessary(&bind_callback_);
197 PostAbortIfNecessary(&recvfrom_callback_);
198 PostAbortIfNecessary(&sendto_callback_);
204 void UDPSocketResourceBase::PostAbortIfNecessary(
205 scoped_refptr<TrackedCallback>* callback) {
206 if (TrackedCallback::IsPending(*callback))
207 (*callback)->PostAbort();
210 void UDPSocketResourceBase::OnPluginMsgSetOptionReply(
211 scoped_refptr<TrackedCallback> callback,
212 const ResourceMessageReplyParams& params) {
213 if (TrackedCallback::IsPending(callback))
214 RunCallback(callback, params.result());
217 void UDPSocketResourceBase::OnPluginMsgBindReply(
218 const ResourceMessageReplyParams& params,
219 const PP_NetAddress_Private& bound_addr) {
220 // It is possible that |bind_callback_| is pending while |closed_| is true:
221 // CloseImpl() has been called, but a BindReply came earlier than the task to
222 // abort |bind_callback_|. We don't want to update |bound_| or |bound_addr_|
224 if (!TrackedCallback::IsPending(bind_callback_) || closed_)
227 if (params.result() == PP_OK)
229 bound_addr_ = bound_addr;
230 RunCallback(bind_callback_, params.result());
233 void UDPSocketResourceBase::OnPluginMsgRecvFromReply(
234 PP_Resource* output_addr,
235 const ResourceMessageReplyParams& params,
236 const std::string& data,
237 const PP_NetAddress_Private& addr) {
238 // It is possible that |recvfrom_callback_| is pending while |read_buffer_| is
239 // NULL: CloseImpl() has been called, but a RecvFromReply came earlier than
240 // the task to abort |recvfrom_callback_|. We shouldn't access the buffer in
241 // that case. The user may have released it.
242 if (!TrackedCallback::IsPending(recvfrom_callback_) || !read_buffer_)
245 int32_t result = params.result();
246 if (result == PP_OK && output_addr) {
247 thunk::EnterResourceCreationNoLock enter(pp_instance());
248 if (enter.succeeded()) {
249 *output_addr = enter.functions()->CreateNetAddressFromNetAddressPrivate(
250 pp_instance(), addr);
252 result = PP_ERROR_FAILED;
256 if (result == PP_OK) {
257 CHECK_LE(static_cast<int32_t>(data.size()), bytes_to_read_);
259 memcpy(read_buffer_, data.c_str(), data.size());
264 recvfrom_addr_ = addr;
267 RunCallback(recvfrom_callback_, static_cast<int32_t>(data.size()));
269 RunCallback(recvfrom_callback_, result);
272 void UDPSocketResourceBase::OnPluginMsgSendToReply(
273 const ResourceMessageReplyParams& params,
274 int32_t bytes_written) {
275 if (!TrackedCallback::IsPending(sendto_callback_))
278 if (params.result() == PP_OK)
279 RunCallback(sendto_callback_, bytes_written);
281 RunCallback(sendto_callback_, params.result());
284 void UDPSocketResourceBase::RunCallback(scoped_refptr<TrackedCallback> callback,
286 callback->Run(ConvertNetworkAPIErrorForCompatibility(pp_result,