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