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),
96 return PP_OK_COMPLETIONPENDING
;
99 int32_t UDPSocketResourceBase::BindImpl(
100 const PP_NetAddress_Private
* addr
,
101 scoped_refptr
<TrackedCallback
> callback
) {
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
;
109 bind_callback_
= callback
;
111 // Send the request, the browser will call us back via BindReply.
112 Call
<PpapiPluginMsg_UDPSocket_BindReply
>(
114 PpapiHostMsg_UDPSocket_Bind(*addr
),
115 base::Bind(&UDPSocketResourceBase::OnPluginMsgBindReply
,
116 base::Unretained(this)),
118 return PP_OK_COMPLETIONPENDING
;
121 PP_Bool
UDPSocketResourceBase::GetBoundAddressImpl(
122 PP_NetAddress_Private
* addr
) {
123 if (!addr
|| !bound_
|| closed_
)
130 int32_t UDPSocketResourceBase::RecvFromImpl(
134 scoped_refptr
<TrackedCallback
> callback
) {
135 if (!buffer
|| num_bytes
<= 0)
136 return PP_ERROR_BADARGUMENT
;
138 return PP_ERROR_FAILED
;
139 if (TrackedCallback::IsPending(recvfrom_callback_
))
140 return PP_ERROR_INPROGRESS
;
142 read_buffer_
= buffer
;
143 bytes_to_read_
= std::min(num_bytes
, kMaxReadSize
);
144 recvfrom_callback_
= callback
;
146 // Send the request, the browser will call us back via RecvFromReply.
147 Call
<PpapiPluginMsg_UDPSocket_RecvFromReply
>(
149 PpapiHostMsg_UDPSocket_RecvFrom(bytes_to_read_
),
150 base::Bind(&UDPSocketResourceBase::OnPluginMsgRecvFromReply
,
151 base::Unretained(this), addr
),
153 return PP_OK_COMPLETIONPENDING
;
156 PP_Bool
UDPSocketResourceBase::GetRecvFromAddressImpl(
157 PP_NetAddress_Private
* addr
) {
160 *addr
= recvfrom_addr_
;
164 int32_t UDPSocketResourceBase::SendToImpl(
167 const PP_NetAddress_Private
* addr
,
168 scoped_refptr
<TrackedCallback
> callback
) {
169 if (!buffer
|| num_bytes
<= 0 || !addr
)
170 return PP_ERROR_BADARGUMENT
;
172 return PP_ERROR_FAILED
;
173 if (TrackedCallback::IsPending(sendto_callback_
))
174 return PP_ERROR_INPROGRESS
;
176 if (num_bytes
> kMaxWriteSize
)
177 num_bytes
= kMaxWriteSize
;
179 sendto_callback_
= callback
;
181 // Send the request, the browser will call us back via SendToReply.
182 Call
<PpapiPluginMsg_UDPSocket_SendToReply
>(
184 PpapiHostMsg_UDPSocket_SendTo(std::string(buffer
, num_bytes
), *addr
),
185 base::Bind(&UDPSocketResourceBase::OnPluginMsgSendToReply
,
186 base::Unretained(this)),
188 return PP_OK_COMPLETIONPENDING
;
191 void UDPSocketResourceBase::CloseImpl() {
198 Post(BROWSER
, PpapiHostMsg_UDPSocket_Close());
200 PostAbortIfNecessary(&bind_callback_
);
201 PostAbortIfNecessary(&recvfrom_callback_
);
202 PostAbortIfNecessary(&sendto_callback_
);
208 void UDPSocketResourceBase::PostAbortIfNecessary(
209 scoped_refptr
<TrackedCallback
>* callback
) {
210 if (TrackedCallback::IsPending(*callback
))
211 (*callback
)->PostAbort();
214 void UDPSocketResourceBase::OnPluginMsgSetOptionReply(
215 scoped_refptr
<TrackedCallback
> callback
,
216 const ResourceMessageReplyParams
& params
) {
217 if (TrackedCallback::IsPending(callback
))
218 RunCallback(callback
, params
.result());
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_|
228 if (!TrackedCallback::IsPending(bind_callback_
) || closed_
)
231 if (params
.result() == PP_OK
)
233 bound_addr_
= bound_addr
;
234 RunCallback(bind_callback_
, params
.result());
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_
)
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
);
256 result
= PP_ERROR_FAILED
;
260 if (result
== PP_OK
) {
261 CHECK_LE(static_cast<int32_t>(data
.size()), bytes_to_read_
);
263 memcpy(read_buffer_
, data
.c_str(), data
.size());
268 recvfrom_addr_
= addr
;
271 RunCallback(recvfrom_callback_
, static_cast<int32_t>(data
.size()));
273 RunCallback(recvfrom_callback_
, result
);
276 void UDPSocketResourceBase::OnPluginMsgSendToReply(
277 const ResourceMessageReplyParams
& params
,
278 int32_t bytes_written
) {
279 if (!TrackedCallback::IsPending(sendto_callback_
))
282 if (params
.result() == PP_OK
)
283 RunCallback(sendto_callback_
, bytes_written
);
285 RunCallback(sendto_callback_
, params
.result());
288 void UDPSocketResourceBase::RunCallback(scoped_refptr
<TrackedCallback
> callback
,
290 callback
->Run(ConvertNetworkAPIErrorForCompatibility(pp_result
,