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