• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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