Added GetState, GetManagedProperties, CreateNetwork methods to WiFiService.
[chromium-blink-merge.git] / remoting / jingle_glue / chromium_socket_factory.cc
blobcc599be978ec3de4b6e1d5cc4622cb276c74117c
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/jingle_glue/chromium_socket_factory.h"
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/asyncresolverinterface.h"
18 namespace remoting {
20 namespace {
22 // Size of the buffer to allocate for RecvFrom().
23 const int kReceiveBufferSize = 65536;
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;
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;
38 // TODO(lambroslambrou): Move STUN/relay address resolution from
39 // PepperPortAllocator to this class.
40 class DummyAsyncResolver : public talk_base::AsyncResolverInterface {
41 public:
42 DummyAsyncResolver() {}
43 virtual ~DummyAsyncResolver() {}
44 virtual void Start(const talk_base::SocketAddress& addr) OVERRIDE {}
45 virtual bool GetResolvedAddress(
46 int family,
47 talk_base::SocketAddress* addr) const OVERRIDE {
48 return false;
50 virtual int GetError() const OVERRIDE {
51 return 0;
53 virtual void Destroy(bool wait) OVERRIDE {
54 delete this;
57 private:
58 DISALLOW_COPY_AND_ASSIGN(DummyAsyncResolver);
61 class UdpPacketSocket : public talk_base::AsyncPacketSocket {
62 public:
63 UdpPacketSocket();
64 virtual ~UdpPacketSocket();
66 bool Init(const talk_base::SocketAddress& local_address,
67 int min_port, int max_port);
69 // talk_base::AsyncPacketSocket interface.
70 virtual talk_base::SocketAddress GetLocalAddress() const OVERRIDE;
71 virtual talk_base::SocketAddress GetRemoteAddress() const OVERRIDE;
72 virtual int Send(const void* data, size_t data_size,
73 talk_base::DiffServCodePoint dscp) OVERRIDE;
74 virtual int SendTo(const void* data, size_t data_size,
75 const talk_base::SocketAddress& address,
76 talk_base::DiffServCodePoint dscp) OVERRIDE;
77 virtual int Close() OVERRIDE;
78 virtual State GetState() const OVERRIDE;
79 virtual int GetOption(talk_base::Socket::Option option, int* value) OVERRIDE;
80 virtual int SetOption(talk_base::Socket::Option option, int value) OVERRIDE;
81 virtual int GetError() const OVERRIDE;
82 virtual void SetError(int error) OVERRIDE;
84 private:
85 struct PendingPacket {
86 PendingPacket(const void* buffer,
87 int buffer_size,
88 const net::IPEndPoint& address);
90 scoped_refptr<net::IOBufferWithSize> data;
91 net::IPEndPoint address;
94 void OnBindCompleted(int error);
96 void DoSend();
97 void OnSendCompleted(int result);
99 void DoRead();
100 void OnReadCompleted(int result);
101 void HandleReadResult(int result);
103 scoped_ptr<net::UDPServerSocket> socket_;
105 State state_;
106 int error_;
108 talk_base::SocketAddress local_address_;
110 // Receive buffer and address are populated by asynchronous reads.
111 scoped_refptr<net::IOBuffer> receive_buffer_;
112 net::IPEndPoint receive_address_;
114 bool send_pending_;
115 std::list<PendingPacket> send_queue_;
116 int send_queue_size_;
118 DISALLOW_COPY_AND_ASSIGN(UdpPacketSocket);
121 UdpPacketSocket::PendingPacket::PendingPacket(
122 const void* buffer,
123 int buffer_size,
124 const net::IPEndPoint& address)
125 : data(new net::IOBufferWithSize(buffer_size)),
126 address(address) {
127 memcpy(data->data(), buffer, buffer_size);
130 UdpPacketSocket::UdpPacketSocket()
131 : state_(STATE_CLOSED),
132 error_(0),
133 send_pending_(false),
134 send_queue_size_(0) {
137 UdpPacketSocket::~UdpPacketSocket() {
138 Close();
141 bool UdpPacketSocket::Init(const talk_base::SocketAddress& local_address,
142 int min_port, int max_port) {
143 net::IPEndPoint local_endpoint;
144 if (!jingle_glue::SocketAddressToIPEndPoint(
145 local_address, &local_endpoint)) {
146 return false;
149 for (int port = min_port; port <= max_port; ++port) {
150 socket_.reset(new net::UDPServerSocket(NULL, net::NetLog::Source()));
151 int result = socket_->Listen(
152 net::IPEndPoint(local_endpoint.address(), port));
153 if (result == net::OK) {
154 break;
155 } else {
156 socket_.reset();
160 if (!socket_.get()) {
161 // Failed to bind the socket.
162 return false;
165 if (socket_->GetLocalAddress(&local_endpoint) != net::OK ||
166 !jingle_glue::IPEndPointToSocketAddress(local_endpoint,
167 &local_address_)) {
168 return false;
171 state_ = STATE_BOUND;
172 DoRead();
174 return true;
177 talk_base::SocketAddress UdpPacketSocket::GetLocalAddress() const {
178 DCHECK_EQ(state_, STATE_BOUND);
179 return local_address_;
182 talk_base::SocketAddress UdpPacketSocket::GetRemoteAddress() const {
183 // UDP sockets are not connected - this method should never be called.
184 NOTREACHED();
185 return talk_base::SocketAddress();
188 int UdpPacketSocket::Send(const void* data, size_t data_size,
189 talk_base::DiffServCodePoint dscp) {
190 // UDP sockets are not connected - this method should never be called.
191 NOTREACHED();
192 return EWOULDBLOCK;
195 int UdpPacketSocket::SendTo(const void* data, size_t data_size,
196 const talk_base::SocketAddress& address,
197 talk_base::DiffServCodePoint dscp) {
198 if (state_ != STATE_BOUND) {
199 NOTREACHED();
200 return EINVAL;
203 if (error_ != 0) {
204 return error_;
207 net::IPEndPoint endpoint;
208 if (!jingle_glue::SocketAddressToIPEndPoint(address, &endpoint)) {
209 return EINVAL;
212 if (send_queue_size_ >= kMaxSendBufferSize) {
213 return EWOULDBLOCK;
216 send_queue_.push_back(PendingPacket(data, data_size, endpoint));
217 send_queue_size_ += data_size;
219 DoSend();
220 return data_size;
223 int UdpPacketSocket::Close() {
224 state_ = STATE_CLOSED;
225 socket_.reset();
226 return 0;
229 talk_base::AsyncPacketSocket::State UdpPacketSocket::GetState() const {
230 return state_;
233 int UdpPacketSocket::GetOption(talk_base::Socket::Option option, int* value) {
234 // This method is never called by libjingle.
235 NOTIMPLEMENTED();
236 return -1;
239 int UdpPacketSocket::SetOption(talk_base::Socket::Option option, int value) {
240 if (state_ != STATE_BOUND) {
241 NOTREACHED();
242 return EINVAL;
245 switch (option) {
246 case talk_base::Socket::OPT_DONTFRAGMENT:
247 NOTIMPLEMENTED();
248 return -1;
250 case talk_base::Socket::OPT_RCVBUF: {
251 bool success = socket_->SetReceiveBufferSize(value);
252 return success ? 0 : -1;
255 case talk_base::Socket::OPT_SNDBUF: {
256 bool success = socket_->SetSendBufferSize(value);
257 return success ? 0 : -1;
260 case talk_base::Socket::OPT_NODELAY:
261 // OPT_NODELAY is only for TCP sockets.
262 NOTREACHED();
263 return -1;
265 case talk_base::Socket::OPT_IPV6_V6ONLY:
266 NOTIMPLEMENTED();
267 return -1;
269 case talk_base::Socket::OPT_DSCP:
270 NOTIMPLEMENTED();
271 return -1;
274 NOTREACHED();
275 return -1;
278 int UdpPacketSocket::GetError() const {
279 return error_;
282 void UdpPacketSocket::SetError(int error) {
283 error_ = error;
286 void UdpPacketSocket::DoSend() {
287 if (send_pending_ || send_queue_.empty())
288 return;
290 PendingPacket& packet = send_queue_.front();
291 int result = socket_->SendTo(
292 packet.data.get(),
293 packet.data->size(),
294 packet.address,
295 base::Bind(&UdpPacketSocket::OnSendCompleted, base::Unretained(this)));
296 if (result == net::ERR_IO_PENDING) {
297 send_pending_ = true;
298 } else {
299 OnSendCompleted(result);
303 void UdpPacketSocket::OnSendCompleted(int result) {
304 send_pending_ = false;
306 if (result < 0) {
307 if (!IsTransientError(result)) {
308 LOG(ERROR) << "Send failed on a UDP socket: " << result;
309 error_ = EINVAL;
310 return;
314 // Don't need to worry about partial sends because this is a datagram
315 // socket.
316 send_queue_size_ -= send_queue_.front().data->size();
317 send_queue_.pop_front();
318 DoSend();
321 void UdpPacketSocket::DoRead() {
322 int result = 0;
323 while (result >= 0) {
324 receive_buffer_ = new net::IOBuffer(kReceiveBufferSize);
325 result = socket_->RecvFrom(
326 receive_buffer_.get(),
327 kReceiveBufferSize,
328 &receive_address_,
329 base::Bind(&UdpPacketSocket::OnReadCompleted, base::Unretained(this)));
330 HandleReadResult(result);
334 void UdpPacketSocket::OnReadCompleted(int result) {
335 HandleReadResult(result);
336 if (result >= 0) {
337 DoRead();
341 void UdpPacketSocket::HandleReadResult(int result) {
342 if (result == net::ERR_IO_PENDING) {
343 return;
346 if (result > 0) {
347 talk_base::SocketAddress address;
348 if (!jingle_glue::IPEndPointToSocketAddress(receive_address_, &address)) {
349 NOTREACHED();
350 LOG(ERROR) << "Failed to convert address received from RecvFrom().";
351 return;
353 SignalReadPacket(this, receive_buffer_->data(), result, address);
354 } else {
355 LOG(ERROR) << "Received error when reading from UDP socket: " << result;
359 } // namespace
361 ChromiumPacketSocketFactory::ChromiumPacketSocketFactory() {
364 ChromiumPacketSocketFactory::~ChromiumPacketSocketFactory() {
367 talk_base::AsyncPacketSocket* ChromiumPacketSocketFactory::CreateUdpSocket(
368 const talk_base::SocketAddress& local_address,
369 int min_port, int max_port) {
370 scoped_ptr<UdpPacketSocket> result(new UdpPacketSocket());
371 if (!result->Init(local_address, min_port, max_port))
372 return NULL;
373 return result.release();
376 talk_base::AsyncPacketSocket*
377 ChromiumPacketSocketFactory::CreateServerTcpSocket(
378 const talk_base::SocketAddress& local_address,
379 int min_port, int max_port,
380 int opts) {
381 // We don't use TCP sockets for remoting connections.
382 NOTREACHED();
383 return NULL;
386 talk_base::AsyncPacketSocket*
387 ChromiumPacketSocketFactory::CreateClientTcpSocket(
388 const talk_base::SocketAddress& local_address,
389 const talk_base::SocketAddress& remote_address,
390 const talk_base::ProxyInfo& proxy_info,
391 const std::string& user_agent,
392 int opts) {
393 // We don't use TCP sockets for remoting connections.
394 NOTREACHED();
395 return NULL;
398 talk_base::AsyncResolverInterface*
399 ChromiumPacketSocketFactory::CreateAsyncResolver() {
400 return new DummyAsyncResolver();
403 } // namespace remoting