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