Revert 168224 - Update V8 to version 3.15.4.
[chromium-blink-merge.git] / remoting / client / plugin / pepper_packet_socket_factory.cc
blob29428ff7daece985f860bf3e38120986d221713a
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.
5 #include "remoting/client/plugin/pepper_packet_socket_factory.h"
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"
16 namespace remoting {
18 namespace {
20 // Size of the buffer to allocate for RecvFrom().
21 const int kReceiveBufferSize = 65536;
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.
27 const int kMaxSendBufferSize = 256 * 1024;
29 class UdpPacketSocket : public talk_base::AsyncPacketSocket {
30 public:
31 explicit UdpPacketSocket(const pp::InstanceHandle& instance);
32 virtual ~UdpPacketSocket();
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);
40 // talk_base::AsyncPacketSocket interface.
41 virtual talk_base::SocketAddress GetLocalAddress() const;
42 virtual talk_base::SocketAddress GetRemoteAddress() const;
43 virtual int Send(const void* data, size_t data_size);
44 virtual int SendTo(const void* data,
45 size_t data_size,
46 const talk_base::SocketAddress& address);
47 virtual int Close();
48 virtual State GetState() const;
49 virtual int GetOption(talk_base::Socket::Option opt, int* value);
50 virtual int SetOption(talk_base::Socket::Option opt, int value);
51 virtual int GetError() const;
52 virtual void SetError(int error);
54 private:
55 struct PendingPacket {
56 PendingPacket(const void* buffer,
57 int buffer_size,
58 const PP_NetAddress_Private& address);
60 scoped_refptr<net::IOBufferWithSize> data;
61 PP_NetAddress_Private address;
64 void OnBindCompleted(int error);
66 void DoSend();
67 void OnSendCompleted(int result);
69 void DoRead();
70 void OnReadCompleted(int result);
71 void HandleReadResult(int result);
73 pp::UDPSocketPrivate socket_;
75 State state_;
76 int error_;
78 talk_base::SocketAddress local_address_;
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_;
85 std::vector<char> receive_buffer_;
87 bool send_pending_;
88 std::list<PendingPacket> send_queue_;
89 int send_queue_size_;
91 base::WeakPtrFactory<UdpPacketSocket> weak_factory_;
93 DISALLOW_COPY_AND_ASSIGN(UdpPacketSocket);
96 UdpPacketSocket::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);
105 UdpPacketSocket::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)) {
116 UdpPacketSocket::~UdpPacketSocket() {
117 Close();
120 bool UdpPacketSocket::Init(const talk_base::SocketAddress& local_address,
121 int min_port,
122 int max_port) {
123 if (socket_.is_null()) {
124 return false;
127 local_address_ = local_address;
128 max_port_ = max_port;
129 min_port_ = min_port;
131 PP_NetAddress_Private pp_local_address;
132 if (!SocketAddressToPpAddressWithPort(local_address_, &pp_local_address,
133 min_port_)) {
134 return false;
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;
143 return true;
146 void UdpPacketSocket::OnBindCompleted(int result) {
147 DCHECK(state_ == STATE_BINDING || state_ == STATE_CLOSED);
149 if (result == PP_ERROR_ABORTED) {
150 // Socket is being destroyed while binding.
151 return;
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;
163 state_ = STATE_BOUND;
164 SignalAddressReady(this, local_address_);
165 DoRead();
166 return;
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);
180 } else {
181 LOG(ERROR) << "Failed to bind UDP socket: " << result;
185 talk_base::SocketAddress UdpPacketSocket::GetLocalAddress() const {
186 DCHECK_EQ(state_, STATE_BOUND);
187 return local_address_;
190 talk_base::SocketAddress UdpPacketSocket::GetRemoteAddress() const {
191 // UDP sockets are not connected - this method should never be called.
192 NOTREACHED();
193 return talk_base::SocketAddress();
196 int 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;
202 int 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;
211 if (error_ != 0) {
212 return error_;
215 PP_NetAddress_Private pp_address;
216 if (!SocketAddressToPpAddress(address, &pp_address)) {
217 return EINVAL;
220 if (send_queue_size_ >= kMaxSendBufferSize) {
221 return EWOULDBLOCK;
224 send_queue_.push_back(PendingPacket(data, data_size, pp_address));
225 send_queue_size_ += data_size;
226 DoSend();
227 return data_size;
230 int UdpPacketSocket::Close() {
231 state_ = STATE_CLOSED;
232 socket_.Close();
233 return 0;
236 talk_base::AsyncPacketSocket::State UdpPacketSocket::GetState() const {
237 return state_;
240 int UdpPacketSocket::GetOption(talk_base::Socket::Option opt, int* value) {
241 // Options are not supported for Pepper UDP sockets.
242 return -1;
245 int UdpPacketSocket::SetOption(talk_base::Socket::Option opt, int value) {
246 // Options are not supported for Pepper UDP sockets.
247 return -1;
250 int UdpPacketSocket::GetError() const {
251 return error_;
254 void UdpPacketSocket::SetError(int error) {
255 error_ = error;
258 void UdpPacketSocket::DoSend() {
259 if (send_pending_ || send_queue_.empty())
260 return;
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;
271 void 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;
279 send_pending_ = false;
281 if (result < 0) {
282 LOG(ERROR) << "Send failed on a UDP socket: " << result;
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.
295 // TODO(sergeyu): Once implementation of the Pepper UDP interface
296 // is fixed, uncomment the code below, but ignore
297 // host-unreacheable error.
299 // error_ = EINVAL;
300 // return;
303 send_queue_size_ -= send_queue_.front().data->size();
304 send_queue_.pop_front();
305 DoSend();
308 void 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);
317 void UdpPacketSocket::OnReadCompleted(int result) {
318 HandleReadResult(result);
319 if (result > 0) {
320 DoRead();
324 void 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;
331 talk_base::SocketAddress address;
332 if (!PpAddressToSocketAddress(pp_address, &address)) {
333 LOG(ERROR) << "Failed to covert address received from RecvFrom().";
334 return;
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;
342 } // namespace
344 PepperPacketSocketFactory::PepperPacketSocketFactory(
345 const pp::InstanceHandle& instance)
346 : pp_instance_(instance) {
349 PepperPacketSocketFactory::~PepperPacketSocketFactory() {
352 talk_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();
362 talk_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;
372 talk_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;
383 } // namespace remoting