pepper_packet_socket_factory.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
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 "net/base/net_errors.h" 11#include "ppapi/cpp/net_address.h" 12#include "ppapi/cpp/udp_socket.h" 13#include "ppapi/utility/completion_callback_factory.h" 14#include "remoting/client/plugin/pepper_util.h" 15#include "remoting/jingle_glue/socket_util.h" 16#include "third_party/libjingle/source/talk/base/asyncpacketsocket.h" 17 18namespace remoting { 19 20namespace { 21 22// Size of the buffer to allocate for RecvFrom(). 23const 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. 29const int kMaxSendBufferSize = 256 * 1024; 30 31int PepperErrorToNetError(int error) { 32 switch (error) { 33 case PP_OK: 34 return net::OK; 35 case PP_OK_COMPLETIONPENDING: 36 return net::ERR_IO_PENDING; 37 case PP_ERROR_ABORTED: 38 return net::ERR_ABORTED; 39 case PP_ERROR_BADARGUMENT: 40 return net::ERR_INVALID_ARGUMENT; 41 case PP_ERROR_FILENOTFOUND: 42 return net::ERR_FILE_NOT_FOUND; 43 case PP_ERROR_TIMEDOUT: 44 return net::ERR_TIMED_OUT; 45 case PP_ERROR_FILETOOBIG: 46 return net::ERR_FILE_TOO_BIG; 47 case PP_ERROR_NOTSUPPORTED: 48 return net::ERR_NOT_IMPLEMENTED; 49 case PP_ERROR_NOMEMORY: 50 return net::ERR_OUT_OF_MEMORY; 51 case PP_ERROR_FILEEXISTS: 52 return net::ERR_FILE_EXISTS; 53 case PP_ERROR_NOSPACE: 54 return net::ERR_FILE_NO_SPACE; 55 case PP_ERROR_CONNECTION_CLOSED: 56 return net::ERR_CONNECTION_CLOSED; 57 case PP_ERROR_CONNECTION_RESET: 58 return net::ERR_CONNECTION_RESET; 59 case PP_ERROR_CONNECTION_REFUSED: 60 return net::ERR_CONNECTION_REFUSED; 61 case PP_ERROR_CONNECTION_ABORTED: 62 return net::ERR_CONNECTION_ABORTED; 63 case PP_ERROR_CONNECTION_FAILED: 64 return net::ERR_CONNECTION_FAILED; 65 case PP_ERROR_NAME_NOT_RESOLVED: 66 return net::ERR_NAME_NOT_RESOLVED; 67 case PP_ERROR_ADDRESS_INVALID: 68 return net::ERR_ADDRESS_INVALID; 69 case PP_ERROR_ADDRESS_UNREACHABLE: 70 return net::ERR_ADDRESS_UNREACHABLE; 71 case PP_ERROR_CONNECTION_TIMEDOUT: 72 return net::ERR_CONNECTION_TIMED_OUT; 73 case PP_ERROR_NOACCESS: 74 return net::ERR_NETWORK_ACCESS_DENIED; 75 case PP_ERROR_MESSAGE_TOO_BIG: 76 return net::ERR_MSG_TOO_BIG; 77 case PP_ERROR_ADDRESS_IN_USE: 78 return net::ERR_ADDRESS_IN_USE; 79 default: 80 return net::ERR_FAILED; 81 } 82} 83 84class UdpPacketSocket : public talk_base::AsyncPacketSocket { 85 public: 86 explicit UdpPacketSocket(const pp::InstanceHandle& instance); 87 virtual ~UdpPacketSocket(); 88 89 // |min_port| and |max_port| are set to zero if the port number 90 // should be assigned by the OS. 91 bool Init(const talk_base::SocketAddress& local_address, 92 int min_port, 93 int max_port); 94 95 // talk_base::AsyncPacketSocket interface. 96 virtual talk_base::SocketAddress GetLocalAddress() const OVERRIDE; 97 virtual talk_base::SocketAddress GetRemoteAddress() const OVERRIDE; 98 virtual int Send(const void* data, size_t data_size, 99 const talk_base::PacketOptions& options) OVERRIDE; 100 virtual int SendTo(const void* data, 101 size_t data_size, 102 const talk_base::SocketAddress& address, 103 const talk_base::PacketOptions& options) OVERRIDE; 104 virtual int Close() OVERRIDE; 105 virtual State GetState() const OVERRIDE; 106 virtual int GetOption(talk_base::Socket::Option opt, int* value) OVERRIDE; 107 virtual int SetOption(talk_base::Socket::Option opt, int value) OVERRIDE; 108 virtual int GetError() const OVERRIDE; 109 virtual void SetError(int error) OVERRIDE; 110 111 private: 112 struct PendingPacket { 113 PendingPacket(const void* buffer, 114 int buffer_size, 115 const pp::NetAddress& address); 116 117 scoped_refptr<net::IOBufferWithSize> data; 118 pp::NetAddress address; 119 bool retried; 120 }; 121 122 void OnBindCompleted(int error); 123 124 void DoSend(); 125 void OnSendCompleted(int result); 126 127 void DoRead(); 128 void OnReadCompleted(int result, pp::NetAddress address); 129 void HandleReadResult(int result, pp::NetAddress address); 130 131 pp::InstanceHandle instance_; 132 133 pp::UDPSocket socket_; 134 135 State state_; 136 int error_; 137 138 talk_base::SocketAddress local_address_; 139 140 // Used to scan ports when necessary. Both values are set to 0 when 141 // the port number is assigned by OS. 142 uint16_t min_port_; 143 uint16_t max_port_; 144 145 std::vector<char> receive_buffer_; 146 147 bool send_pending_; 148 std::list<PendingPacket> send_queue_; 149 int send_queue_size_; 150 151 pp::CompletionCallbackFactory<UdpPacketSocket> callback_factory_; 152 153 DISALLOW_COPY_AND_ASSIGN(UdpPacketSocket); 154}; 155 156UdpPacketSocket::PendingPacket::PendingPacket( 157 const void* buffer, 158 int buffer_size, 159 const pp::NetAddress& address) 160 : data(new net::IOBufferWithSize(buffer_size)), 161 address(address), 162 retried(true) { 163 memcpy(data->data(), buffer, buffer_size); 164} 165 166UdpPacketSocket::UdpPacketSocket(const pp::InstanceHandle& instance) 167 : instance_(instance), 168 socket_(instance), 169 state_(STATE_CLOSED), 170 error_(0), 171 min_port_(0), 172 max_port_(0), 173 send_pending_(false), 174 send_queue_size_(0), 175 callback_factory_(this) { 176} 177 178UdpPacketSocket::~UdpPacketSocket() { 179 Close(); 180} 181 182bool UdpPacketSocket::Init(const talk_base::SocketAddress& local_address, 183 int min_port, 184 int max_port) { 185 if (socket_.is_null()) { 186 return false; 187 } 188 189 local_address_ = local_address; 190 max_port_ = max_port; 191 min_port_ = min_port; 192 193 pp::NetAddress pp_local_address; 194 if (!SocketAddressToPpNetAddressWithPort( 195 instance_, local_address_, &pp_local_address, min_port_)) { 196 return false; 197 } 198 199 pp::CompletionCallback callback = 200 callback_factory_.NewCallback(&UdpPacketSocket::OnBindCompleted); 201 int result = socket_.Bind(pp_local_address, callback); 202 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING); 203 state_ = STATE_BINDING; 204 205 return true; 206} 207 208void UdpPacketSocket::OnBindCompleted(int result) { 209 DCHECK(state_ == STATE_BINDING || state_ == STATE_CLOSED); 210 211 if (result == PP_ERROR_ABORTED) { 212 // Socket is being destroyed while binding. 213 return; 214 } 215 216 if (result == PP_OK) { 217 pp::NetAddress address = socket_.GetBoundAddress(); 218 PpNetAddressToSocketAddress(address, &local_address_); 219 state_ = STATE_BOUND; 220 SignalAddressReady(this, local_address_); 221 DoRead(); 222 return; 223 } 224 225 if (min_port_ < max_port_) { 226 // Try to bind to the next available port. 227 ++min_port_; 228 pp::NetAddress pp_local_address; 229 if (SocketAddressToPpNetAddressWithPort( 230 instance_, local_address_, &pp_local_address, min_port_)) { 231 pp::CompletionCallback callback = 232 callback_factory_.NewCallback(&UdpPacketSocket::OnBindCompleted); 233 int result = socket_.Bind(pp_local_address, callback); 234 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING); 235 } 236 } else { 237 LOG(ERROR) << "Failed to bind UDP socket to " << local_address_.ToString() 238 << ", error: " << result; 239 } 240} 241 242talk_base::SocketAddress UdpPacketSocket::GetLocalAddress() const { 243 DCHECK_EQ(state_, STATE_BOUND); 244 return local_address_; 245} 246 247talk_base::SocketAddress UdpPacketSocket::GetRemoteAddress() const { 248 // UDP sockets are not connected - this method should never be called. 249 NOTREACHED(); 250 return talk_base::SocketAddress(); 251} 252 253int UdpPacketSocket::Send(const void* data, size_t data_size, 254 const talk_base::PacketOptions& options) { 255 // UDP sockets are not connected - this method should never be called. 256 NOTREACHED(); 257 return EWOULDBLOCK; 258} 259 260int UdpPacketSocket::SendTo(const void* data, 261 size_t data_size, 262 const talk_base::SocketAddress& address, 263 const talk_base::PacketOptions& options) { 264 if (state_ != STATE_BOUND) { 265 // TODO(sergeyu): StunPort may try to send stun request before we 266 // are bound. Fix that problem and change this to DCHECK. 267 return EINVAL; 268 } 269 270 if (error_ != 0) { 271 return error_; 272 } 273 274 pp::NetAddress pp_address; 275 if (!SocketAddressToPpNetAddress(instance_, address, &pp_address)) { 276 return EINVAL; 277 } 278 279 if (send_queue_size_ >= kMaxSendBufferSize) { 280 return EWOULDBLOCK; 281 } 282 283 send_queue_.push_back(PendingPacket(data, data_size, pp_address)); 284 send_queue_size_ += data_size; 285 DoSend(); 286 return data_size; 287} 288 289int UdpPacketSocket::Close() { 290 state_ = STATE_CLOSED; 291 socket_.Close(); 292 return 0; 293} 294 295talk_base::AsyncPacketSocket::State UdpPacketSocket::GetState() const { 296 return state_; 297} 298 299int UdpPacketSocket::GetOption(talk_base::Socket::Option opt, int* value) { 300 // Options are not supported for Pepper UDP sockets. 301 return -1; 302} 303 304int UdpPacketSocket::SetOption(talk_base::Socket::Option opt, int value) { 305 // Options are not supported for Pepper UDP sockets. 306 return -1; 307} 308 309int UdpPacketSocket::GetError() const { 310 return error_; 311} 312 313void UdpPacketSocket::SetError(int error) { 314 error_ = error; 315} 316 317void UdpPacketSocket::DoSend() { 318 if (send_pending_ || send_queue_.empty()) 319 return; 320 321 pp::CompletionCallback callback = 322 callback_factory_.NewCallback(&UdpPacketSocket::OnSendCompleted); 323 int result = socket_.SendTo( 324 send_queue_.front().data->data(), send_queue_.front().data->size(), 325 send_queue_.front().address, 326 callback); 327 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING); 328 send_pending_ = true; 329} 330 331void UdpPacketSocket::OnSendCompleted(int result) { 332 if (result == PP_ERROR_ABORTED) { 333 // Send is aborted when the socket is being destroyed. 334 // |send_queue_| may be already destroyed, it's not safe to access 335 // it here. 336 return; 337 } 338 339 send_pending_ = false; 340 341 if (result < 0) { 342 int net_error = PepperErrorToNetError(result); 343 SocketErrorAction action = GetSocketErrorAction(net_error); 344 switch (action) { 345 case SOCKET_ERROR_ACTION_FAIL: 346 LOG(ERROR) << "Send failed on a UDP socket: " << result; 347 error_ = EINVAL; 348 return; 349 350 case SOCKET_ERROR_ACTION_RETRY: 351 // Retry resending only once. 352 if (!send_queue_.front().retried) { 353 send_queue_.front().retried = true; 354 DoSend(); 355 return; 356 } 357 break; 358 359 case SOCKET_ERROR_ACTION_IGNORE: 360 break; 361 } 362 } 363 364 send_queue_size_ -= send_queue_.front().data->size(); 365 send_queue_.pop_front(); 366 DoSend(); 367} 368 369void UdpPacketSocket::DoRead() { 370 receive_buffer_.resize(kReceiveBufferSize); 371 pp::CompletionCallbackWithOutput<pp::NetAddress> callback = 372 callback_factory_.NewCallbackWithOutput( 373 &UdpPacketSocket::OnReadCompleted); 374 int result = 375 socket_.RecvFrom(&receive_buffer_[0], receive_buffer_.size(), callback); 376 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING); 377} 378 379void UdpPacketSocket::OnReadCompleted(int result, pp::NetAddress address) { 380 HandleReadResult(result, address); 381 if (result > 0) { 382 DoRead(); 383 } 384} 385 386void UdpPacketSocket::HandleReadResult(int result, pp::NetAddress address) { 387 if (result > 0) { 388 talk_base::SocketAddress socket_address; 389 PpNetAddressToSocketAddress(address, &socket_address); 390 SignalReadPacket(this, &receive_buffer_[0], result, socket_address, 391 talk_base::CreatePacketTime(0)); 392 } else if (result != PP_ERROR_ABORTED) { 393 LOG(ERROR) << "Received error when reading from UDP socket: " << result; 394 } 395} 396 397} // namespace 398 399PepperPacketSocketFactory::PepperPacketSocketFactory( 400 const pp::InstanceHandle& instance) 401 : pp_instance_(instance) { 402} 403 404PepperPacketSocketFactory::~PepperPacketSocketFactory() { 405} 406 407talk_base::AsyncPacketSocket* PepperPacketSocketFactory::CreateUdpSocket( 408 const talk_base::SocketAddress& local_address, 409 int min_port, 410 int max_port) { 411 scoped_ptr<UdpPacketSocket> result(new UdpPacketSocket(pp_instance_)); 412 if (!result->Init(local_address, min_port, max_port)) 413 return NULL; 414 return result.release(); 415} 416 417talk_base::AsyncPacketSocket* PepperPacketSocketFactory::CreateServerTcpSocket( 418 const talk_base::SocketAddress& local_address, 419 int min_port, 420 int max_port, 421 int opts) { 422 // We don't use TCP sockets for remoting connections. 423 NOTREACHED(); 424 return NULL; 425} 426 427talk_base::AsyncPacketSocket* PepperPacketSocketFactory::CreateClientTcpSocket( 428 const talk_base::SocketAddress& local_address, 429 const talk_base::SocketAddress& remote_address, 430 const talk_base::ProxyInfo& proxy_info, 431 const std::string& user_agent, 432 int opts) { 433 // We don't use TCP sockets for remoting connections. 434 NOTREACHED(); 435 return NULL; 436} 437 438talk_base::AsyncResolverInterface* 439PepperPacketSocketFactory::CreateAsyncResolver() { 440 NOTREACHED(); 441 return NULL; 442} 443 444} // namespace remoting 445