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. | |
| 23 const int kMaxSendBufferSize = 256 * 1024; | |
|
Wez
2012/04/20 21:37:07
This is a limit on the amount of user data; the li
Sergey Ulanov
2012/04/23 22:16:51
Right. I don't think it matters though. Normally t
Wez
2012/04/25 00:01:59
Right, so best to make it clear in the comment wha
Sergey Ulanov
2012/04/25 00:25:01
Done.
| |
| 24 | |
| 25 class UdpPacketSocket : public talk_base::AsyncPacketSocket { | |
| 26 public: | |
| 27 explicit UdpPacketSocket(const pp::InstanceHandle& instance); | |
| 28 virtual ~UdpPacketSocket(); | |
| 29 | |
| 30 // Always takes ownership of client even if initialization fails. | |
| 31 bool Init(const talk_base::SocketAddress& local_address, | |
| 32 int min_port, | |
| 33 int max_port); | |
| 34 | |
| 35 // talk_base::AsyncPacketSocket interface. | |
| 36 virtual talk_base::SocketAddress GetLocalAddress() const; | |
| 37 virtual talk_base::SocketAddress GetRemoteAddress() const; | |
| 38 virtual int Send(const void* data, size_t data_size); | |
| 39 virtual int SendTo(const void* data, | |
| 40 size_t data_size, | |
| 41 const talk_base::SocketAddress& address); | |
| 42 virtual int Close(); | |
| 43 virtual State GetState() const; | |
| 44 virtual int GetOption(talk_base::Socket::Option opt, int* value); | |
| 45 virtual int SetOption(talk_base::Socket::Option opt, int value); | |
| 46 virtual int GetError() const; | |
| 47 virtual void SetError(int error); | |
| 48 | |
| 49 private: | |
| 50 struct PendingPacket { | |
| 51 PendingPacket(const void* buffer, | |
| 52 int buffer_size, | |
| 53 const PP_NetAddress_Private& address); | |
| 54 | |
| 55 scoped_refptr<net::IOBufferWithSize> data; | |
| 56 PP_NetAddress_Private address; | |
| 57 }; | |
| 58 | |
| 59 void OnBindCompleted(int error); | |
| 60 | |
| 61 void DoSend(); | |
| 62 void OnSendCompleted(int result); | |
| 63 | |
| 64 void DoRead(); | |
| 65 void OnReadCompleted(int result); | |
| 66 void HandleReadResult(int result); | |
| 67 | |
| 68 pp::UDPSocketPrivate socket; | |
|
Wez
2012/04/20 21:37:07
socket -> socket_
Sergey Ulanov
2012/04/23 22:16:51
Done.
| |
| 69 | |
| 70 State state_; | |
| 71 int error_; | |
| 72 | |
| 73 talk_base::SocketAddress local_address_; | |
|
Wez
2012/04/20 21:37:07
Add a comment indicating that this is contains the
Sergey Ulanov
2012/04/23 22:16:51
Done.
| |
| 74 | |
| 75 // Used when the caller specified min_port_ and max_port_. | |
|
Wez
2012/04/20 21:37:07
Doesn't the caller always specify those? The key t
Sergey Ulanov
2012/04/23 22:16:51
Done.
| |
| 76 uint16_t current_port_; | |
|
Wez
2012/04/20 21:37:07
nit: |current_port_| sounds like it's the port to
Sergey Ulanov
2012/04/23 22:16:51
Done.
| |
| 77 uint16_t max_port_; | |
| 78 | |
| 79 std::vector<char> receive_buffer_; | |
| 80 | |
| 81 bool send_pending_; | |
| 82 std::list<PendingPacket> send_queue_; | |
| 83 int send_queue_size_; | |
| 84 | |
| 85 DISALLOW_COPY_AND_ASSIGN(UdpPacketSocket); | |
| 86 }; | |
| 87 | |
| 88 UdpPacketSocket::PendingPacket::PendingPacket( | |
| 89 const void* buffer, | |
| 90 int buffer_size, | |
| 91 const PP_NetAddress_Private& address) | |
| 92 : data(new net::IOBufferWithSize(buffer_size)), | |
| 93 address(address) { | |
| 94 memcpy(data->data(), buffer, buffer_size); | |
| 95 } | |
| 96 | |
| 97 UdpPacketSocket::UdpPacketSocket(const pp::InstanceHandle& instance) | |
| 98 : socket(instance), | |
| 99 state_(STATE_CLOSED), | |
| 100 error_(0), | |
| 101 current_port_(0), | |
| 102 max_port_(0), | |
| 103 send_pending_(false), | |
| 104 send_queue_size_(0) { | |
| 105 } | |
| 106 | |
| 107 UdpPacketSocket::~UdpPacketSocket() { | |
| 108 } | |
| 109 | |
| 110 bool SocketAddressToPpAddressWithPort(const talk_base::SocketAddress& address, | |
| 111 PP_NetAddress_Private* pp_address, | |
| 112 uint16_t port) { | |
| 113 bool result; | |
| 114 switch(address.ipaddr().family()) { | |
| 115 case AF_INET: { | |
| 116 in_addr addr = address.ipaddr().ipv4_address(); | |
| 117 result = pp::NetAddressPrivate::CreateFromIPv4Address( | |
| 118 reinterpret_cast<uint8_t*>(&addr), port, pp_address); | |
| 119 break; | |
| 120 } | |
| 121 case AF_INET6: { | |
| 122 in6_addr addr = address.ipaddr().ipv6_address(); | |
| 123 result = pp::NetAddressPrivate::CreateFromIPv6Address( | |
| 124 addr.s6_addr, 0, port, pp_address); | |
| 125 break; | |
| 126 } | |
| 127 default: { | |
| 128 LOG(WARNING) << "Unknown address family: " << address.ipaddr().family(); | |
| 129 } | |
| 130 } | |
| 131 if (!result) { | |
| 132 LOG(WARNING) << "Failed to convert address: " << address.ToString(); | |
| 133 } | |
| 134 return result; | |
| 135 } | |
| 136 | |
| 137 bool SocketAddressToPpAddress(const talk_base::SocketAddress& address, | |
| 138 PP_NetAddress_Private* pp_address) { | |
| 139 return SocketAddressToPpAddressWithPort(address, pp_address, address.port()); | |
| 140 } | |
| 141 | |
| 142 bool PpAddressToSocketAddress(const PP_NetAddress_Private& pp_address, | |
| 143 talk_base::SocketAddress* address) { | |
| 144 uint8_t addr_storage[16]; | |
| 145 bool result = pp::NetAddressPrivate::GetAddress( | |
| 146 pp_address, &addr_storage, sizeof(addr_storage)); | |
| 147 | |
| 148 if (result) { | |
| 149 switch (pp::NetAddressPrivate::GetFamily(pp_address)) { | |
| 150 case PP_NETADDRESSFAMILY_IPV4: | |
| 151 address->SetIP(talk_base::IPAddress( | |
| 152 *reinterpret_cast<in_addr*>(addr_storage))); | |
| 153 break; | |
| 154 case PP_NETADDRESSFAMILY_IPV6: | |
| 155 address->SetIP(talk_base::IPAddress( | |
| 156 *reinterpret_cast<in6_addr*>(addr_storage))); | |
| 157 break; | |
| 158 default: | |
| 159 result = false; | |
| 160 } | |
| 161 } | |
| 162 | |
| 163 if (!result) { | |
| 164 LOG(WARNING) << "Failed to convert address: " | |
| 165 << pp::NetAddressPrivate::Describe(pp_address, true); | |
| 166 } else { | |
| 167 address->SetPort(pp::NetAddressPrivate::GetPort(pp_address)); | |
| 168 } | |
| 169 return result; | |
| 170 } | |
| 171 | |
| 172 bool UdpPacketSocket::Init(const talk_base::SocketAddress& local_address, | |
| 173 int min_port, | |
| 174 int max_port) { | |
| 175 if (socket.is_null()) { | |
| 176 return false; | |
| 177 } | |
| 178 | |
| 179 local_address_ = local_address; | |
| 180 max_port_ = max_port; | |
| 181 current_port_ = min_port; | |
| 182 | |
| 183 PP_NetAddress_Private pp_local_address; | |
| 184 if (!SocketAddressToPpAddressWithPort(local_address_, &pp_local_address, | |
| 185 current_port_)) { | |
| 186 return false; | |
| 187 } | |
| 188 | |
| 189 int result = socket.Bind(&pp_local_address, PpCompletionCallback( | |
| 190 base::Bind(&UdpPacketSocket::OnBindCompleted, base::Unretained(this)))); | |
| 191 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING); | |
| 192 state_ = STATE_BINDING; | |
| 193 | |
| 194 return true; | |
| 195 } | |
| 196 | |
| 197 void UdpPacketSocket::OnBindCompleted(int result) { | |
| 198 DCHECK_EQ(state_, STATE_BINDING); | |
| 199 | |
| 200 if (result == PP_OK) { | |
| 201 PP_NetAddress_Private address; | |
| 202 if (socket.GetBoundAddress(&address)) { | |
| 203 PpAddressToSocketAddress(address, &local_address_); | |
| 204 } else { | |
| 205 LOG(ERROR) << "Failed to get bind address for bound socket?"; | |
| 206 error_ = EINVAL; | |
| 207 return; | |
| 208 } | |
| 209 state_ = STATE_BOUND; | |
| 210 SignalAddressReady(this, local_address_); | |
| 211 DoRead(); | |
| 212 return; | |
| 213 } | |
| 214 | |
| 215 if (current_port_ < max_port_) { | |
| 216 // Try to bind to the next available port. | |
| 217 ++current_port_; | |
| 218 PP_NetAddress_Private pp_local_address; | |
| 219 if (SocketAddressToPpAddressWithPort(local_address_, &pp_local_address, | |
| 220 current_port_)) { | |
| 221 int result = socket.Bind(&pp_local_address, PpCompletionCallback( | |
| 222 base::Bind(&UdpPacketSocket::OnBindCompleted, | |
| 223 base::Unretained(this)))); | |
|
Wez
2012/04/20 21:37:07
Hmmm, I think we'll leak a base::Callback from PpC
Sergey Ulanov
2012/04/23 22:16:51
The callbacks must be invoked with PP_ERROR_ABORTE
Wez
2012/04/25 00:01:59
If the caller deletes this object while the socket
Sergey Ulanov
2012/04/25 00:25:01
More recent version of OnBindCompleted() handles t
| |
| 224 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING); | |
| 225 } | |
| 226 } else { | |
| 227 LOG(ERROR) << "Failed to bind UDP socket: " << result; | |
| 228 } | |
| 229 } | |
| 230 | |
| 231 talk_base::SocketAddress UdpPacketSocket::GetLocalAddress() const { | |
| 232 return local_address_; | |
| 233 } | |
| 234 | |
| 235 talk_base::SocketAddress UdpPacketSocket::GetRemoteAddress() const { | |
| 236 // UDP sockets are not connected - this method should never be called. | |
| 237 NOTREACHED(); | |
| 238 return talk_base::SocketAddress(); | |
| 239 } | |
| 240 | |
| 241 int UdpPacketSocket::Send(const void* data, size_t data_size) { | |
| 242 // UDP sockets are not connected - this method should never be called. | |
|
Wez
2012/04/20 21:37:07
They _can_ be connected, in which case this and Ge
Sergey Ulanov
2012/04/23 22:16:51
UDP instances of AsyncPacketSocket are never conne
| |
| 243 NOTREACHED(); | |
| 244 return EWOULDBLOCK; | |
| 245 } | |
| 246 | |
| 247 int UdpPacketSocket::SendTo(const void* data, | |
| 248 size_t data_size, | |
| 249 const talk_base::SocketAddress& address) { | |
| 250 if (error_ != 0) { | |
| 251 return error_; | |
| 252 } | |
| 253 | |
| 254 PP_NetAddress_Private pp_address; | |
| 255 if (!SocketAddressToPpAddress(address, &pp_address)) { | |
| 256 return EINVAL; | |
| 257 } | |
| 258 | |
| 259 if (send_queue_size_ >= kMaxSendBufferSize) { | |
| 260 return EWOULDBLOCK; | |
| 261 } | |
| 262 | |
| 263 send_queue_.push_back(PendingPacket(data, data_size, pp_address)); | |
| 264 send_queue_size_ += data_size; | |
| 265 DoSend(); | |
| 266 return data_size; | |
| 267 } | |
| 268 | |
| 269 int UdpPacketSocket::Close() { | |
| 270 socket.Close(); | |
| 271 state_ = STATE_CLOSED; | |
| 272 return 0; | |
| 273 } | |
| 274 | |
| 275 talk_base::AsyncPacketSocket::State UdpPacketSocket::GetState() const { | |
| 276 return state_; | |
| 277 } | |
| 278 | |
| 279 int UdpPacketSocket::GetOption(talk_base::Socket::Option opt, int* value) { | |
| 280 return -1; | |
|
Wez
2012/04/20 21:37:07
nit: Add a // comment explaining this return code.
Sergey Ulanov
2012/04/23 22:16:51
Done.
| |
| 281 } | |
| 282 | |
| 283 int UdpPacketSocket::SetOption(talk_base::Socket::Option opt, int value) { | |
| 284 return -1; | |
| 285 } | |
| 286 | |
| 287 int UdpPacketSocket::GetError() const { | |
| 288 return error_; | |
| 289 } | |
| 290 | |
| 291 void UdpPacketSocket::SetError(int error) { | |
| 292 error_ = error; | |
| 293 } | |
| 294 | |
| 295 void UdpPacketSocket::DoSend() { | |
| 296 if (send_pending_ || send_queue_.empty()) | |
| 297 return; | |
| 298 | |
| 299 int result = socket.SendTo( | |
| 300 send_queue_.front().data->data(), send_queue_.front().data->size(), | |
| 301 &send_queue_.front().address, | |
| 302 PpCompletionCallback(base::Bind(&UdpPacketSocket::OnSendCompleted, | |
| 303 base::Unretained(this)))); | |
|
Wez
2012/04/20 21:37:07
Is the SendTo() interface actually defined to not
Sergey Ulanov
2012/04/23 22:16:51
Yes, SendTo() would return an error when another s
Wez
2012/04/25 00:01:59
Shouldn't you get PP_ERROR_IN_PROGRESS to the comp
Sergey Ulanov
2012/04/25 00:25:01
I take this back - looks like the current UDP sock
| |
| 304 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING); | |
| 305 send_pending_ = true; | |
| 306 } | |
| 307 | |
| 308 void UdpPacketSocket::OnSendCompleted(int result) { | |
| 309 if (result < 0) { | |
| 310 LOG(ERROR) << "Send failed on a UDP socket: " << result; | |
| 311 error_ = EINVAL; | |
| 312 return; | |
| 313 } | |
| 314 | |
| 315 send_pending_ = false; | |
| 316 send_queue_size_ -= send_queue_.front().data->size(); | |
| 317 send_queue_.pop_front(); | |
| 318 DoSend(); | |
| 319 } | |
| 320 | |
| 321 void UdpPacketSocket::DoRead() { | |
| 322 receive_buffer_.resize(kReceiveBufferSize); | |
| 323 int result = socket.RecvFrom( | |
| 324 &receive_buffer_[0], receive_buffer_.size(), | |
| 325 PpCompletionCallback(base::Bind(&UdpPacketSocket::OnReadCompleted, | |
| 326 base::Unretained(this)))); | |
| 327 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING); | |
| 328 } | |
| 329 | |
| 330 void UdpPacketSocket::OnReadCompleted(int result) { | |
| 331 HandleReadResult(result); | |
| 332 if (result > 0) { | |
| 333 DoRead(); | |
| 334 } | |
| 335 } | |
| 336 | |
| 337 void UdpPacketSocket::HandleReadResult(int result) { | |
| 338 if (result > 0) { | |
| 339 PP_NetAddress_Private pp_address; | |
| 340 if (!socket.GetRecvFromAddress(&pp_address)) { | |
| 341 LOG(ERROR) << "GetRecvFromAddress() failed after successfull RecvFrom()."; | |
| 342 return; | |
| 343 } | |
| 344 talk_base::SocketAddress address; | |
| 345 if (!PpAddressToSocketAddress(pp_address, &address)) { | |
| 346 LOG(ERROR) << "Failed to covert address received from RecvFrom()."; | |
| 347 return; | |
| 348 } | |
| 349 SignalReadPacket(this, &receive_buffer_[0], result, address); | |
|
Wez
2012/04/20 21:37:07
SignalReadPacket() could trigger the caller to tea
Sergey Ulanov
2012/04/23 22:16:51
It should be safe to delete the socket from a call
Wez
2012/04/25 00:01:59
Right. So if calling code deletes us from within
Sergey Ulanov
2012/04/25 00:25:01
ah, I see what you are talking about now. Actually
| |
| 350 } | |
| 351 } | |
| 352 | |
| 353 } // namespace | |
| 354 | |
| 355 PepperPacketSocketFactory::PepperPacketSocketFactory( | |
| 356 const pp::InstanceHandle& instance) | |
| 357 : pp_instance_(instance) { | |
| 358 } | |
| 359 | |
| 360 PepperPacketSocketFactory::~PepperPacketSocketFactory() { | |
| 361 } | |
| 362 | |
| 363 talk_base::AsyncPacketSocket* PepperPacketSocketFactory::CreateUdpSocket( | |
| 364 const talk_base::SocketAddress& local_address, | |
| 365 int min_port, | |
| 366 int max_port) { | |
| 367 scoped_ptr<UdpPacketSocket> result(new UdpPacketSocket(pp_instance_)); | |
| 368 if (!result->Init(local_address, min_port, max_port)) | |
| 369 return NULL; | |
| 370 return result.release(); | |
| 371 } | |
| 372 | |
| 373 talk_base::AsyncPacketSocket* PepperPacketSocketFactory::CreateServerTcpSocket( | |
| 374 const talk_base::SocketAddress& local_address, | |
| 375 int min_port, | |
| 376 int max_port, | |
| 377 bool ssl) { | |
| 378 // Don't use TCP sockets for remoting connections. | |
|
Wez
2012/04/20 21:37:07
NOTREACHED()?
Sergey Ulanov
2012/04/23 22:16:51
Done.
| |
| 379 return NULL; | |
| 380 } | |
| 381 | |
| 382 talk_base::AsyncPacketSocket* PepperPacketSocketFactory::CreateClientTcpSocket( | |
| 383 const talk_base::SocketAddress& local_address, | |
| 384 const talk_base::SocketAddress& remote_address, | |
| 385 const talk_base::ProxyInfo& proxy_info, | |
| 386 const std::string& user_agent, | |
| 387 bool ssl) { | |
| 388 // Don't use TCP sockets for remoting connections. | |
| 389 return NULL; | |
| 390 } | |
| 391 | |
| 392 } // namespace remoting | |
| OLD | NEW |