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
,