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"
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"
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
{
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
,
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
,
46 const talk_base::SocketAddress
& address
);
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
);
55 struct PendingPacket
{
56 PendingPacket(const void* buffer
,
58 const PP_NetAddress_Private
& address
);
60 scoped_refptr
<net::IOBufferWithSize
> data
;
61 PP_NetAddress_Private address
;
64 void OnBindCompleted(int error
);
67 void OnSendCompleted(int result
);
70 void OnReadCompleted(int result
);
71 void HandleReadResult(int result
);
73 pp::UDPSocketPrivate socket_
;
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.
85 std::vector
<char> receive_buffer_
;
88 std::list
<PendingPacket
> send_queue_
;
91 base::WeakPtrFactory
<UdpPacketSocket
> weak_factory_
;
93 DISALLOW_COPY_AND_ASSIGN(UdpPacketSocket
);
96 UdpPacketSocket::PendingPacket::PendingPacket(
99 const PP_NetAddress_Private
& address
)
100 : data(new net::IOBufferWithSize(buffer_size
)),
102 memcpy(data
->data(), buffer
, buffer_size
);
105 UdpPacketSocket::UdpPacketSocket(const pp::InstanceHandle
& instance
)
107 state_(STATE_CLOSED
),
111 send_pending_(false),
113 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
116 UdpPacketSocket::~UdpPacketSocket() {
120 bool UdpPacketSocket::Init(const talk_base::SocketAddress
& local_address
,
123 if (socket_
.is_null()) {
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
,
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
;
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.
154 if (result
== PP_OK
) {
155 PP_NetAddress_Private address
;
156 if (socket_
.GetBoundAddress(&address
)) {
157 PpAddressToSocketAddress(address
, &local_address_
);
159 LOG(ERROR
) << "Failed to get bind address for bound socket?";
163 state_
= STATE_BOUND
;
164 SignalAddressReady(this, local_address_
);
169 if (min_port_
< max_port_
) {
170 // Try to bind to the next available port.
172 PP_NetAddress_Private pp_local_address
;
173 if (SocketAddressToPpAddressWithPort(local_address_
, &pp_local_address
,
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
);
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.
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.
202 int UdpPacketSocket::SendTo(const void* data
,
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.
215 PP_NetAddress_Private pp_address
;
216 if (!SocketAddressToPpAddress(address
, &pp_address
)) {
220 if (send_queue_size_
>= kMaxSendBufferSize
) {
224 send_queue_
.push_back(PendingPacket(data
, data_size
, pp_address
));
225 send_queue_size_
+= data_size
;
230 int UdpPacketSocket::Close() {
231 state_
= STATE_CLOSED
;
236 talk_base::AsyncPacketSocket::State
UdpPacketSocket::GetState() const {
240 int UdpPacketSocket::GetOption(talk_base::Socket::Option opt
, int* value
) {
241 // Options are not supported for Pepper UDP sockets.
245 int UdpPacketSocket::SetOption(talk_base::Socket::Option opt
, int value
) {
246 // Options are not supported for Pepper UDP sockets.
250 int UdpPacketSocket::GetError() const {
254 void UdpPacketSocket::SetError(int error
) {
258 void UdpPacketSocket::DoSend() {
259 if (send_pending_
|| send_queue_
.empty())
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
279 send_pending_
= false;
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
295 // TODO(sergeyu): Once implementation of the Pepper UDP interface
296 // is fixed, uncomment the code below, but ignore
297 // host-unreacheable error.
303 send_queue_size_
-= send_queue_
.front().data
->size();
304 send_queue_
.pop_front();
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
);
324 void UdpPacketSocket::HandleReadResult(int result
) {
326 PP_NetAddress_Private pp_address
;
327 if (!socket_
.GetRecvFromAddress(&pp_address
)) {
328 LOG(ERROR
) << "GetRecvFromAddress() failed after successfull RecvFrom().";
331 talk_base::SocketAddress address
;
332 if (!PpAddressToSocketAddress(pp_address
, &address
)) {
333 LOG(ERROR
) << "Failed to covert address received from RecvFrom().";
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
;
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
,
356 scoped_ptr
<UdpPacketSocket
> result(new UdpPacketSocket(pp_instance_
));
357 if (!result
->Init(local_address
, min_port
, max_port
))
359 return result
.release();
362 talk_base::AsyncPacketSocket
* PepperPacketSocketFactory::CreateServerTcpSocket(
363 const talk_base::SocketAddress
& local_address
,
367 // We don't use TCP sockets for remoting connections.
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
,
378 // We don't use TCP sockets for remoting connections.
383 } // namespace remoting