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 "net/base/io_buffer.h"
10 #include "net/base/net_errors.h"
11 #include "ppapi/cpp/net_address.h"
12 #include "ppapi/cpp/udp_socket.h"
13 #include "ppapi/utility/completion_callback_factory.h"
14 #include "remoting/client/plugin/pepper_util.h"
15 #include "remoting/protocol/socket_util.h"
16 #include "third_party/libjingle/source/talk/base/asyncpacketsocket.h"
22 // Size of the buffer to allocate for RecvFrom().
23 const int kReceiveBufferSize
= 65536;
25 // Maximum amount of data in the send buffers. This is necessary to
26 // prevent out-of-memory crashes if the caller sends data faster than
27 // Pepper's UDP API can handle it. This maximum should never be
28 // reached under normal conditions.
29 const int kMaxSendBufferSize
= 256 * 1024;
31 int PepperErrorToNetError(int error
) {
35 case PP_OK_COMPLETIONPENDING
:
36 return net::ERR_IO_PENDING
;
37 case PP_ERROR_ABORTED
:
38 return net::ERR_ABORTED
;
39 case PP_ERROR_BADARGUMENT
:
40 return net::ERR_INVALID_ARGUMENT
;
41 case PP_ERROR_FILENOTFOUND
:
42 return net::ERR_FILE_NOT_FOUND
;
43 case PP_ERROR_TIMEDOUT
:
44 return net::ERR_TIMED_OUT
;
45 case PP_ERROR_FILETOOBIG
:
46 return net::ERR_FILE_TOO_BIG
;
47 case PP_ERROR_NOTSUPPORTED
:
48 return net::ERR_NOT_IMPLEMENTED
;
49 case PP_ERROR_NOMEMORY
:
50 return net::ERR_OUT_OF_MEMORY
;
51 case PP_ERROR_FILEEXISTS
:
52 return net::ERR_FILE_EXISTS
;
53 case PP_ERROR_NOSPACE
:
54 return net::ERR_FILE_NO_SPACE
;
55 case PP_ERROR_CONNECTION_CLOSED
:
56 return net::ERR_CONNECTION_CLOSED
;
57 case PP_ERROR_CONNECTION_RESET
:
58 return net::ERR_CONNECTION_RESET
;
59 case PP_ERROR_CONNECTION_REFUSED
:
60 return net::ERR_CONNECTION_REFUSED
;
61 case PP_ERROR_CONNECTION_ABORTED
:
62 return net::ERR_CONNECTION_ABORTED
;
63 case PP_ERROR_CONNECTION_FAILED
:
64 return net::ERR_CONNECTION_FAILED
;
65 case PP_ERROR_NAME_NOT_RESOLVED
:
66 return net::ERR_NAME_NOT_RESOLVED
;
67 case PP_ERROR_ADDRESS_INVALID
:
68 return net::ERR_ADDRESS_INVALID
;
69 case PP_ERROR_ADDRESS_UNREACHABLE
:
70 return net::ERR_ADDRESS_UNREACHABLE
;
71 case PP_ERROR_CONNECTION_TIMEDOUT
:
72 return net::ERR_CONNECTION_TIMED_OUT
;
73 case PP_ERROR_NOACCESS
:
74 return net::ERR_NETWORK_ACCESS_DENIED
;
75 case PP_ERROR_MESSAGE_TOO_BIG
:
76 return net::ERR_MSG_TOO_BIG
;
77 case PP_ERROR_ADDRESS_IN_USE
:
78 return net::ERR_ADDRESS_IN_USE
;
80 return net::ERR_FAILED
;
84 class UdpPacketSocket
: public talk_base::AsyncPacketSocket
{
86 explicit UdpPacketSocket(const pp::InstanceHandle
& instance
);
87 virtual ~UdpPacketSocket();
89 // |min_port| and |max_port| are set to zero if the port number
90 // should be assigned by the OS.
91 bool Init(const talk_base::SocketAddress
& local_address
,
95 // talk_base::AsyncPacketSocket interface.
96 virtual talk_base::SocketAddress
GetLocalAddress() const OVERRIDE
;
97 virtual talk_base::SocketAddress
GetRemoteAddress() const OVERRIDE
;
98 virtual int Send(const void* data
, size_t data_size
,
99 const talk_base::PacketOptions
& options
) OVERRIDE
;
100 virtual int SendTo(const void* data
,
102 const talk_base::SocketAddress
& address
,
103 const talk_base::PacketOptions
& options
) OVERRIDE
;
104 virtual int Close() OVERRIDE
;
105 virtual State
GetState() const OVERRIDE
;
106 virtual int GetOption(talk_base::Socket::Option opt
, int* value
) OVERRIDE
;
107 virtual int SetOption(talk_base::Socket::Option opt
, int value
) OVERRIDE
;
108 virtual int GetError() const OVERRIDE
;
109 virtual void SetError(int error
) OVERRIDE
;
112 struct PendingPacket
{
113 PendingPacket(const void* buffer
,
115 const pp::NetAddress
& address
);
117 scoped_refptr
<net::IOBufferWithSize
> data
;
118 pp::NetAddress address
;
122 void OnBindCompleted(int error
);
125 void OnSendCompleted(int result
);
128 void OnReadCompleted(int result
, pp::NetAddress address
);
129 void HandleReadResult(int result
, pp::NetAddress address
);
131 pp::InstanceHandle instance_
;
133 pp::UDPSocket socket_
;
138 talk_base::SocketAddress local_address_
;
140 // Used to scan ports when necessary. Both values are set to 0 when
141 // the port number is assigned by OS.
145 std::vector
<char> receive_buffer_
;
148 std::list
<PendingPacket
> send_queue_
;
149 int send_queue_size_
;
151 pp::CompletionCallbackFactory
<UdpPacketSocket
> callback_factory_
;
153 DISALLOW_COPY_AND_ASSIGN(UdpPacketSocket
);
156 UdpPacketSocket::PendingPacket::PendingPacket(
159 const pp::NetAddress
& address
)
160 : data(new net::IOBufferWithSize(buffer_size
)),
163 memcpy(data
->data(), buffer
, buffer_size
);
166 UdpPacketSocket::UdpPacketSocket(const pp::InstanceHandle
& instance
)
167 : instance_(instance
),
169 state_(STATE_CLOSED
),
173 send_pending_(false),
175 callback_factory_(this) {
178 UdpPacketSocket::~UdpPacketSocket() {
182 bool UdpPacketSocket::Init(const talk_base::SocketAddress
& local_address
,
185 if (socket_
.is_null()) {
189 local_address_
= local_address
;
190 max_port_
= max_port
;
191 min_port_
= min_port
;
193 pp::NetAddress pp_local_address
;
194 if (!SocketAddressToPpNetAddressWithPort(
195 instance_
, local_address_
, &pp_local_address
, min_port_
)) {
199 pp::CompletionCallback callback
=
200 callback_factory_
.NewCallback(&UdpPacketSocket::OnBindCompleted
);
201 int result
= socket_
.Bind(pp_local_address
, callback
);
202 DCHECK_EQ(result
, PP_OK_COMPLETIONPENDING
);
203 state_
= STATE_BINDING
;
208 void UdpPacketSocket::OnBindCompleted(int result
) {
209 DCHECK(state_
== STATE_BINDING
|| state_
== STATE_CLOSED
);
211 if (result
== PP_ERROR_ABORTED
) {
212 // Socket is being destroyed while binding.
216 if (result
== PP_OK
) {
217 pp::NetAddress address
= socket_
.GetBoundAddress();
218 PpNetAddressToSocketAddress(address
, &local_address_
);
219 state_
= STATE_BOUND
;
220 SignalAddressReady(this, local_address_
);
225 if (min_port_
< max_port_
) {
226 // Try to bind to the next available port.
228 pp::NetAddress pp_local_address
;
229 if (SocketAddressToPpNetAddressWithPort(
230 instance_
, local_address_
, &pp_local_address
, min_port_
)) {
231 pp::CompletionCallback callback
=
232 callback_factory_
.NewCallback(&UdpPacketSocket::OnBindCompleted
);
233 int result
= socket_
.Bind(pp_local_address
, callback
);
234 DCHECK_EQ(result
, PP_OK_COMPLETIONPENDING
);
237 LOG(ERROR
) << "Failed to bind UDP socket to " << local_address_
.ToString()
238 << ", error: " << result
;
242 talk_base::SocketAddress
UdpPacketSocket::GetLocalAddress() const {
243 DCHECK_EQ(state_
, STATE_BOUND
);
244 return local_address_
;
247 talk_base::SocketAddress
UdpPacketSocket::GetRemoteAddress() const {
248 // UDP sockets are not connected - this method should never be called.
250 return talk_base::SocketAddress();
253 int UdpPacketSocket::Send(const void* data
, size_t data_size
,
254 const talk_base::PacketOptions
& options
) {
255 // UDP sockets are not connected - this method should never be called.
260 int UdpPacketSocket::SendTo(const void* data
,
262 const talk_base::SocketAddress
& address
,
263 const talk_base::PacketOptions
& options
) {
264 if (state_
!= STATE_BOUND
) {
265 // TODO(sergeyu): StunPort may try to send stun request before we
266 // are bound. Fix that problem and change this to DCHECK.
274 pp::NetAddress pp_address
;
275 if (!SocketAddressToPpNetAddress(instance_
, address
, &pp_address
)) {
279 if (send_queue_size_
>= kMaxSendBufferSize
) {
283 send_queue_
.push_back(PendingPacket(data
, data_size
, pp_address
));
284 send_queue_size_
+= data_size
;
289 int UdpPacketSocket::Close() {
290 state_
= STATE_CLOSED
;
295 talk_base::AsyncPacketSocket::State
UdpPacketSocket::GetState() const {
299 int UdpPacketSocket::GetOption(talk_base::Socket::Option opt
, int* value
) {
300 // Options are not supported for Pepper UDP sockets.
304 int UdpPacketSocket::SetOption(talk_base::Socket::Option opt
, int value
) {
305 // Options are not supported for Pepper UDP sockets.
309 int UdpPacketSocket::GetError() const {
313 void UdpPacketSocket::SetError(int error
) {
317 void UdpPacketSocket::DoSend() {
318 if (send_pending_
|| send_queue_
.empty())
321 pp::CompletionCallback callback
=
322 callback_factory_
.NewCallback(&UdpPacketSocket::OnSendCompleted
);
323 int result
= socket_
.SendTo(
324 send_queue_
.front().data
->data(), send_queue_
.front().data
->size(),
325 send_queue_
.front().address
,
327 DCHECK_EQ(result
, PP_OK_COMPLETIONPENDING
);
328 send_pending_
= true;
331 void UdpPacketSocket::OnSendCompleted(int result
) {
332 if (result
== PP_ERROR_ABORTED
) {
333 // Send is aborted when the socket is being destroyed.
334 // |send_queue_| may be already destroyed, it's not safe to access
339 send_pending_
= false;
342 int net_error
= PepperErrorToNetError(result
);
343 SocketErrorAction action
= GetSocketErrorAction(net_error
);
345 case SOCKET_ERROR_ACTION_FAIL
:
346 LOG(ERROR
) << "Send failed on a UDP socket: " << result
;
350 case SOCKET_ERROR_ACTION_RETRY
:
351 // Retry resending only once.
352 if (!send_queue_
.front().retried
) {
353 send_queue_
.front().retried
= true;
359 case SOCKET_ERROR_ACTION_IGNORE
:
364 send_queue_size_
-= send_queue_
.front().data
->size();
365 send_queue_
.pop_front();
369 void UdpPacketSocket::DoRead() {
370 receive_buffer_
.resize(kReceiveBufferSize
);
371 pp::CompletionCallbackWithOutput
<pp::NetAddress
> callback
=
372 callback_factory_
.NewCallbackWithOutput(
373 &UdpPacketSocket::OnReadCompleted
);
375 socket_
.RecvFrom(&receive_buffer_
[0], receive_buffer_
.size(), callback
);
376 DCHECK_EQ(result
, PP_OK_COMPLETIONPENDING
);
379 void UdpPacketSocket::OnReadCompleted(int result
, pp::NetAddress address
) {
380 HandleReadResult(result
, address
);
386 void UdpPacketSocket::HandleReadResult(int result
, pp::NetAddress address
) {
388 talk_base::SocketAddress socket_address
;
389 PpNetAddressToSocketAddress(address
, &socket_address
);
390 SignalReadPacket(this, &receive_buffer_
[0], result
, socket_address
,
391 talk_base::CreatePacketTime(0));
392 } else if (result
!= PP_ERROR_ABORTED
) {
393 LOG(ERROR
) << "Received error when reading from UDP socket: " << result
;
399 PepperPacketSocketFactory::PepperPacketSocketFactory(
400 const pp::InstanceHandle
& instance
)
401 : pp_instance_(instance
) {
404 PepperPacketSocketFactory::~PepperPacketSocketFactory() {
407 talk_base::AsyncPacketSocket
* PepperPacketSocketFactory::CreateUdpSocket(
408 const talk_base::SocketAddress
& local_address
,
411 scoped_ptr
<UdpPacketSocket
> result(new UdpPacketSocket(pp_instance_
));
412 if (!result
->Init(local_address
, min_port
, max_port
))
414 return result
.release();
417 talk_base::AsyncPacketSocket
* PepperPacketSocketFactory::CreateServerTcpSocket(
418 const talk_base::SocketAddress
& local_address
,
422 // We don't use TCP sockets for remoting connections.
427 talk_base::AsyncPacketSocket
* PepperPacketSocketFactory::CreateClientTcpSocket(
428 const talk_base::SocketAddress
& local_address
,
429 const talk_base::SocketAddress
& remote_address
,
430 const talk_base::ProxyInfo
& proxy_info
,
431 const std::string
& user_agent
,
433 // We don't use TCP sockets for remoting connections.
438 talk_base::AsyncResolverInterface
*
439 PepperPacketSocketFactory::CreateAsyncResolver() {
444 } // namespace remoting