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