- add sources.
[platform/framework/web/crosswalk.git] / src / ppapi / proxy / udp_socket_resource_base.cc
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
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
53 UDPSocketResourceBase::~UDPSocketResourceBase() {
54 }
55
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   return PP_OK_COMPLETIONPENDING;
96 }
97
98 int32_t UDPSocketResourceBase::BindImpl(
99     const PP_NetAddress_Private* addr,
100     scoped_refptr<TrackedCallback> callback) {
101   if (!addr)
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;
107
108   bind_callback_ = callback;
109
110   // Send the request, the browser will call us back via BindReply.
111   Call<PpapiPluginMsg_UDPSocket_BindReply>(
112       BROWSER,
113       PpapiHostMsg_UDPSocket_Bind(*addr),
114       base::Bind(&UDPSocketResourceBase::OnPluginMsgBindReply,
115                  base::Unretained(this)));
116   return PP_OK_COMPLETIONPENDING;
117 }
118
119 PP_Bool UDPSocketResourceBase::GetBoundAddressImpl(
120     PP_NetAddress_Private* addr) {
121   if (!addr || !bound_ || closed_)
122     return PP_FALSE;
123
124   *addr = bound_addr_;
125   return PP_TRUE;
126 }
127
128 int32_t UDPSocketResourceBase::RecvFromImpl(
129     char* buffer,
130     int32_t num_bytes,
131     PP_Resource* addr,
132     scoped_refptr<TrackedCallback> callback) {
133   if (!buffer || num_bytes <= 0)
134     return PP_ERROR_BADARGUMENT;
135   if (!bound_)
136     return PP_ERROR_FAILED;
137   if (TrackedCallback::IsPending(recvfrom_callback_))
138     return PP_ERROR_INPROGRESS;
139
140   read_buffer_ = buffer;
141   bytes_to_read_ = std::min(num_bytes, kMaxReadSize);
142   recvfrom_callback_ = callback;
143
144   // Send the request, the browser will call us back via RecvFromReply.
145   Call<PpapiPluginMsg_UDPSocket_RecvFromReply>(
146       BROWSER,
147       PpapiHostMsg_UDPSocket_RecvFrom(bytes_to_read_),
148       base::Bind(&UDPSocketResourceBase::OnPluginMsgRecvFromReply,
149                  base::Unretained(this), addr));
150   return PP_OK_COMPLETIONPENDING;
151 }
152
153 PP_Bool UDPSocketResourceBase::GetRecvFromAddressImpl(
154     PP_NetAddress_Private* addr) {
155   if (!addr)
156     return PP_FALSE;
157   *addr = recvfrom_addr_;
158   return PP_TRUE;
159 }
160
161 int32_t UDPSocketResourceBase::SendToImpl(
162     const char* buffer,
163     int32_t num_bytes,
164     const PP_NetAddress_Private* addr,
165     scoped_refptr<TrackedCallback> callback) {
166   if (!buffer || num_bytes <= 0 || !addr)
167     return PP_ERROR_BADARGUMENT;
168   if (!bound_)
169     return PP_ERROR_FAILED;
170   if (TrackedCallback::IsPending(sendto_callback_))
171     return PP_ERROR_INPROGRESS;
172
173   if (num_bytes > kMaxWriteSize)
174     num_bytes = kMaxWriteSize;
175
176   sendto_callback_ = callback;
177
178   // Send the request, the browser will call us back via SendToReply.
179   Call<PpapiPluginMsg_UDPSocket_SendToReply>(
180       BROWSER,
181       PpapiHostMsg_UDPSocket_SendTo(std::string(buffer, num_bytes), *addr),
182       base::Bind(&UDPSocketResourceBase::OnPluginMsgSendToReply,
183                  base::Unretained(this)));
184   return PP_OK_COMPLETIONPENDING;
185 }
186
187 void UDPSocketResourceBase::CloseImpl() {
188   if(closed_)
189     return;
190
191   bound_ = false;
192   closed_ = true;
193
194   Post(BROWSER, PpapiHostMsg_UDPSocket_Close());
195
196   PostAbortIfNecessary(&bind_callback_);
197   PostAbortIfNecessary(&recvfrom_callback_);
198   PostAbortIfNecessary(&sendto_callback_);
199
200   read_buffer_ = NULL;
201   bytes_to_read_ = -1;
202 }
203
204 void UDPSocketResourceBase::PostAbortIfNecessary(
205     scoped_refptr<TrackedCallback>* callback) {
206   if (TrackedCallback::IsPending(*callback))
207     (*callback)->PostAbort();
208 }
209
210 void UDPSocketResourceBase::OnPluginMsgSetOptionReply(
211     scoped_refptr<TrackedCallback> callback,
212     const ResourceMessageReplyParams& params) {
213   if (TrackedCallback::IsPending(callback))
214     RunCallback(callback, params.result());
215 }
216
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_|
223   // in that case.
224   if (!TrackedCallback::IsPending(bind_callback_) || closed_)
225     return;
226
227   if (params.result() == PP_OK)
228     bound_ = true;
229   bound_addr_ = bound_addr;
230   RunCallback(bind_callback_, params.result());
231 }
232
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_)
243     return;
244
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);
251     } else {
252       result = PP_ERROR_FAILED;
253     }
254   }
255
256   if (result == PP_OK) {
257     CHECK_LE(static_cast<int32_t>(data.size()), bytes_to_read_);
258     if (!data.empty())
259       memcpy(read_buffer_, data.c_str(), data.size());
260   }
261
262   read_buffer_ = NULL;
263   bytes_to_read_ = -1;
264   recvfrom_addr_ = addr;
265
266   if (result == PP_OK)
267     RunCallback(recvfrom_callback_, static_cast<int32_t>(data.size()));
268   else
269     RunCallback(recvfrom_callback_, result);
270 }
271
272 void UDPSocketResourceBase::OnPluginMsgSendToReply(
273     const ResourceMessageReplyParams& params,
274     int32_t bytes_written) {
275   if (!TrackedCallback::IsPending(sendto_callback_))
276     return;
277
278   if (params.result() == PP_OK)
279     RunCallback(sendto_callback_, bytes_written);
280   else
281     RunCallback(sendto_callback_, params.result());
282 }
283
284 void UDPSocketResourceBase::RunCallback(scoped_refptr<TrackedCallback> callback,
285                                         int32_t pp_result) {
286   callback->Run(ConvertNetworkAPIErrorForCompatibility(pp_result,
287                                                        private_api_));
288 }
289
290 }  // namespace proxy
291 }  // namespace ppapi