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