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_address_resolver.h"
15 #include "remoting/client/plugin/pepper_util.h"
16 #include "remoting/protocol/socket_util.h"
17 #include "third_party/webrtc/base/asyncpacketsocket.h"
18 #include "third_party/webrtc/base/nethelpers.h"
24 // Size of the buffer to allocate for RecvFrom().
25 const int kReceiveBufferSize
= 65536;
27 // Maximum amount of data in the send buffers. This is necessary to
28 // prevent out-of-memory crashes if the caller sends data faster than
29 // Pepper's UDP API can handle it. This maximum should never be
30 // reached under normal conditions.
31 const int kMaxSendBufferSize
= 256 * 1024;
33 int PepperErrorToNetError(int error
) {
37 case PP_OK_COMPLETIONPENDING
:
38 return net::ERR_IO_PENDING
;
39 case PP_ERROR_ABORTED
:
40 return net::ERR_ABORTED
;
41 case PP_ERROR_BADARGUMENT
:
42 return net::ERR_INVALID_ARGUMENT
;
43 case PP_ERROR_FILENOTFOUND
:
44 return net::ERR_FILE_NOT_FOUND
;
45 case PP_ERROR_TIMEDOUT
:
46 return net::ERR_TIMED_OUT
;
47 case PP_ERROR_FILETOOBIG
:
48 return net::ERR_FILE_TOO_BIG
;
49 case PP_ERROR_NOTSUPPORTED
:
50 return net::ERR_NOT_IMPLEMENTED
;
51 case PP_ERROR_NOMEMORY
:
52 return net::ERR_OUT_OF_MEMORY
;
53 case PP_ERROR_FILEEXISTS
:
54 return net::ERR_FILE_EXISTS
;
55 case PP_ERROR_NOSPACE
:
56 return net::ERR_FILE_NO_SPACE
;
57 case PP_ERROR_CONNECTION_CLOSED
:
58 return net::ERR_CONNECTION_CLOSED
;
59 case PP_ERROR_CONNECTION_RESET
:
60 return net::ERR_CONNECTION_RESET
;
61 case PP_ERROR_CONNECTION_REFUSED
:
62 return net::ERR_CONNECTION_REFUSED
;
63 case PP_ERROR_CONNECTION_ABORTED
:
64 return net::ERR_CONNECTION_ABORTED
;
65 case PP_ERROR_CONNECTION_FAILED
:
66 return net::ERR_CONNECTION_FAILED
;
67 case PP_ERROR_NAME_NOT_RESOLVED
:
68 return net::ERR_NAME_NOT_RESOLVED
;
69 case PP_ERROR_ADDRESS_INVALID
:
70 return net::ERR_ADDRESS_INVALID
;
71 case PP_ERROR_ADDRESS_UNREACHABLE
:
72 return net::ERR_ADDRESS_UNREACHABLE
;
73 case PP_ERROR_CONNECTION_TIMEDOUT
:
74 return net::ERR_CONNECTION_TIMED_OUT
;
75 case PP_ERROR_NOACCESS
:
76 return net::ERR_NETWORK_ACCESS_DENIED
;
77 case PP_ERROR_MESSAGE_TOO_BIG
:
78 return net::ERR_MSG_TOO_BIG
;
79 case PP_ERROR_ADDRESS_IN_USE
:
80 return net::ERR_ADDRESS_IN_USE
;
82 return net::ERR_FAILED
;
86 class UdpPacketSocket
: public rtc::AsyncPacketSocket
{
88 explicit UdpPacketSocket(const pp::InstanceHandle
& instance
);
89 ~UdpPacketSocket() override
;
91 // |min_port| and |max_port| are set to zero if the port number
92 // should be assigned by the OS.
93 bool Init(const rtc::SocketAddress
& local_address
,
97 // rtc::AsyncPacketSocket interface.
98 rtc::SocketAddress
GetLocalAddress() const override
;
99 rtc::SocketAddress
GetRemoteAddress() const override
;
100 int Send(const void* data
,
102 const rtc::PacketOptions
& options
) override
;
103 int SendTo(const void* data
,
105 const rtc::SocketAddress
& address
,
106 const rtc::PacketOptions
& options
) override
;
107 int Close() override
;
108 State
GetState() const override
;
109 int GetOption(rtc::Socket::Option opt
, int* value
) override
;
110 int SetOption(rtc::Socket::Option opt
, int value
) override
;
111 int GetError() const override
;
112 void SetError(int error
) override
;
115 struct PendingPacket
{
116 PendingPacket(const void* buffer
,
118 const pp::NetAddress
& address
);
120 scoped_refptr
<net::IOBufferWithSize
> data
;
121 pp::NetAddress address
;
125 void OnBindCompleted(int error
);
128 void OnSendCompleted(int result
);
131 void OnReadCompleted(int result
, pp::NetAddress address
);
132 void HandleReadResult(int result
, pp::NetAddress address
);
134 pp::InstanceHandle instance_
;
136 pp::UDPSocket socket_
;
141 rtc::SocketAddress local_address_
;
143 // Used to scan ports when necessary. Both values are set to 0 when
144 // the port number is assigned by OS.
148 std::vector
<char> receive_buffer_
;
151 std::list
<PendingPacket
> send_queue_
;
152 int send_queue_size_
;
154 pp::CompletionCallbackFactory
<UdpPacketSocket
> callback_factory_
;
156 DISALLOW_COPY_AND_ASSIGN(UdpPacketSocket
);
159 UdpPacketSocket::PendingPacket::PendingPacket(
162 const pp::NetAddress
& address
)
163 : data(new net::IOBufferWithSize(buffer_size
)),
166 memcpy(data
->data(), buffer
, buffer_size
);
169 UdpPacketSocket::UdpPacketSocket(const pp::InstanceHandle
& instance
)
170 : instance_(instance
),
172 state_(STATE_CLOSED
),
176 send_pending_(false),
178 callback_factory_(this) {
181 UdpPacketSocket::~UdpPacketSocket() {
185 bool UdpPacketSocket::Init(const rtc::SocketAddress
& local_address
,
188 if (socket_
.is_null()) {
192 local_address_
= local_address
;
193 max_port_
= max_port
;
194 min_port_
= min_port
;
196 pp::NetAddress pp_local_address
;
197 if (!SocketAddressToPpNetAddressWithPort(
198 instance_
, local_address_
, &pp_local_address
, min_port_
)) {
202 pp::CompletionCallback callback
=
203 callback_factory_
.NewCallback(&UdpPacketSocket::OnBindCompleted
);
204 int result
= socket_
.Bind(pp_local_address
, callback
);
205 DCHECK_EQ(result
, PP_OK_COMPLETIONPENDING
);
206 state_
= STATE_BINDING
;
211 void UdpPacketSocket::OnBindCompleted(int result
) {
212 DCHECK(state_
== STATE_BINDING
|| state_
== STATE_CLOSED
);
214 if (result
== PP_ERROR_ABORTED
) {
215 // Socket is being destroyed while binding.
219 if (result
== PP_OK
) {
220 pp::NetAddress address
= socket_
.GetBoundAddress();
221 PpNetAddressToSocketAddress(address
, &local_address_
);
222 state_
= STATE_BOUND
;
223 SignalAddressReady(this, local_address_
);
228 if (min_port_
< max_port_
) {
229 // Try to bind to the next available port.
231 pp::NetAddress pp_local_address
;
232 if (SocketAddressToPpNetAddressWithPort(
233 instance_
, local_address_
, &pp_local_address
, min_port_
)) {
234 pp::CompletionCallback callback
=
235 callback_factory_
.NewCallback(&UdpPacketSocket::OnBindCompleted
);
236 int result
= socket_
.Bind(pp_local_address
, callback
);
237 DCHECK_EQ(result
, PP_OK_COMPLETIONPENDING
);
240 LOG(ERROR
) << "Failed to bind UDP socket to " << local_address_
.ToString()
241 << ", error: " << result
;
245 rtc::SocketAddress
UdpPacketSocket::GetLocalAddress() const {
246 DCHECK_EQ(state_
, STATE_BOUND
);
247 return local_address_
;
250 rtc::SocketAddress
UdpPacketSocket::GetRemoteAddress() const {
251 // UDP sockets are not connected - this method should never be called.
253 return rtc::SocketAddress();
256 int UdpPacketSocket::Send(const void* data
, size_t data_size
,
257 const rtc::PacketOptions
& options
) {
258 // UDP sockets are not connected - this method should never be called.
263 int UdpPacketSocket::SendTo(const void* data
,
265 const rtc::SocketAddress
& address
,
266 const rtc::PacketOptions
& options
) {
267 if (state_
!= STATE_BOUND
) {
268 // TODO(sergeyu): StunPort may try to send stun request before we
269 // are bound. Fix that problem and change this to DCHECK.
277 pp::NetAddress pp_address
;
278 if (!SocketAddressToPpNetAddress(instance_
, address
, &pp_address
)) {
282 if (send_queue_size_
>= kMaxSendBufferSize
) {
286 send_queue_
.push_back(PendingPacket(data
, data_size
, pp_address
));
287 send_queue_size_
+= data_size
;
292 int UdpPacketSocket::Close() {
293 state_
= STATE_CLOSED
;
298 rtc::AsyncPacketSocket::State
UdpPacketSocket::GetState() const {
302 int UdpPacketSocket::GetOption(rtc::Socket::Option opt
, int* value
) {
303 // Options are not supported for Pepper UDP sockets.
307 int UdpPacketSocket::SetOption(rtc::Socket::Option opt
, int value
) {
308 // Options are not supported for Pepper UDP sockets.
312 int UdpPacketSocket::GetError() const {
316 void UdpPacketSocket::SetError(int error
) {
320 void UdpPacketSocket::DoSend() {
321 if (send_pending_
|| send_queue_
.empty())
324 pp::CompletionCallback callback
=
325 callback_factory_
.NewCallback(&UdpPacketSocket::OnSendCompleted
);
326 int result
= socket_
.SendTo(
327 send_queue_
.front().data
->data(), send_queue_
.front().data
->size(),
328 send_queue_
.front().address
,
330 DCHECK_EQ(result
, PP_OK_COMPLETIONPENDING
);
331 send_pending_
= true;
334 void UdpPacketSocket::OnSendCompleted(int result
) {
335 if (result
== PP_ERROR_ABORTED
) {
336 // Send is aborted when the socket is being destroyed.
337 // |send_queue_| may be already destroyed, it's not safe to access
342 send_pending_
= false;
345 int net_error
= PepperErrorToNetError(result
);
346 SocketErrorAction action
= GetSocketErrorAction(net_error
);
348 case SOCKET_ERROR_ACTION_FAIL
:
349 LOG(ERROR
) << "Send failed on a UDP socket: " << result
;
353 case SOCKET_ERROR_ACTION_RETRY
:
354 // Retry resending only once.
355 if (!send_queue_
.front().retried
) {
356 send_queue_
.front().retried
= true;
362 case SOCKET_ERROR_ACTION_IGNORE
:
367 send_queue_size_
-= send_queue_
.front().data
->size();
368 send_queue_
.pop_front();
372 void UdpPacketSocket::DoRead() {
373 receive_buffer_
.resize(kReceiveBufferSize
);
374 pp::CompletionCallbackWithOutput
<pp::NetAddress
> callback
=
375 callback_factory_
.NewCallbackWithOutput(
376 &UdpPacketSocket::OnReadCompleted
);
378 socket_
.RecvFrom(&receive_buffer_
[0], receive_buffer_
.size(), callback
);
379 DCHECK_EQ(result
, PP_OK_COMPLETIONPENDING
);
382 void UdpPacketSocket::OnReadCompleted(int result
, pp::NetAddress address
) {
383 HandleReadResult(result
, address
);
389 void UdpPacketSocket::HandleReadResult(int result
, pp::NetAddress address
) {
391 rtc::SocketAddress socket_address
;
392 PpNetAddressToSocketAddress(address
, &socket_address
);
393 SignalReadPacket(this, &receive_buffer_
[0], result
, socket_address
,
394 rtc::CreatePacketTime(0));
395 } else if (result
!= PP_ERROR_ABORTED
) {
396 LOG(ERROR
) << "Received error when reading from UDP socket: " << result
;
402 PepperPacketSocketFactory::PepperPacketSocketFactory(
403 const pp::InstanceHandle
& instance
)
404 : pp_instance_(instance
) {
407 PepperPacketSocketFactory::~PepperPacketSocketFactory() {
410 rtc::AsyncPacketSocket
* PepperPacketSocketFactory::CreateUdpSocket(
411 const rtc::SocketAddress
& local_address
,
414 scoped_ptr
<UdpPacketSocket
> result(new UdpPacketSocket(pp_instance_
));
415 if (!result
->Init(local_address
, min_port
, max_port
))
417 return result
.release();
420 rtc::AsyncPacketSocket
* PepperPacketSocketFactory::CreateServerTcpSocket(
421 const rtc::SocketAddress
& local_address
,
425 // We don't use TCP sockets for remoting connections.
430 rtc::AsyncPacketSocket
* PepperPacketSocketFactory::CreateClientTcpSocket(
431 const rtc::SocketAddress
& local_address
,
432 const rtc::SocketAddress
& remote_address
,
433 const rtc::ProxyInfo
& proxy_info
,
434 const std::string
& user_agent
,
436 // We don't use TCP sockets for remoting connections.
441 rtc::AsyncResolverInterface
*
442 PepperPacketSocketFactory::CreateAsyncResolver() {
443 return new PepperAddressResolver(pp_instance_
);
446 } // namespace remoting