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.
4
5 #include "remoting/client/plugin/pepper_packet_socket_factory.h"
6
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "net/base/io_buffer.h"
10 #include "ppapi/cpp/net_address.h"
11 #include "ppapi/cpp/udp_socket.h"
12 #include "ppapi/utility/completion_callback_factory.h"
13 #include "remoting/client/plugin/pepper_util.h"
14 #include "third_party/libjingle/source/talk/base/asyncpacketsocket.h"
15
16 namespace remoting {
17
18 namespace {
19
20 // Size of the buffer to allocate for RecvFrom().
21 const int kReceiveBufferSize = 65536;
22
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;
28
29 class UdpPacketSocket : public talk_base::AsyncPacketSocket {
30 public:
31 explicit UdpPacketSocket(const pp::InstanceHandle& instance);
32 virtual ~UdpPacketSocket();
33
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);
39
40 // talk_base::AsyncPacketSocket interface.
41 virtual talk_base::SocketAddress GetLocalAddress() const OVERRIDE;
42 virtual talk_base::SocketAddress GetRemoteAddress() const OVERRIDE;
43 virtual int Send(const void* data, size_t data_size,
44 talk_base::DiffServCodePoint dscp) OVERRIDE;
45 virtual int SendTo(const void* data,
46 size_t data_size,
47 const talk_base::SocketAddress& address,
48 talk_base::DiffServCodePoint dscp) OVERRIDE;
49 virtual int Close() OVERRIDE;
50 virtual State GetState() const OVERRIDE;
51 virtual int GetOption(talk_base::Socket::Option opt, int* value) OVERRIDE;
52 virtual int SetOption(talk_base::Socket::Option opt, int value) OVERRIDE;
53 virtual int GetError() const OVERRIDE;
54 virtual void SetError(int error) OVERRIDE;
55
56 private:
57 struct PendingPacket {
58 PendingPacket(const void* buffer,
59 int buffer_size,
60 const pp::NetAddress& address);
61
62 scoped_refptr<net::IOBufferWithSize> data;
63 pp::NetAddress address;
64 };
65
66 void OnBindCompleted(int error);
67
68 void DoSend();
69 void OnSendCompleted(int result);
70
71 void DoRead();
72 void OnReadCompleted(int result, pp::NetAddress address);
73 void HandleReadResult(int result, pp::NetAddress address);
74
75 pp::InstanceHandle instance_;
76
77 pp::UDPSocket socket_;
78
79 State state_;
80 int error_;
81
82 talk_base::SocketAddress local_address_;
83
84 // Used to scan ports when necessary. Both values are set to 0 when
85 // the port number is assigned by OS.
86 uint16_t min_port_;
87 uint16_t max_port_;
88
89 std::vector<char> receive_buffer_;
90
91 bool send_pending_;
92 std::list<PendingPacket> send_queue_;
93 int send_queue_size_;
94
95 pp::CompletionCallbackFactory<UdpPacketSocket> callback_factory_;
96
97 DISALLOW_COPY_AND_ASSIGN(UdpPacketSocket);
98 };
99
PendingPacket(const void * buffer,int buffer_size,const pp::NetAddress & address)100 UdpPacketSocket::PendingPacket::PendingPacket(
101 const void* buffer,
102 int buffer_size,
103 const pp::NetAddress& address)
104 : data(new net::IOBufferWithSize(buffer_size)),
105 address(address) {
106 memcpy(data->data(), buffer, buffer_size);
107 }
108
UdpPacketSocket(const pp::InstanceHandle & instance)109 UdpPacketSocket::UdpPacketSocket(const pp::InstanceHandle& instance)
110 : instance_(instance),
111 socket_(instance),
112 state_(STATE_CLOSED),
113 error_(0),
114 min_port_(0),
115 max_port_(0),
116 send_pending_(false),
117 send_queue_size_(0),
118 callback_factory_(this) {
119 }
120
~UdpPacketSocket()121 UdpPacketSocket::~UdpPacketSocket() {
122 Close();
123 }
124
Init(const talk_base::SocketAddress & local_address,int min_port,int max_port)125 bool UdpPacketSocket::Init(const talk_base::SocketAddress& local_address,
126 int min_port,
127 int max_port) {
128 if (socket_.is_null()) {
129 return false;
130 }
131
132 local_address_ = local_address;
133 max_port_ = max_port;
134 min_port_ = min_port;
135
136 pp::NetAddress pp_local_address;
137 if (!SocketAddressToPpNetAddressWithPort(
138 instance_, local_address_, &pp_local_address, min_port_)) {
139 return false;
140 }
141
142 pp::CompletionCallback callback =
143 callback_factory_.NewCallback(&UdpPacketSocket::OnBindCompleted);
144 int result = socket_.Bind(pp_local_address, callback);
145 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING);
146 state_ = STATE_BINDING;
147
148 return true;
149 }
150
OnBindCompleted(int result)151 void UdpPacketSocket::OnBindCompleted(int result) {
152 DCHECK(state_ == STATE_BINDING || state_ == STATE_CLOSED);
153
154 if (result == PP_ERROR_ABORTED) {
155 // Socket is being destroyed while binding.
156 return;
157 }
158
159 if (result == PP_OK) {
160 pp::NetAddress address = socket_.GetBoundAddress();
161 PpNetAddressToSocketAddress(address, &local_address_);
162 state_ = STATE_BOUND;
163 SignalAddressReady(this, local_address_);
164 DoRead();
165 return;
166 }
167
168 if (min_port_ < max_port_) {
169 // Try to bind to the next available port.
170 ++min_port_;
171 pp::NetAddress pp_local_address;
172 if (SocketAddressToPpNetAddressWithPort(
173 instance_, local_address_, &pp_local_address, min_port_)) {
174 pp::CompletionCallback callback =
175 callback_factory_.NewCallback(&UdpPacketSocket::OnBindCompleted);
176 int result = socket_.Bind(pp_local_address, callback);
177 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING);
178 }
179 } else {
180 LOG(ERROR) << "Failed to bind UDP socket: " << result;
181 }
182 }
183
GetLocalAddress() const184 talk_base::SocketAddress UdpPacketSocket::GetLocalAddress() const {
185 DCHECK_EQ(state_, STATE_BOUND);
186 return local_address_;
187 }
188
GetRemoteAddress() const189 talk_base::SocketAddress UdpPacketSocket::GetRemoteAddress() const {
190 // UDP sockets are not connected - this method should never be called.
191 NOTREACHED();
192 return talk_base::SocketAddress();
193 }
194
Send(const void * data,size_t data_size,talk_base::DiffServCodePoint dscp)195 int UdpPacketSocket::Send(const void* data, size_t data_size,
196 talk_base::DiffServCodePoint dscp) {
197 // UDP sockets are not connected - this method should never be called.
198 NOTREACHED();
199 return EWOULDBLOCK;
200 }
201
SendTo(const void * data,size_t data_size,const talk_base::SocketAddress & address,talk_base::DiffServCodePoint dscp)202 int UdpPacketSocket::SendTo(const void* data,
203 size_t data_size,
204 const talk_base::SocketAddress& address,
205 talk_base::DiffServCodePoint dscp) {
206 if (state_ != STATE_BOUND) {
207 // TODO(sergeyu): StunPort may try to send stun request before we
208 // are bound. Fix that problem and change this to DCHECK.
209 return EINVAL;
210 }
211
212 if (error_ != 0) {
213 return error_;
214 }
215
216 pp::NetAddress pp_address;
217 if (!SocketAddressToPpNetAddress(instance_, address, &pp_address)) {
218 return EINVAL;
219 }
220
221 if (send_queue_size_ >= kMaxSendBufferSize) {
222 return EWOULDBLOCK;
223 }
224
225 send_queue_.push_back(PendingPacket(data, data_size, pp_address));
226 send_queue_size_ += data_size;
227 DoSend();
228 return data_size;
229 }
230
Close()231 int UdpPacketSocket::Close() {
232 state_ = STATE_CLOSED;
233 socket_.Close();
234 return 0;
235 }
236
GetState() const237 talk_base::AsyncPacketSocket::State UdpPacketSocket::GetState() const {
238 return state_;
239 }
240
GetOption(talk_base::Socket::Option opt,int * value)241 int UdpPacketSocket::GetOption(talk_base::Socket::Option opt, int* value) {
242 // Options are not supported for Pepper UDP sockets.
243 return -1;
244 }
245
SetOption(talk_base::Socket::Option opt,int value)246 int UdpPacketSocket::SetOption(talk_base::Socket::Option opt, int value) {
247 // Options are not supported for Pepper UDP sockets.
248 return -1;
249 }
250
GetError() const251 int UdpPacketSocket::GetError() const {
252 return error_;
253 }
254
SetError(int error)255 void UdpPacketSocket::SetError(int error) {
256 error_ = error;
257 }
258
DoSend()259 void UdpPacketSocket::DoSend() {
260 if (send_pending_ || send_queue_.empty())
261 return;
262
263 pp::CompletionCallback callback =
264 callback_factory_.NewCallback(&UdpPacketSocket::OnSendCompleted);
265 int result = socket_.SendTo(
266 send_queue_.front().data->data(), send_queue_.front().data->size(),
267 send_queue_.front().address,
268 callback);
269 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING);
270 send_pending_ = true;
271 }
272
OnSendCompleted(int result)273 void UdpPacketSocket::OnSendCompleted(int result) {
274 if (result == PP_ERROR_ABORTED) {
275 // Send is aborted when the socket is being destroyed.
276 // |send_queue_| may be already destroyed, it's not safe to access
277 // it here.
278 return;
279 }
280
281 send_pending_ = false;
282
283 if (result < 0) {
284 LOG(ERROR) << "Send failed on a UDP socket: " << result;
285
286 // OS (e.g. OSX) may return EHOSTUNREACH when the peer has the
287 // same subnet address as the local host but connected to a
288 // different network. That error must be ingored because the
289 // socket may still be useful for other ICE canidadates (e.g. for
290 // STUN candidates with a different address). Unfortunately pepper
291 // interface currently returns PP_ERROR_FAILED for any error (see
292 // crbug.com/136406). It's not possible to distinguish that case
293 // from other errors and so we have to ingore all of them. This
294 // behavior matchers the libjingle's AsyncUDPSocket used by the
295 // host.
296 //
297 // TODO(sergeyu): Once implementation of the Pepper UDP interface
298 // is fixed, uncomment the code below, but ignore
299 // host-unreacheable error.
300
301 // error_ = EINVAL;
302 // return;
303 }
304
305 send_queue_size_ -= send_queue_.front().data->size();
306 send_queue_.pop_front();
307 DoSend();
308 }
309
DoRead()310 void UdpPacketSocket::DoRead() {
311 receive_buffer_.resize(kReceiveBufferSize);
312 pp::CompletionCallbackWithOutput<pp::NetAddress> callback =
313 callback_factory_.NewCallbackWithOutput(
314 &UdpPacketSocket::OnReadCompleted);
315 int result =
316 socket_.RecvFrom(&receive_buffer_[0], receive_buffer_.size(), callback);
317 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING);
318 }
319
OnReadCompleted(int result,pp::NetAddress address)320 void UdpPacketSocket::OnReadCompleted(int result, pp::NetAddress address) {
321 HandleReadResult(result, address);
322 if (result > 0) {
323 DoRead();
324 }
325 }
326
HandleReadResult(int result,pp::NetAddress address)327 void UdpPacketSocket::HandleReadResult(int result, pp::NetAddress address) {
328 if (result > 0) {
329 talk_base::SocketAddress socket_address;
330 PpNetAddressToSocketAddress(address, &socket_address);
331 SignalReadPacket(this, &receive_buffer_[0], result, socket_address,
332 talk_base::CreatePacketTime(0));
333 } else if (result != PP_ERROR_ABORTED) {
334 LOG(ERROR) << "Received error when reading from UDP socket: " << result;
335 }
336 }
337
338 } // namespace
339
PepperPacketSocketFactory(const pp::InstanceHandle & instance)340 PepperPacketSocketFactory::PepperPacketSocketFactory(
341 const pp::InstanceHandle& instance)
342 : pp_instance_(instance) {
343 }
344
~PepperPacketSocketFactory()345 PepperPacketSocketFactory::~PepperPacketSocketFactory() {
346 }
347
CreateUdpSocket(const talk_base::SocketAddress & local_address,int min_port,int max_port)348 talk_base::AsyncPacketSocket* PepperPacketSocketFactory::CreateUdpSocket(
349 const talk_base::SocketAddress& local_address,
350 int min_port,
351 int max_port) {
352 scoped_ptr<UdpPacketSocket> result(new UdpPacketSocket(pp_instance_));
353 if (!result->Init(local_address, min_port, max_port))
354 return NULL;
355 return result.release();
356 }
357
CreateServerTcpSocket(const talk_base::SocketAddress & local_address,int min_port,int max_port,int opts)358 talk_base::AsyncPacketSocket* PepperPacketSocketFactory::CreateServerTcpSocket(
359 const talk_base::SocketAddress& local_address,
360 int min_port,
361 int max_port,
362 int opts) {
363 // We don't use TCP sockets for remoting connections.
364 NOTREACHED();
365 return NULL;
366 }
367
CreateClientTcpSocket(const talk_base::SocketAddress & local_address,const talk_base::SocketAddress & remote_address,const talk_base::ProxyInfo & proxy_info,const std::string & user_agent,int opts)368 talk_base::AsyncPacketSocket* PepperPacketSocketFactory::CreateClientTcpSocket(
369 const talk_base::SocketAddress& local_address,
370 const talk_base::SocketAddress& remote_address,
371 const talk_base::ProxyInfo& proxy_info,
372 const std::string& user_agent,
373 int opts) {
374 // We don't use TCP sockets for remoting connections.
375 NOTREACHED();
376 return NULL;
377 }
378
379 talk_base::AsyncResolverInterface*
CreateAsyncResolver()380 PepperPacketSocketFactory::CreateAsyncResolver() {
381 NOTREACHED();
382 return NULL;
383 }
384
385 } // namespace remoting
386