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