1// Copyright 2014 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/protocol/chromium_socket_factory.h"
6
7#include "base/bind.h"
8#include "base/logging.h"
9#include "base/memory/scoped_ptr.h"
10#include "jingle/glue/utils.h"
11#include "net/base/io_buffer.h"
12#include "net/base/ip_endpoint.h"
13#include "net/base/net_errors.h"
14#include "net/udp/udp_server_socket.h"
15#include "remoting/protocol/socket_util.h"
16#include "third_party/webrtc/base/asyncpacketsocket.h"
17#include "third_party/webrtc/base/nethelpers.h"
18
19namespace remoting {
20namespace protocol {
21
22namespace {
23
24// Size of the buffer to allocate for RecvFrom().
25const int kReceiveBufferSize = 65536;
26
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.
31const int kMaxSendBufferSize = 256 * 1024;
32
33class UdpPacketSocket : public rtc::AsyncPacketSocket {
34 public:
35  UdpPacketSocket();
36  virtual ~UdpPacketSocket();
37
38  bool Init(const rtc::SocketAddress& local_address,
39            int min_port, int max_port);
40
41  // rtc::AsyncPacketSocket interface.
42  virtual rtc::SocketAddress GetLocalAddress() const OVERRIDE;
43  virtual rtc::SocketAddress GetRemoteAddress() const OVERRIDE;
44  virtual int Send(const void* data, size_t data_size,
45                   const rtc::PacketOptions& options) OVERRIDE;
46  virtual int SendTo(const void* data, size_t data_size,
47                     const rtc::SocketAddress& address,
48                     const rtc::PacketOptions& options) OVERRIDE;
49  virtual int Close() OVERRIDE;
50  virtual State GetState() const OVERRIDE;
51  virtual int GetOption(rtc::Socket::Option option, int* value) OVERRIDE;
52  virtual int SetOption(rtc::Socket::Option option, 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 net::IPEndPoint& address);
61
62    scoped_refptr<net::IOBufferWithSize> data;
63    net::IPEndPoint address;
64    bool retried;
65  };
66
67  void OnBindCompleted(int error);
68
69  void DoSend();
70  void OnSendCompleted(int result);
71
72  void DoRead();
73  void OnReadCompleted(int result);
74  void HandleReadResult(int result);
75
76  scoped_ptr<net::UDPServerSocket> socket_;
77
78  State state_;
79  int error_;
80
81  rtc::SocketAddress local_address_;
82
83  // Receive buffer and address are populated by asynchronous reads.
84  scoped_refptr<net::IOBuffer> receive_buffer_;
85  net::IPEndPoint receive_address_;
86
87  bool send_pending_;
88  std::list<PendingPacket> send_queue_;
89  int send_queue_size_;
90
91  DISALLOW_COPY_AND_ASSIGN(UdpPacketSocket);
92};
93
94UdpPacketSocket::PendingPacket::PendingPacket(
95    const void* buffer,
96    int buffer_size,
97    const net::IPEndPoint& address)
98    : data(new net::IOBufferWithSize(buffer_size)),
99      address(address),
100      retried(false) {
101  memcpy(data->data(), buffer, buffer_size);
102}
103
104UdpPacketSocket::UdpPacketSocket()
105    : state_(STATE_CLOSED),
106      error_(0),
107      send_pending_(false),
108      send_queue_size_(0) {
109}
110
111UdpPacketSocket::~UdpPacketSocket() {
112  Close();
113}
114
115bool UdpPacketSocket::Init(const rtc::SocketAddress& local_address,
116                           int min_port, int max_port) {
117  net::IPEndPoint local_endpoint;
118  if (!jingle_glue::SocketAddressToIPEndPoint(
119          local_address, &local_endpoint)) {
120    return false;
121  }
122
123  for (int port = min_port; port <= max_port; ++port) {
124    socket_.reset(new net::UDPServerSocket(NULL, net::NetLog::Source()));
125    int result = socket_->Listen(
126        net::IPEndPoint(local_endpoint.address(), port));
127    if (result == net::OK) {
128      break;
129    } else {
130      socket_.reset();
131    }
132  }
133
134  if (!socket_.get()) {
135    // Failed to bind the socket.
136    return false;
137  }
138
139  if (socket_->GetLocalAddress(&local_endpoint) != net::OK ||
140      !jingle_glue::IPEndPointToSocketAddress(local_endpoint,
141                                              &local_address_)) {
142    return false;
143  }
144
145  state_ = STATE_BOUND;
146  DoRead();
147
148  return true;
149}
150
151rtc::SocketAddress UdpPacketSocket::GetLocalAddress() const {
152  DCHECK_EQ(state_, STATE_BOUND);
153  return local_address_;
154}
155
156rtc::SocketAddress UdpPacketSocket::GetRemoteAddress() const {
157  // UDP sockets are not connected - this method should never be called.
158  NOTREACHED();
159  return rtc::SocketAddress();
160}
161
162int UdpPacketSocket::Send(const void* data, size_t data_size,
163                          const rtc::PacketOptions& options) {
164  // UDP sockets are not connected - this method should never be called.
165  NOTREACHED();
166  return EWOULDBLOCK;
167}
168
169int UdpPacketSocket::SendTo(const void* data, size_t data_size,
170                            const rtc::SocketAddress& address,
171                            const rtc::PacketOptions& options) {
172  if (state_ != STATE_BOUND) {
173    NOTREACHED();
174    return EINVAL;
175  }
176
177  if (error_ != 0) {
178    return error_;
179  }
180
181  net::IPEndPoint endpoint;
182  if (!jingle_glue::SocketAddressToIPEndPoint(address, &endpoint)) {
183    return EINVAL;
184  }
185
186  if (send_queue_size_ >= kMaxSendBufferSize) {
187    return EWOULDBLOCK;
188  }
189
190  send_queue_.push_back(PendingPacket(data, data_size, endpoint));
191  send_queue_size_ += data_size;
192
193  DoSend();
194  return data_size;
195}
196
197int UdpPacketSocket::Close() {
198  state_ = STATE_CLOSED;
199  socket_.reset();
200  return 0;
201}
202
203rtc::AsyncPacketSocket::State UdpPacketSocket::GetState() const {
204  return state_;
205}
206
207int UdpPacketSocket::GetOption(rtc::Socket::Option option, int* value) {
208  // This method is never called by libjingle.
209  NOTIMPLEMENTED();
210  return -1;
211}
212
213int UdpPacketSocket::SetOption(rtc::Socket::Option option, int value) {
214  if (state_ != STATE_BOUND) {
215    NOTREACHED();
216    return EINVAL;
217  }
218
219  switch (option) {
220    case rtc::Socket::OPT_DONTFRAGMENT:
221      NOTIMPLEMENTED();
222      return -1;
223
224    case rtc::Socket::OPT_RCVBUF: {
225      int net_error = socket_->SetReceiveBufferSize(value);
226      return (net_error == net::OK) ? 0 : -1;
227    }
228
229    case rtc::Socket::OPT_SNDBUF: {
230      int net_error = socket_->SetSendBufferSize(value);
231      return (net_error == net::OK) ? 0 : -1;
232    }
233
234    case rtc::Socket::OPT_NODELAY:
235      // OPT_NODELAY is only for TCP sockets.
236      NOTREACHED();
237      return -1;
238
239    case rtc::Socket::OPT_IPV6_V6ONLY:
240      NOTIMPLEMENTED();
241      return -1;
242
243    case rtc::Socket::OPT_DSCP:
244      NOTIMPLEMENTED();
245      return -1;
246
247    case rtc::Socket::OPT_RTP_SENDTIME_EXTN_ID:
248      NOTIMPLEMENTED();
249      return -1;
250  }
251
252  NOTREACHED();
253  return -1;
254}
255
256int UdpPacketSocket::GetError() const {
257  return error_;
258}
259
260void UdpPacketSocket::SetError(int error) {
261  error_ = error;
262}
263
264void UdpPacketSocket::DoSend() {
265  if (send_pending_ || send_queue_.empty())
266    return;
267
268  PendingPacket& packet = send_queue_.front();
269  int result = socket_->SendTo(
270      packet.data.get(),
271      packet.data->size(),
272      packet.address,
273      base::Bind(&UdpPacketSocket::OnSendCompleted, base::Unretained(this)));
274  if (result == net::ERR_IO_PENDING) {
275    send_pending_ = true;
276  } else {
277    OnSendCompleted(result);
278  }
279}
280
281void UdpPacketSocket::OnSendCompleted(int result) {
282  send_pending_ = false;
283
284  if (result < 0) {
285    SocketErrorAction action = GetSocketErrorAction(result);
286    switch (action) {
287      case SOCKET_ERROR_ACTION_FAIL:
288        LOG(ERROR) << "Send failed on a UDP socket: " << result;
289        error_ = EINVAL;
290        return;
291
292      case SOCKET_ERROR_ACTION_RETRY:
293        // Retry resending only once.
294        if (!send_queue_.front().retried) {
295          send_queue_.front().retried = true;
296          DoSend();
297          return;
298        }
299        break;
300
301      case SOCKET_ERROR_ACTION_IGNORE:
302        break;
303    }
304  }
305
306  // Don't need to worry about partial sends because this is a datagram
307  // socket.
308  send_queue_size_ -= send_queue_.front().data->size();
309  send_queue_.pop_front();
310  DoSend();
311}
312
313void UdpPacketSocket::DoRead() {
314  int result = 0;
315  while (result >= 0) {
316    receive_buffer_ = new net::IOBuffer(kReceiveBufferSize);
317    result = socket_->RecvFrom(
318        receive_buffer_.get(),
319        kReceiveBufferSize,
320        &receive_address_,
321        base::Bind(&UdpPacketSocket::OnReadCompleted, base::Unretained(this)));
322    HandleReadResult(result);
323  }
324}
325
326void UdpPacketSocket::OnReadCompleted(int result) {
327  HandleReadResult(result);
328  if (result >= 0) {
329    DoRead();
330  }
331}
332
333void UdpPacketSocket::HandleReadResult(int result) {
334  if (result == net::ERR_IO_PENDING) {
335    return;
336  }
337
338  if (result > 0) {
339    rtc::SocketAddress address;
340    if (!jingle_glue::IPEndPointToSocketAddress(receive_address_, &address)) {
341      NOTREACHED();
342      LOG(ERROR) << "Failed to convert address received from RecvFrom().";
343      return;
344    }
345    SignalReadPacket(this, receive_buffer_->data(), result, address,
346                     rtc::CreatePacketTime(0));
347  } else {
348    LOG(ERROR) << "Received error when reading from UDP socket: " << result;
349  }
350}
351
352}  // namespace
353
354ChromiumPacketSocketFactory::ChromiumPacketSocketFactory() {
355}
356
357ChromiumPacketSocketFactory::~ChromiumPacketSocketFactory() {
358}
359
360rtc::AsyncPacketSocket* ChromiumPacketSocketFactory::CreateUdpSocket(
361      const rtc::SocketAddress& local_address,
362      int min_port, int max_port) {
363  scoped_ptr<UdpPacketSocket> result(new UdpPacketSocket());
364  if (!result->Init(local_address, min_port, max_port))
365    return NULL;
366  return result.release();
367}
368
369rtc::AsyncPacketSocket*
370ChromiumPacketSocketFactory::CreateServerTcpSocket(
371    const rtc::SocketAddress& local_address,
372    int min_port, int max_port,
373    int opts) {
374  // We don't use TCP sockets for remoting connections.
375  NOTIMPLEMENTED();
376  return NULL;
377}
378
379rtc::AsyncPacketSocket*
380ChromiumPacketSocketFactory::CreateClientTcpSocket(
381      const rtc::SocketAddress& local_address,
382      const rtc::SocketAddress& remote_address,
383      const rtc::ProxyInfo& proxy_info,
384      const std::string& user_agent,
385      int opts) {
386  // We don't use TCP sockets for remoting connections.
387  NOTREACHED();
388  return NULL;
389}
390
391rtc::AsyncResolverInterface*
392ChromiumPacketSocketFactory::CreateAsyncResolver() {
393  return new rtc::AsyncResolver();
394}
395
396}  // namespace protocol
397}  // namespace remoting
398