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