OLD | NEW |
(Empty) | |
| 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/private/net_address_private.h" |
| 11 #include "ppapi/cpp/private/udp_socket_private.h" |
| 12 #include "remoting/client/plugin/pepper_util.h" |
| 13 #include "third_party/libjingle/source/talk/base/asyncpacketsocket.h" |
| 14 |
| 15 namespace remoting { |
| 16 |
| 17 namespace { |
| 18 |
| 19 // Size of the buffer to allocate for RecvFrom(). |
| 20 const int kReceiveBufferSize = 65536; |
| 21 |
| 22 // Maximum amount of data in the send buffers. This is necessary to |
| 23 // prevent out-of-memory crashes if the caller sends data faster than |
| 24 // Pepper's UDP API can handle it. This maximum should never be |
| 25 // reached under normal conditions. |
| 26 const int kMaxSendBufferSize = 256 * 1024; |
| 27 |
| 28 class UdpPacketSocket : public talk_base::AsyncPacketSocket { |
| 29 public: |
| 30 explicit UdpPacketSocket(const pp::InstanceHandle& instance); |
| 31 virtual ~UdpPacketSocket(); |
| 32 |
| 33 // |min_port| and |max_port| are set to zero if the port number |
| 34 // |should be assigned by the OS. |
| 35 bool Init(const talk_base::SocketAddress& local_address, |
| 36 int min_port, |
| 37 int max_port); |
| 38 |
| 39 // talk_base::AsyncPacketSocket interface. |
| 40 virtual talk_base::SocketAddress GetLocalAddress() const; |
| 41 virtual talk_base::SocketAddress GetRemoteAddress() const; |
| 42 virtual int Send(const void* data, size_t data_size); |
| 43 virtual int SendTo(const void* data, |
| 44 size_t data_size, |
| 45 const talk_base::SocketAddress& address); |
| 46 virtual int Close(); |
| 47 virtual State GetState() const; |
| 48 virtual int GetOption(talk_base::Socket::Option opt, int* value); |
| 49 virtual int SetOption(talk_base::Socket::Option opt, int value); |
| 50 virtual int GetError() const; |
| 51 virtual void SetError(int error); |
| 52 |
| 53 private: |
| 54 struct PendingPacket { |
| 55 PendingPacket(const void* buffer, |
| 56 int buffer_size, |
| 57 const PP_NetAddress_Private& address); |
| 58 |
| 59 scoped_refptr<net::IOBufferWithSize> data; |
| 60 PP_NetAddress_Private address; |
| 61 }; |
| 62 |
| 63 void OnBindCompleted(int error); |
| 64 |
| 65 void DoSend(); |
| 66 void OnSendCompleted(int result); |
| 67 |
| 68 void DoRead(); |
| 69 void OnReadCompleted(int result); |
| 70 void HandleReadResult(int result); |
| 71 |
| 72 pp::UDPSocketPrivate socket_; |
| 73 |
| 74 State state_; |
| 75 int error_; |
| 76 |
| 77 talk_base::SocketAddress local_address_; |
| 78 |
| 79 // Used to scan ports when necessary. Both values are set to 0 when |
| 80 // the port number is assigned by OS. |
| 81 uint16_t min_port_; |
| 82 uint16_t max_port_; |
| 83 |
| 84 std::vector<char> receive_buffer_; |
| 85 |
| 86 bool send_pending_; |
| 87 std::list<PendingPacket> send_queue_; |
| 88 int send_queue_size_; |
| 89 |
| 90 DISALLOW_COPY_AND_ASSIGN(UdpPacketSocket); |
| 91 }; |
| 92 |
| 93 UdpPacketSocket::PendingPacket::PendingPacket( |
| 94 const void* buffer, |
| 95 int buffer_size, |
| 96 const PP_NetAddress_Private& address) |
| 97 : data(new net::IOBufferWithSize(buffer_size)), |
| 98 address(address) { |
| 99 memcpy(data->data(), buffer, buffer_size); |
| 100 } |
| 101 |
| 102 UdpPacketSocket::UdpPacketSocket(const pp::InstanceHandle& instance) |
| 103 : socket_(instance), |
| 104 state_(STATE_CLOSED), |
| 105 error_(0), |
| 106 min_port_(0), |
| 107 max_port_(0), |
| 108 send_pending_(false), |
| 109 send_queue_size_(0) { |
| 110 } |
| 111 |
| 112 UdpPacketSocket::~UdpPacketSocket() { |
| 113 Close(); |
| 114 } |
| 115 |
| 116 bool SocketAddressToPpAddressWithPort(const talk_base::SocketAddress& address, |
| 117 PP_NetAddress_Private* pp_address, |
| 118 uint16_t port) { |
| 119 bool result = false; |
| 120 switch (address.ipaddr().family()) { |
| 121 case AF_INET: { |
| 122 in_addr addr = address.ipaddr().ipv4_address(); |
| 123 result = pp::NetAddressPrivate::CreateFromIPv4Address( |
| 124 reinterpret_cast<uint8_t*>(&addr), port, pp_address); |
| 125 break; |
| 126 } |
| 127 case AF_INET6: { |
| 128 in6_addr addr = address.ipaddr().ipv6_address(); |
| 129 result = pp::NetAddressPrivate::CreateFromIPv6Address( |
| 130 addr.s6_addr, 0, port, pp_address); |
| 131 break; |
| 132 } |
| 133 default: { |
| 134 LOG(WARNING) << "Unknown address family: " << address.ipaddr().family(); |
| 135 } |
| 136 } |
| 137 if (!result) { |
| 138 LOG(WARNING) << "Failed to convert address: " << address.ToString(); |
| 139 } |
| 140 return result; |
| 141 } |
| 142 |
| 143 bool SocketAddressToPpAddress(const talk_base::SocketAddress& address, |
| 144 PP_NetAddress_Private* pp_address) { |
| 145 return SocketAddressToPpAddressWithPort(address, pp_address, address.port()); |
| 146 } |
| 147 |
| 148 bool PpAddressToSocketAddress(const PP_NetAddress_Private& pp_address, |
| 149 talk_base::SocketAddress* address) { |
| 150 uint8_t addr_storage[16]; |
| 151 bool result = pp::NetAddressPrivate::GetAddress( |
| 152 pp_address, &addr_storage, sizeof(addr_storage)); |
| 153 |
| 154 if (result) { |
| 155 switch (pp::NetAddressPrivate::GetFamily(pp_address)) { |
| 156 case PP_NETADDRESSFAMILY_IPV4: |
| 157 address->SetIP(talk_base::IPAddress( |
| 158 *reinterpret_cast<in_addr*>(addr_storage))); |
| 159 break; |
| 160 case PP_NETADDRESSFAMILY_IPV6: |
| 161 address->SetIP(talk_base::IPAddress( |
| 162 *reinterpret_cast<in6_addr*>(addr_storage))); |
| 163 break; |
| 164 default: |
| 165 result = false; |
| 166 } |
| 167 } |
| 168 |
| 169 if (!result) { |
| 170 LOG(WARNING) << "Failed to convert address: " |
| 171 << pp::NetAddressPrivate::Describe(pp_address, true); |
| 172 } else { |
| 173 address->SetPort(pp::NetAddressPrivate::GetPort(pp_address)); |
| 174 } |
| 175 return result; |
| 176 } |
| 177 |
| 178 bool UdpPacketSocket::Init(const talk_base::SocketAddress& local_address, |
| 179 int min_port, |
| 180 int max_port) { |
| 181 if (socket_.is_null()) { |
| 182 return false; |
| 183 } |
| 184 |
| 185 local_address_ = local_address; |
| 186 max_port_ = max_port; |
| 187 min_port_ = min_port; |
| 188 |
| 189 PP_NetAddress_Private pp_local_address; |
| 190 if (!SocketAddressToPpAddressWithPort(local_address_, &pp_local_address, |
| 191 min_port_)) { |
| 192 return false; |
| 193 } |
| 194 |
| 195 int result = socket_.Bind(&pp_local_address, PpCompletionCallback( |
| 196 base::Bind(&UdpPacketSocket::OnBindCompleted, base::Unretained(this)))); |
| 197 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING); |
| 198 state_ = STATE_BINDING; |
| 199 |
| 200 return true; |
| 201 } |
| 202 |
| 203 void UdpPacketSocket::OnBindCompleted(int result) { |
| 204 DCHECK(state_ == STATE_BINDING || state_ == STATE_CLOSED); |
| 205 |
| 206 if (result == PP_ERROR_ABORTED) { |
| 207 // Socket is being destroyed while binding. |
| 208 return; |
| 209 } |
| 210 |
| 211 if (result == PP_OK) { |
| 212 PP_NetAddress_Private address; |
| 213 if (socket_.GetBoundAddress(&address)) { |
| 214 PpAddressToSocketAddress(address, &local_address_); |
| 215 } else { |
| 216 LOG(ERROR) << "Failed to get bind address for bound socket?"; |
| 217 error_ = EINVAL; |
| 218 return; |
| 219 } |
| 220 state_ = STATE_BOUND; |
| 221 SignalAddressReady(this, local_address_); |
| 222 DoRead(); |
| 223 return; |
| 224 } |
| 225 |
| 226 if (min_port_ < max_port_) { |
| 227 // Try to bind to the next available port. |
| 228 ++min_port_; |
| 229 PP_NetAddress_Private pp_local_address; |
| 230 if (SocketAddressToPpAddressWithPort(local_address_, &pp_local_address, |
| 231 min_port_)) { |
| 232 int result = socket_.Bind(&pp_local_address, PpCompletionCallback( |
| 233 base::Bind(&UdpPacketSocket::OnBindCompleted, |
| 234 base::Unretained(this)))); |
| 235 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING); |
| 236 } |
| 237 } else { |
| 238 LOG(ERROR) << "Failed to bind UDP socket: " << result; |
| 239 } |
| 240 } |
| 241 |
| 242 talk_base::SocketAddress UdpPacketSocket::GetLocalAddress() const { |
| 243 DCHECK_EQ(state_, STATE_BOUND); |
| 244 return local_address_; |
| 245 } |
| 246 |
| 247 talk_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 |
| 253 int UdpPacketSocket::Send(const void* data, size_t data_size) { |
| 254 // UDP sockets are not connected - this method should never be called. |
| 255 NOTREACHED(); |
| 256 return EWOULDBLOCK; |
| 257 } |
| 258 |
| 259 int UdpPacketSocket::SendTo(const void* data, |
| 260 size_t data_size, |
| 261 const talk_base::SocketAddress& address) { |
| 262 DCHECK_EQ(state_, STATE_BOUND); |
| 263 |
| 264 if (error_ != 0) { |
| 265 return error_; |
| 266 } |
| 267 |
| 268 PP_NetAddress_Private pp_address; |
| 269 if (!SocketAddressToPpAddress(address, &pp_address)) { |
| 270 return EINVAL; |
| 271 } |
| 272 |
| 273 if (send_queue_size_ >= kMaxSendBufferSize) { |
| 274 return EWOULDBLOCK; |
| 275 } |
| 276 |
| 277 send_queue_.push_back(PendingPacket(data, data_size, pp_address)); |
| 278 send_queue_size_ += data_size; |
| 279 DoSend(); |
| 280 return data_size; |
| 281 } |
| 282 |
| 283 int UdpPacketSocket::Close() { |
| 284 state_ = STATE_CLOSED; |
| 285 socket_.Close(); |
| 286 return 0; |
| 287 } |
| 288 |
| 289 talk_base::AsyncPacketSocket::State UdpPacketSocket::GetState() const { |
| 290 return state_; |
| 291 } |
| 292 |
| 293 int UdpPacketSocket::GetOption(talk_base::Socket::Option opt, int* value) { |
| 294 // Options are not supported for Pepper UDP sockets. |
| 295 return -1; |
| 296 } |
| 297 |
| 298 int UdpPacketSocket::SetOption(talk_base::Socket::Option opt, int value) { |
| 299 // Options are not supported for Pepper UDP sockets. |
| 300 return -1; |
| 301 } |
| 302 |
| 303 int UdpPacketSocket::GetError() const { |
| 304 return error_; |
| 305 } |
| 306 |
| 307 void UdpPacketSocket::SetError(int error) { |
| 308 error_ = error; |
| 309 } |
| 310 |
| 311 void UdpPacketSocket::DoSend() { |
| 312 if (send_pending_ || send_queue_.empty()) |
| 313 return; |
| 314 |
| 315 int result = socket_.SendTo( |
| 316 send_queue_.front().data->data(), send_queue_.front().data->size(), |
| 317 &send_queue_.front().address, |
| 318 PpCompletionCallback(base::Bind(&UdpPacketSocket::OnSendCompleted, |
| 319 base::Unretained(this)))); |
| 320 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING); |
| 321 send_pending_ = true; |
| 322 } |
| 323 |
| 324 void UdpPacketSocket::OnSendCompleted(int result) { |
| 325 send_pending_ = false; |
| 326 |
| 327 if (result < 0) { |
| 328 if (result != PP_ERROR_ABORTED) { |
| 329 LOG(ERROR) << "Send failed on a UDP socket: " << result; |
| 330 } |
| 331 error_ = EINVAL; |
| 332 return; |
| 333 } |
| 334 |
| 335 send_queue_size_ -= send_queue_.front().data->size(); |
| 336 send_queue_.pop_front(); |
| 337 DoSend(); |
| 338 } |
| 339 |
| 340 void UdpPacketSocket::DoRead() { |
| 341 receive_buffer_.resize(kReceiveBufferSize); |
| 342 int result = socket_.RecvFrom( |
| 343 &receive_buffer_[0], receive_buffer_.size(), |
| 344 PpCompletionCallback(base::Bind(&UdpPacketSocket::OnReadCompleted, |
| 345 base::Unretained(this)))); |
| 346 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING); |
| 347 } |
| 348 |
| 349 void UdpPacketSocket::OnReadCompleted(int result) { |
| 350 HandleReadResult(result); |
| 351 if (result > 0) { |
| 352 DoRead(); |
| 353 } |
| 354 } |
| 355 |
| 356 void UdpPacketSocket::HandleReadResult(int result) { |
| 357 if (result > 0) { |
| 358 PP_NetAddress_Private pp_address; |
| 359 if (!socket_.GetRecvFromAddress(&pp_address)) { |
| 360 LOG(ERROR) << "GetRecvFromAddress() failed after successfull RecvFrom()."; |
| 361 return; |
| 362 } |
| 363 talk_base::SocketAddress address; |
| 364 if (!PpAddressToSocketAddress(pp_address, &address)) { |
| 365 LOG(ERROR) << "Failed to covert address received from RecvFrom()."; |
| 366 return; |
| 367 } |
| 368 SignalReadPacket(this, &receive_buffer_[0], result, address); |
| 369 } else if (result != PP_ERROR_ABORTED) { |
| 370 LOG(ERROR) << "Received error when reading from UDP socket: " << result; |
| 371 } |
| 372 } |
| 373 |
| 374 } // namespace |
| 375 |
| 376 PepperPacketSocketFactory::PepperPacketSocketFactory( |
| 377 const pp::InstanceHandle& instance) |
| 378 : pp_instance_(instance) { |
| 379 } |
| 380 |
| 381 PepperPacketSocketFactory::~PepperPacketSocketFactory() { |
| 382 } |
| 383 |
| 384 talk_base::AsyncPacketSocket* PepperPacketSocketFactory::CreateUdpSocket( |
| 385 const talk_base::SocketAddress& local_address, |
| 386 int min_port, |
| 387 int max_port) { |
| 388 scoped_ptr<UdpPacketSocket> result(new UdpPacketSocket(pp_instance_)); |
| 389 if (!result->Init(local_address, min_port, max_port)) |
| 390 return NULL; |
| 391 return result.release(); |
| 392 } |
| 393 |
| 394 talk_base::AsyncPacketSocket* PepperPacketSocketFactory::CreateServerTcpSocket( |
| 395 const talk_base::SocketAddress& local_address, |
| 396 int min_port, |
| 397 int max_port, |
| 398 bool ssl) { |
| 399 // We don't use TCP sockets for remoting connections. |
| 400 NOTREACHED(); |
| 401 return NULL; |
| 402 } |
| 403 |
| 404 talk_base::AsyncPacketSocket* PepperPacketSocketFactory::CreateClientTcpSocket( |
| 405 const talk_base::SocketAddress& local_address, |
| 406 const talk_base::SocketAddress& remote_address, |
| 407 const talk_base::ProxyInfo& proxy_info, |
| 408 const std::string& user_agent, |
| 409 bool ssl) { |
| 410 // We don't use TCP sockets for remoting connections. |
| 411 NOTREACHED(); |
| 412 return NULL; |
| 413 } |
| 414 |
| 415 } // namespace remoting |
OLD | NEW |