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 virtual ~UdpPacketSocket();
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 virtual rtc::SocketAddress GetLocalAddress() const OVERRIDE;
99 virtual rtc::SocketAddress GetRemoteAddress() const OVERRIDE;
100 virtual int Send(const void* data, size_t data_size,
101 const rtc::PacketOptions& options) OVERRIDE;
102 virtual int SendTo(const void* data,
104 const rtc::SocketAddress& address,
105 const rtc::PacketOptions& options) OVERRIDE;
106 virtual int Close() OVERRIDE;
107 virtual State GetState() const OVERRIDE;
108 virtual int GetOption(rtc::Socket::Option opt, int* value) OVERRIDE;
109 virtual int SetOption(rtc::Socket::Option opt, int value) OVERRIDE;
110 virtual int GetError() const OVERRIDE;
111 virtual void SetError(int error) OVERRIDE;
114 struct PendingPacket {
115 PendingPacket(const void* buffer,
117 const pp::NetAddress& address);
119 scoped_refptr<net::IOBufferWithSize> data;
120 pp::NetAddress address;
124 void OnBindCompleted(int error);
127 void OnSendCompleted(int result);
130 void OnReadCompleted(int result, pp::NetAddress address);
131 void HandleReadResult(int result, pp::NetAddress address);
133 pp::InstanceHandle instance_;
135 pp::UDPSocket socket_;
140 rtc::SocketAddress local_address_;
142 // Used to scan ports when necessary. Both values are set to 0 when
143 // the port number is assigned by OS.
147 std::vector<char> receive_buffer_;
150 std::list<PendingPacket> send_queue_;
151 int send_queue_size_;
153 pp::CompletionCallbackFactory<UdpPacketSocket> callback_factory_;
155 DISALLOW_COPY_AND_ASSIGN(UdpPacketSocket);
158 UdpPacketSocket::PendingPacket::PendingPacket(
161 const pp::NetAddress& address)
162 : data(new net::IOBufferWithSize(buffer_size)),
165 memcpy(data->data(), buffer, buffer_size);
168 UdpPacketSocket::UdpPacketSocket(const pp::InstanceHandle& instance)
169 : instance_(instance),
171 state_(STATE_CLOSED),
175 send_pending_(false),
177 callback_factory_(this) {
180 UdpPacketSocket::~UdpPacketSocket() {
184 bool UdpPacketSocket::Init(const rtc::SocketAddress& local_address,
187 if (socket_.is_null()) {
191 local_address_ = local_address;
192 max_port_ = max_port;
193 min_port_ = min_port;
195 pp::NetAddress pp_local_address;
196 if (!SocketAddressToPpNetAddressWithPort(
197 instance_, local_address_, &pp_local_address, min_port_)) {
201 pp::CompletionCallback callback =
202 callback_factory_.NewCallback(&UdpPacketSocket::OnBindCompleted);
203 int result = socket_.Bind(pp_local_address, callback);
204 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING);
205 state_ = STATE_BINDING;
210 void UdpPacketSocket::OnBindCompleted(int result) {
211 DCHECK(state_ == STATE_BINDING || state_ == STATE_CLOSED);
213 if (result == PP_ERROR_ABORTED) {
214 // Socket is being destroyed while binding.
218 if (result == PP_OK) {
219 pp::NetAddress address = socket_.GetBoundAddress();
220 PpNetAddressToSocketAddress(address, &local_address_);
221 state_ = STATE_BOUND;
222 SignalAddressReady(this, local_address_);
227 if (min_port_ < max_port_) {
228 // Try to bind to the next available port.
230 pp::NetAddress pp_local_address;
231 if (SocketAddressToPpNetAddressWithPort(
232 instance_, local_address_, &pp_local_address, min_port_)) {
233 pp::CompletionCallback callback =
234 callback_factory_.NewCallback(&UdpPacketSocket::OnBindCompleted);
235 int result = socket_.Bind(pp_local_address, callback);
236 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING);
239 LOG(ERROR) << "Failed to bind UDP socket to " << local_address_.ToString()
240 << ", error: " << result;
244 rtc::SocketAddress UdpPacketSocket::GetLocalAddress() const {
245 DCHECK_EQ(state_, STATE_BOUND);
246 return local_address_;
249 rtc::SocketAddress UdpPacketSocket::GetRemoteAddress() const {
250 // UDP sockets are not connected - this method should never be called.
252 return rtc::SocketAddress();
255 int UdpPacketSocket::Send(const void* data, size_t data_size,
256 const rtc::PacketOptions& options) {
257 // UDP sockets are not connected - this method should never be called.
262 int UdpPacketSocket::SendTo(const void* data,
264 const rtc::SocketAddress& address,
265 const rtc::PacketOptions& options) {
266 if (state_ != STATE_BOUND) {
267 // TODO(sergeyu): StunPort may try to send stun request before we
268 // are bound. Fix that problem and change this to DCHECK.
276 pp::NetAddress pp_address;
277 if (!SocketAddressToPpNetAddress(instance_, address, &pp_address)) {
281 if (send_queue_size_ >= kMaxSendBufferSize) {
285 send_queue_.push_back(PendingPacket(data, data_size, pp_address));
286 send_queue_size_ += data_size;
291 int UdpPacketSocket::Close() {
292 state_ = STATE_CLOSED;
297 rtc::AsyncPacketSocket::State UdpPacketSocket::GetState() const {
301 int UdpPacketSocket::GetOption(rtc::Socket::Option opt, int* value) {
302 // Options are not supported for Pepper UDP sockets.
306 int UdpPacketSocket::SetOption(rtc::Socket::Option opt, int value) {
307 // Options are not supported for Pepper UDP sockets.
311 int UdpPacketSocket::GetError() const {
315 void UdpPacketSocket::SetError(int error) {
319 void UdpPacketSocket::DoSend() {
320 if (send_pending_ || send_queue_.empty())
323 pp::CompletionCallback callback =
324 callback_factory_.NewCallback(&UdpPacketSocket::OnSendCompleted);
325 int result = socket_.SendTo(
326 send_queue_.front().data->data(), send_queue_.front().data->size(),
327 send_queue_.front().address,
329 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING);
330 send_pending_ = true;
333 void UdpPacketSocket::OnSendCompleted(int result) {
334 if (result == PP_ERROR_ABORTED) {
335 // Send is aborted when the socket is being destroyed.
336 // |send_queue_| may be already destroyed, it's not safe to access
341 send_pending_ = false;
344 int net_error = PepperErrorToNetError(result);
345 SocketErrorAction action = GetSocketErrorAction(net_error);
347 case SOCKET_ERROR_ACTION_FAIL:
348 LOG(ERROR) << "Send failed on a UDP socket: " << result;
352 case SOCKET_ERROR_ACTION_RETRY:
353 // Retry resending only once.
354 if (!send_queue_.front().retried) {
355 send_queue_.front().retried = true;
361 case SOCKET_ERROR_ACTION_IGNORE:
366 send_queue_size_ -= send_queue_.front().data->size();
367 send_queue_.pop_front();
371 void UdpPacketSocket::DoRead() {
372 receive_buffer_.resize(kReceiveBufferSize);
373 pp::CompletionCallbackWithOutput<pp::NetAddress> callback =
374 callback_factory_.NewCallbackWithOutput(
375 &UdpPacketSocket::OnReadCompleted);
377 socket_.RecvFrom(&receive_buffer_[0], receive_buffer_.size(), callback);
378 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING);
381 void UdpPacketSocket::OnReadCompleted(int result, pp::NetAddress address) {
382 HandleReadResult(result, address);
388 void UdpPacketSocket::HandleReadResult(int result, pp::NetAddress address) {
390 rtc::SocketAddress socket_address;
391 PpNetAddressToSocketAddress(address, &socket_address);
392 SignalReadPacket(this, &receive_buffer_[0], result, socket_address,
393 rtc::CreatePacketTime(0));
394 } else if (result != PP_ERROR_ABORTED) {
395 LOG(ERROR) << "Received error when reading from UDP socket: " << result;
401 PepperPacketSocketFactory::PepperPacketSocketFactory(
402 const pp::InstanceHandle& instance)
403 : pp_instance_(instance) {
406 PepperPacketSocketFactory::~PepperPacketSocketFactory() {
409 rtc::AsyncPacketSocket* PepperPacketSocketFactory::CreateUdpSocket(
410 const rtc::SocketAddress& local_address,
413 scoped_ptr<UdpPacketSocket> result(new UdpPacketSocket(pp_instance_));
414 if (!result->Init(local_address, min_port, max_port))
416 return result.release();
419 rtc::AsyncPacketSocket* PepperPacketSocketFactory::CreateServerTcpSocket(
420 const rtc::SocketAddress& local_address,
424 // We don't use TCP sockets for remoting connections.
429 rtc::AsyncPacketSocket* PepperPacketSocketFactory::CreateClientTcpSocket(
430 const rtc::SocketAddress& local_address,
431 const rtc::SocketAddress& remote_address,
432 const rtc::ProxyInfo& proxy_info,
433 const std::string& user_agent,
435 // We don't use TCP sockets for remoting connections.
440 rtc::AsyncResolverInterface*
441 PepperPacketSocketFactory::CreateAsyncResolver() {
442 return new PepperAddressResolver(pp_instance_);
445 } // namespace remoting