pepper_packet_socket_factory.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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 "remoting/client/plugin/pepper_packet_socket_factory.h"
6
7#include "base/bind.h"
8#include "base/logging.h"
9#include "net/base/io_buffer.h"
10#include "ppapi/cpp/net_address.h"
11#include "ppapi/cpp/udp_socket.h"
12#include "ppapi/utility/completion_callback_factory.h"
13#include "remoting/client/plugin/pepper_util.h"
14#include "third_party/libjingle/source/talk/base/asyncpacketsocket.h"
15
16namespace remoting {
17
18namespace {
19
20// Size of the buffer to allocate for RecvFrom().
21const int kReceiveBufferSize = 65536;
22
23// Maximum amount of data in the send buffers. This is necessary to
24// prevent out-of-memory crashes if the caller sends data faster than
25// Pepper's UDP API can handle it. This maximum should never be
26// reached under normal conditions.
27const int kMaxSendBufferSize = 256 * 1024;
28
29class UdpPacketSocket : public talk_base::AsyncPacketSocket {
30 public:
31  explicit UdpPacketSocket(const pp::InstanceHandle& instance);
32  virtual ~UdpPacketSocket();
33
34  // |min_port| and |max_port| are set to zero if the port number
35  // should be assigned by the OS.
36  bool Init(const talk_base::SocketAddress& local_address,
37            int min_port,
38            int max_port);
39
40  // talk_base::AsyncPacketSocket interface.
41  virtual talk_base::SocketAddress GetLocalAddress() const OVERRIDE;
42  virtual talk_base::SocketAddress GetRemoteAddress() const OVERRIDE;
43  virtual int Send(const void* data, size_t data_size,
44                   const talk_base::PacketOptions& options) OVERRIDE;
45  virtual int SendTo(const void* data,
46                     size_t data_size,
47                     const talk_base::SocketAddress& address,
48                     const talk_base::PacketOptions& options) OVERRIDE;
49  virtual int Close() OVERRIDE;
50  virtual State GetState() const OVERRIDE;
51  virtual int GetOption(talk_base::Socket::Option opt, int* value) OVERRIDE;
52  virtual int SetOption(talk_base::Socket::Option opt, int value) OVERRIDE;
53  virtual int GetError() const OVERRIDE;
54  virtual void SetError(int error) OVERRIDE;
55
56 private:
57  struct PendingPacket {
58    PendingPacket(const void* buffer,
59                  int buffer_size,
60                  const pp::NetAddress& address);
61
62    scoped_refptr<net::IOBufferWithSize> data;
63    pp::NetAddress address;
64  };
65
66  void OnBindCompleted(int error);
67
68  void DoSend();
69  void OnSendCompleted(int result);
70
71  void DoRead();
72  void OnReadCompleted(int result, pp::NetAddress address);
73  void HandleReadResult(int result, pp::NetAddress address);
74
75  pp::InstanceHandle instance_;
76
77  pp::UDPSocket socket_;
78
79  State state_;
80  int error_;
81
82  talk_base::SocketAddress local_address_;
83
84  // Used to scan ports when necessary. Both values are set to 0 when
85  // the port number is assigned by OS.
86  uint16_t min_port_;
87  uint16_t max_port_;
88
89  std::vector<char> receive_buffer_;
90
91  bool send_pending_;
92  std::list<PendingPacket> send_queue_;
93  int send_queue_size_;
94
95  pp::CompletionCallbackFactory<UdpPacketSocket> callback_factory_;
96
97  DISALLOW_COPY_AND_ASSIGN(UdpPacketSocket);
98};
99
100UdpPacketSocket::PendingPacket::PendingPacket(
101    const void* buffer,
102    int buffer_size,
103    const pp::NetAddress& address)
104    : data(new net::IOBufferWithSize(buffer_size)),
105      address(address) {
106  memcpy(data->data(), buffer, buffer_size);
107}
108
109UdpPacketSocket::UdpPacketSocket(const pp::InstanceHandle& instance)
110    : instance_(instance),
111      socket_(instance),
112      state_(STATE_CLOSED),
113      error_(0),
114      min_port_(0),
115      max_port_(0),
116      send_pending_(false),
117      send_queue_size_(0),
118      callback_factory_(this) {
119}
120
121UdpPacketSocket::~UdpPacketSocket() {
122  Close();
123}
124
125bool UdpPacketSocket::Init(const talk_base::SocketAddress& local_address,
126                           int min_port,
127                           int max_port) {
128  if (socket_.is_null()) {
129    return false;
130  }
131
132  local_address_ = local_address;
133  max_port_ = max_port;
134  min_port_ = min_port;
135
136  pp::NetAddress pp_local_address;
137  if (!SocketAddressToPpNetAddressWithPort(
138          instance_, local_address_, &pp_local_address, min_port_)) {
139    return false;
140  }
141
142  pp::CompletionCallback callback =
143      callback_factory_.NewCallback(&UdpPacketSocket::OnBindCompleted);
144  int result = socket_.Bind(pp_local_address, callback);
145  DCHECK_EQ(result, PP_OK_COMPLETIONPENDING);
146  state_ = STATE_BINDING;
147
148  return true;
149}
150
151void UdpPacketSocket::OnBindCompleted(int result) {
152  DCHECK(state_ == STATE_BINDING || state_ == STATE_CLOSED);
153
154  if (result == PP_ERROR_ABORTED) {
155    // Socket is being destroyed while binding.
156    return;
157  }
158
159  if (result == PP_OK) {
160    pp::NetAddress address = socket_.GetBoundAddress();
161    PpNetAddressToSocketAddress(address, &local_address_);
162    state_ = STATE_BOUND;
163    SignalAddressReady(this, local_address_);
164    DoRead();
165    return;
166  }
167
168  if (min_port_ < max_port_) {
169    // Try to bind to the next available port.
170    ++min_port_;
171    pp::NetAddress pp_local_address;
172    if (SocketAddressToPpNetAddressWithPort(
173            instance_, local_address_, &pp_local_address, min_port_)) {
174      pp::CompletionCallback callback =
175          callback_factory_.NewCallback(&UdpPacketSocket::OnBindCompleted);
176      int result = socket_.Bind(pp_local_address, callback);
177      DCHECK_EQ(result, PP_OK_COMPLETIONPENDING);
178    }
179  } else {
180    LOG(ERROR) << "Failed to bind UDP socket: " << result;
181  }
182}
183
184talk_base::SocketAddress UdpPacketSocket::GetLocalAddress() const {
185  DCHECK_EQ(state_, STATE_BOUND);
186  return local_address_;
187}
188
189talk_base::SocketAddress UdpPacketSocket::GetRemoteAddress() const {
190  // UDP sockets are not connected - this method should never be called.
191  NOTREACHED();
192  return talk_base::SocketAddress();
193}
194
195int UdpPacketSocket::Send(const void* data, size_t data_size,
196                          const talk_base::PacketOptions& options) {
197  // UDP sockets are not connected - this method should never be called.
198  NOTREACHED();
199  return EWOULDBLOCK;
200}
201
202int UdpPacketSocket::SendTo(const void* data,
203                            size_t data_size,
204                            const talk_base::SocketAddress& address,
205                            const talk_base::PacketOptions& options) {
206  if (state_ != STATE_BOUND) {
207    // TODO(sergeyu): StunPort may try to send stun request before we
208    // are bound. Fix that problem and change this to DCHECK.
209    return EINVAL;
210  }
211
212  if (error_ != 0) {
213    return error_;
214  }
215
216  pp::NetAddress pp_address;
217  if (!SocketAddressToPpNetAddress(instance_, address, &pp_address)) {
218    return EINVAL;
219  }
220
221  if (send_queue_size_ >= kMaxSendBufferSize) {
222    return EWOULDBLOCK;
223  }
224
225  send_queue_.push_back(PendingPacket(data, data_size, pp_address));
226  send_queue_size_ += data_size;
227  DoSend();
228  return data_size;
229}
230
231int UdpPacketSocket::Close() {
232  state_ = STATE_CLOSED;
233  socket_.Close();
234  return 0;
235}
236
237talk_base::AsyncPacketSocket::State UdpPacketSocket::GetState() const {
238  return state_;
239}
240
241int UdpPacketSocket::GetOption(talk_base::Socket::Option opt, int* value) {
242  // Options are not supported for Pepper UDP sockets.
243  return -1;
244}
245
246int UdpPacketSocket::SetOption(talk_base::Socket::Option opt, int value) {
247  // Options are not supported for Pepper UDP sockets.
248  return -1;
249}
250
251int UdpPacketSocket::GetError() const {
252  return error_;
253}
254
255void UdpPacketSocket::SetError(int error) {
256  error_ = error;
257}
258
259void UdpPacketSocket::DoSend() {
260  if (send_pending_ || send_queue_.empty())
261    return;
262
263  pp::CompletionCallback callback =
264      callback_factory_.NewCallback(&UdpPacketSocket::OnSendCompleted);
265  int result = socket_.SendTo(
266      send_queue_.front().data->data(), send_queue_.front().data->size(),
267      send_queue_.front().address,
268      callback);
269  DCHECK_EQ(result, PP_OK_COMPLETIONPENDING);
270  send_pending_ = true;
271}
272
273void UdpPacketSocket::OnSendCompleted(int result) {
274  if (result == PP_ERROR_ABORTED) {
275    // Send is aborted when the socket is being destroyed.
276    // |send_queue_| may be already destroyed, it's not safe to access
277    // it here.
278    return;
279  }
280
281  send_pending_ = false;
282
283  if (result < 0) {
284    LOG(ERROR) << "Send failed on a UDP socket: " << result;
285
286    // OS (e.g. OSX) may return EHOSTUNREACH when the peer has the
287    // same subnet address as the local host but connected to a
288    // different network. That error must be ingored because the
289    // socket may still be useful for other ICE canidadates (e.g. for
290    // STUN candidates with a different address). Unfortunately pepper
291    // interface currently returns PP_ERROR_FAILED for any error (see
292    // crbug.com/136406). It's not possible to distinguish that case
293    // from other errors and so we have to ingore all of them. This
294    // behavior matchers the libjingle's AsyncUDPSocket used by the
295    // host.
296    //
297    // TODO(sergeyu): Once implementation of the Pepper UDP interface
298    // is fixed, uncomment the code below, but ignore
299    // host-unreacheable error.
300
301    // error_ = EINVAL;
302    // return;
303  }
304
305  send_queue_size_ -= send_queue_.front().data->size();
306  send_queue_.pop_front();
307  DoSend();
308}
309
310void UdpPacketSocket::DoRead() {
311  receive_buffer_.resize(kReceiveBufferSize);
312  pp::CompletionCallbackWithOutput<pp::NetAddress> callback =
313      callback_factory_.NewCallbackWithOutput(
314          &UdpPacketSocket::OnReadCompleted);
315  int result =
316      socket_.RecvFrom(&receive_buffer_[0], receive_buffer_.size(), callback);
317  DCHECK_EQ(result, PP_OK_COMPLETIONPENDING);
318}
319
320void UdpPacketSocket::OnReadCompleted(int result, pp::NetAddress address) {
321  HandleReadResult(result, address);
322  if (result > 0) {
323    DoRead();
324  }
325}
326
327  void UdpPacketSocket::HandleReadResult(int result, pp::NetAddress address) {
328  if (result > 0) {
329    talk_base::SocketAddress socket_address;
330    PpNetAddressToSocketAddress(address, &socket_address);
331    SignalReadPacket(this, &receive_buffer_[0], result, socket_address,
332                     talk_base::CreatePacketTime(0));
333  } else if (result != PP_ERROR_ABORTED) {
334    LOG(ERROR) << "Received error when reading from UDP socket: " << result;
335  }
336}
337
338}  // namespace
339
340PepperPacketSocketFactory::PepperPacketSocketFactory(
341    const pp::InstanceHandle& instance)
342    : pp_instance_(instance) {
343}
344
345PepperPacketSocketFactory::~PepperPacketSocketFactory() {
346}
347
348talk_base::AsyncPacketSocket* PepperPacketSocketFactory::CreateUdpSocket(
349      const talk_base::SocketAddress& local_address,
350      int min_port,
351      int max_port) {
352  scoped_ptr<UdpPacketSocket> result(new UdpPacketSocket(pp_instance_));
353  if (!result->Init(local_address, min_port, max_port))
354    return NULL;
355  return result.release();
356}
357
358talk_base::AsyncPacketSocket* PepperPacketSocketFactory::CreateServerTcpSocket(
359    const talk_base::SocketAddress& local_address,
360    int min_port,
361    int max_port,
362    int opts) {
363  // We don't use TCP sockets for remoting connections.
364  NOTREACHED();
365  return NULL;
366}
367
368talk_base::AsyncPacketSocket* PepperPacketSocketFactory::CreateClientTcpSocket(
369      const talk_base::SocketAddress& local_address,
370      const talk_base::SocketAddress& remote_address,
371      const talk_base::ProxyInfo& proxy_info,
372      const std::string& user_agent,
373      int opts) {
374  // We don't use TCP sockets for remoting connections.
375  NOTREACHED();
376  return NULL;
377}
378
379talk_base::AsyncResolverInterface*
380PepperPacketSocketFactory::CreateAsyncResolver() {
381  NOTREACHED();
382  return NULL;
383}
384
385}  // namespace remoting
386