udp_socket_private_resource.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
1// Copyright (c) 2012 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_private_resource.h"
6
7#include <algorithm>
8#include <cstring>
9
10#include "base/basictypes.h"
11#include "base/logging.h"
12#include "ppapi/c/pp_bool.h"
13#include "ppapi/c/pp_completion_callback.h"
14#include "ppapi/c/pp_errors.h"
15#include "ppapi/proxy/ppapi_messages.h"
16
17namespace ppapi {
18namespace proxy {
19
20const int32_t UDPSocketPrivateResource::kMaxReadSize = 1024 * 1024;
21const int32_t UDPSocketPrivateResource::kMaxWriteSize = 1024 * 1024;
22
23UDPSocketPrivateResource::UDPSocketPrivateResource(Connection connection,
24                                                   PP_Instance instance)
25    : PluginResource(connection, instance),
26      bound_(false),
27      closed_(false),
28      read_buffer_(NULL),
29      bytes_to_read_(-1) {
30  recvfrom_addr_.size = 0;
31  memset(recvfrom_addr_.data, 0,
32         arraysize(recvfrom_addr_.data) * sizeof(*recvfrom_addr_.data));
33  bound_addr_.size = 0;
34  memset(bound_addr_.data, 0,
35         arraysize(bound_addr_.data) * sizeof(*bound_addr_.data));
36
37  SendCreate(BROWSER, PpapiHostMsg_UDPSocketPrivate_Create());
38}
39
40UDPSocketPrivateResource::~UDPSocketPrivateResource() {
41}
42
43thunk::PPB_UDPSocket_Private_API*
44UDPSocketPrivateResource::AsPPB_UDPSocket_Private_API() {
45  return this;
46}
47
48int32_t UDPSocketPrivateResource::SetSocketFeature(
49    PP_UDPSocketFeature_Private name,
50    PP_Var value) {
51  if (bound_ || closed_)
52    return PP_ERROR_FAILED;
53
54  switch (name) {
55    case PP_UDPSOCKETFEATURE_ADDRESS_REUSE:
56    case PP_UDPSOCKETFEATURE_BROADCAST:
57      if (value.type != PP_VARTYPE_BOOL)
58        return PP_ERROR_BADARGUMENT;
59      SendBoolSocketFeature(static_cast<int32_t>(name),
60                            PP_ToBool(value.value.as_bool));
61      break;
62    default:
63      return PP_ERROR_BADARGUMENT;
64  }
65  return PP_OK;
66}
67
68int32_t UDPSocketPrivateResource::Bind(
69    const PP_NetAddress_Private* addr,
70    scoped_refptr<TrackedCallback> callback) {
71  if (!addr)
72    return PP_ERROR_BADARGUMENT;
73  if (bound_ || closed_)
74    return PP_ERROR_FAILED;
75  if (TrackedCallback::IsPending(bind_callback_))
76    return PP_ERROR_INPROGRESS;
77
78  bind_callback_ = callback;
79
80  // Send the request, the browser will call us back via BindReply.
81  SendBind(*addr);
82  return PP_OK_COMPLETIONPENDING;
83}
84
85PP_Bool UDPSocketPrivateResource::GetBoundAddress(PP_NetAddress_Private* addr) {
86  if (!addr || !bound_ || closed_)
87    return PP_FALSE;
88
89  *addr = bound_addr_;
90  return PP_TRUE;
91}
92
93int32_t UDPSocketPrivateResource::RecvFrom(
94    char* buffer,
95    int32_t num_bytes,
96    scoped_refptr<TrackedCallback> callback) {
97  if (!buffer || num_bytes <= 0)
98    return PP_ERROR_BADARGUMENT;
99  if (!bound_)
100    return PP_ERROR_FAILED;
101  if (TrackedCallback::IsPending(recvfrom_callback_))
102    return PP_ERROR_INPROGRESS;
103
104  read_buffer_ = buffer;
105  bytes_to_read_ = std::min(num_bytes, kMaxReadSize);
106  recvfrom_callback_ = callback;
107
108  // Send the request, the browser will call us back via RecvFromReply.
109  SendRecvFrom(bytes_to_read_);
110  return PP_OK_COMPLETIONPENDING;
111}
112
113PP_Bool UDPSocketPrivateResource::GetRecvFromAddress(
114    PP_NetAddress_Private* addr) {
115  if (!addr)
116    return PP_FALSE;
117  *addr = recvfrom_addr_;
118  return PP_TRUE;
119}
120
121void UDPSocketPrivateResource::PostAbortIfNecessary(
122    scoped_refptr<TrackedCallback>* callback) {
123  if (TrackedCallback::IsPending(*callback))
124    (*callback)->PostAbort();
125}
126
127int32_t UDPSocketPrivateResource::SendTo(
128    const char* buffer,
129    int32_t num_bytes,
130    const PP_NetAddress_Private* addr,
131    scoped_refptr<TrackedCallback> callback) {
132  if (!buffer || num_bytes <= 0 || !addr)
133    return PP_ERROR_BADARGUMENT;
134  if (!bound_)
135    return PP_ERROR_FAILED;
136  if (TrackedCallback::IsPending(sendto_callback_))
137    return PP_ERROR_INPROGRESS;
138
139  if (num_bytes > kMaxWriteSize)
140    num_bytes = kMaxWriteSize;
141
142  sendto_callback_ = callback;
143
144  // Send the request, the browser will call us back via SendToReply.
145  SendSendTo(std::string(buffer, num_bytes), *addr);
146  return PP_OK_COMPLETIONPENDING;
147}
148
149void UDPSocketPrivateResource::Close() {
150  if(closed_)
151    return;
152
153  bound_ = false;
154  closed_ = true;
155
156  SendClose();
157
158  PostAbortIfNecessary(&bind_callback_);
159  PostAbortIfNecessary(&recvfrom_callback_);
160  PostAbortIfNecessary(&sendto_callback_);
161}
162
163void UDPSocketPrivateResource::SendBoolSocketFeature(int32_t name, bool value) {
164  PpapiHostMsg_UDPSocketPrivate_SetBoolSocketFeature msg(name, value);
165  Post(BROWSER, msg);
166}
167
168void UDPSocketPrivateResource::SendBind(const PP_NetAddress_Private& addr) {
169  PpapiHostMsg_UDPSocketPrivate_Bind msg(addr);
170  Call<PpapiPluginMsg_UDPSocketPrivate_BindReply>(
171      BROWSER,
172      msg,
173      base::Bind(&UDPSocketPrivateResource::OnPluginMsgBindReply,
174                 base::Unretained(this)));
175}
176
177void UDPSocketPrivateResource::SendRecvFrom(int32_t num_bytes) {
178  PpapiHostMsg_UDPSocketPrivate_RecvFrom msg(num_bytes);
179  Call<PpapiPluginMsg_UDPSocketPrivate_RecvFromReply>(
180      BROWSER,
181      msg,
182      base::Bind(&UDPSocketPrivateResource::OnPluginMsgRecvFromReply,
183                 base::Unretained(this)));
184}
185
186void UDPSocketPrivateResource::SendSendTo(const std::string& buffer,
187                                          const PP_NetAddress_Private& addr) {
188  PpapiHostMsg_UDPSocketPrivate_SendTo msg(buffer, addr);
189  Call<PpapiPluginMsg_UDPSocketPrivate_SendToReply>(
190      BROWSER,
191      msg,
192      base::Bind(&UDPSocketPrivateResource::OnPluginMsgSendToReply,
193                 base::Unretained(this)));
194}
195
196void UDPSocketPrivateResource::SendClose() {
197  PpapiHostMsg_UDPSocketPrivate_Close msg;
198  Post(BROWSER, msg);
199}
200
201void UDPSocketPrivateResource::OnPluginMsgBindReply(
202    const ResourceMessageReplyParams& params,
203    const PP_NetAddress_Private& bound_addr) {
204  if (!TrackedCallback::IsPending(bind_callback_)) {
205    NOTREACHED();
206    return;
207  }
208  if (params.result() == PP_OK)
209    bound_ = true;
210  bound_addr_ = bound_addr;
211  bind_callback_->Run(params.result());
212}
213
214void UDPSocketPrivateResource::OnPluginMsgRecvFromReply(
215    const ResourceMessageReplyParams& params,
216    const std::string& data,
217    const PP_NetAddress_Private& addr) {
218  if (!TrackedCallback::IsPending(recvfrom_callback_) || !read_buffer_) {
219    NOTREACHED();
220    return;
221  }
222  bool succeeded = (params.result() == PP_OK);
223  if (succeeded) {
224    CHECK_LE(static_cast<int32_t>(data.size()), bytes_to_read_);
225    if (!data.empty())
226      memcpy(read_buffer_, data.c_str(), data.size());
227  }
228  read_buffer_ = NULL;
229  bytes_to_read_ = -1;
230  recvfrom_addr_ = addr;
231
232  if (succeeded)
233    recvfrom_callback_->Run(static_cast<int32_t>(data.size()));
234  else
235    recvfrom_callback_->Run(params.result());
236}
237
238void UDPSocketPrivateResource::OnPluginMsgSendToReply(
239    const ResourceMessageReplyParams& params,
240    int32_t bytes_written) {
241  if (!TrackedCallback::IsPending(sendto_callback_)) {
242    NOTREACHED();
243    return;
244  }
245  if (params.result() == PP_OK)
246    sendto_callback_->Run(bytes_written);
247  else
248    sendto_callback_->Run(params.result());
249}
250
251}  // namespace proxy
252}  // namespace ppapi
253