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