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/jingle_glue/chromium_socket_factory.h" 6 7 #include "base/bind.h" 8 #include "base/logging.h" 9 #include "base/memory/scoped_ptr.h" 10 #include "jingle/glue/utils.h" 11 #include "net/base/io_buffer.h" 12 #include "net/base/ip_endpoint.h" 13 #include "net/base/net_errors.h" 14 #include "net/udp/udp_server_socket.h" 15 #include "third_party/libjingle/source/talk/base/asyncpacketsocket.h" 16 17 namespace remoting { 18 19 namespace { 20 21 // Size of the buffer to allocate for RecvFrom(). 22 const int kReceiveBufferSize = 65536; 23 24 // Maximum amount of data in the send buffers. This is necessary to 25 // prevent out-of-memory crashes if the caller sends data faster than 26 // Pepper's UDP API can handle it. This maximum should never be 27 // reached under normal conditions. 28 const int kMaxSendBufferSize = 256 * 1024; 29 30 // Defines set of transient errors. These errors are ignored when we get them 31 // from sendto() calls. 32 bool IsTransientError(int error) { 33 return error == net::ERR_ADDRESS_UNREACHABLE || 34 error == net::ERR_ADDRESS_INVALID; 35 } 36 37 class UdpPacketSocket : public talk_base::AsyncPacketSocket { 38 public: 39 UdpPacketSocket(); 40 virtual ~UdpPacketSocket(); 41 42 bool Init(const talk_base::SocketAddress& local_address, 43 int min_port, int max_port); 44 45 // talk_base::AsyncPacketSocket interface. 46 virtual talk_base::SocketAddress GetLocalAddress() const OVERRIDE; 47 virtual talk_base::SocketAddress GetRemoteAddress() const OVERRIDE; 48 virtual int Send(const void* data, size_t data_size) OVERRIDE; 49 virtual int SendTo(const void* data, size_t data_size, 50 const talk_base::SocketAddress& address) OVERRIDE; 51 virtual int Close() OVERRIDE; 52 virtual State GetState() const OVERRIDE; 53 virtual int GetOption(talk_base::Socket::Option option, int* value) OVERRIDE; 54 virtual int SetOption(talk_base::Socket::Option option, int value) OVERRIDE; 55 virtual int GetError() const OVERRIDE; 56 virtual void SetError(int error) OVERRIDE; 57 58 private: 59 struct PendingPacket { 60 PendingPacket(const void* buffer, 61 int buffer_size, 62 const net::IPEndPoint& address); 63 64 scoped_refptr<net::IOBufferWithSize> data; 65 net::IPEndPoint address; 66 }; 67 68 void OnBindCompleted(int error); 69 70 void DoSend(); 71 void OnSendCompleted(int result); 72 73 void DoRead(); 74 void OnReadCompleted(int result); 75 void HandleReadResult(int result); 76 77 scoped_ptr<net::UDPServerSocket> socket_; 78 79 State state_; 80 int error_; 81 82 talk_base::SocketAddress local_address_; 83 84 // Receive buffer and address are populated by asynchronous reads. 85 scoped_refptr<net::IOBuffer> receive_buffer_; 86 net::IPEndPoint receive_address_; 87 88 bool send_pending_; 89 std::list<PendingPacket> send_queue_; 90 int send_queue_size_; 91 92 DISALLOW_COPY_AND_ASSIGN(UdpPacketSocket); 93 }; 94 95 UdpPacketSocket::PendingPacket::PendingPacket( 96 const void* buffer, 97 int buffer_size, 98 const net::IPEndPoint& address) 99 : data(new net::IOBufferWithSize(buffer_size)), 100 address(address) { 101 memcpy(data->data(), buffer, buffer_size); 102 } 103 104 UdpPacketSocket::UdpPacketSocket() 105 : state_(STATE_CLOSED), 106 error_(0), 107 send_pending_(false), 108 send_queue_size_(0) { 109 } 110 111 UdpPacketSocket::~UdpPacketSocket() { 112 Close(); 113 } 114 115 bool UdpPacketSocket::Init(const talk_base::SocketAddress& local_address, 116 int min_port, int max_port) { 117 net::IPEndPoint local_endpoint; 118 if (!jingle_glue::SocketAddressToIPEndPoint( 119 local_address, &local_endpoint)) { 120 return false; 121 } 122 123 for (int port = min_port; port <= max_port; ++port) { 124 socket_.reset(new net::UDPServerSocket(NULL, net::NetLog::Source())); 125 int result = socket_->Listen( 126 net::IPEndPoint(local_endpoint.address(), port)); 127 if (result == net::OK) { 128 break; 129 } else { 130 socket_.reset(); 131 } 132 } 133 134 if (!socket_.get()) { 135 // Failed to bind the socket. 136 return false; 137 } 138 139 if (socket_->GetLocalAddress(&local_endpoint) != net::OK || 140 !jingle_glue::IPEndPointToSocketAddress(local_endpoint, 141 &local_address_)) { 142 return false; 143 } 144 145 state_ = STATE_BOUND; 146 DoRead(); 147 148 return true; 149 } 150 151 talk_base::SocketAddress UdpPacketSocket::GetLocalAddress() const { 152 DCHECK_EQ(state_, STATE_BOUND); 153 return local_address_; 154 } 155 156 talk_base::SocketAddress UdpPacketSocket::GetRemoteAddress() const { 157 // UDP sockets are not connected - this method should never be called. 158 NOTREACHED(); 159 return talk_base::SocketAddress(); 160 } 161 162 int UdpPacketSocket::Send(const void* data, size_t data_size) { 163 // UDP sockets are not connected - this method should never be called. 164 NOTREACHED(); 165 return EWOULDBLOCK; 166 } 167 168 int UdpPacketSocket::SendTo(const void* data, size_t data_size, 169 const talk_base::SocketAddress& address) { 170 if (state_ != STATE_BOUND) { 171 NOTREACHED(); 172 return EINVAL; 173 } 174 175 if (error_ != 0) { 176 return error_; 177 } 178 179 net::IPEndPoint endpoint; 180 if (!jingle_glue::SocketAddressToIPEndPoint(address, &endpoint)) { 181 return EINVAL; 182 } 183 184 if (send_queue_size_ >= kMaxSendBufferSize) { 185 return EWOULDBLOCK; 186 } 187 188 send_queue_.push_back(PendingPacket(data, data_size, endpoint)); 189 send_queue_size_ += data_size; 190 191 DoSend(); 192 return data_size; 193 } 194 195 int UdpPacketSocket::Close() { 196 state_ = STATE_CLOSED; 197 socket_.reset(); 198 return 0; 199 } 200 201 talk_base::AsyncPacketSocket::State UdpPacketSocket::GetState() const { 202 return state_; 203 } 204 205 int UdpPacketSocket::GetOption(talk_base::Socket::Option option, int* value) { 206 // This method is never called by libjingle. 207 NOTIMPLEMENTED(); 208 return -1; 209 } 210 211 int UdpPacketSocket::SetOption(talk_base::Socket::Option option, int value) { 212 if (state_ != STATE_BOUND) { 213 NOTREACHED(); 214 return EINVAL; 215 } 216 217 switch (option) { 218 case talk_base::Socket::OPT_DONTFRAGMENT: 219 NOTIMPLEMENTED(); 220 return -1; 221 222 case talk_base::Socket::OPT_RCVBUF: { 223 bool success = socket_->SetReceiveBufferSize(value); 224 return success ? 0 : -1; 225 } 226 227 case talk_base::Socket::OPT_SNDBUF: { 228 bool success = socket_->SetSendBufferSize(value); 229 return success ? 0 : -1; 230 } 231 232 case talk_base::Socket::OPT_NODELAY: 233 // OPT_NODELAY is only for TCP sockets. 234 NOTREACHED(); 235 return -1; 236 237 case talk_base::Socket::OPT_IPV6_V6ONLY: 238 NOTIMPLEMENTED(); 239 return -1; 240 } 241 242 NOTREACHED(); 243 return -1; 244 } 245 246 int UdpPacketSocket::GetError() const { 247 return error_; 248 } 249 250 void UdpPacketSocket::SetError(int error) { 251 error_ = error; 252 } 253 254 void UdpPacketSocket::DoSend() { 255 if (send_pending_ || send_queue_.empty()) 256 return; 257 258 PendingPacket& packet = send_queue_.front(); 259 int result = socket_->SendTo( 260 packet.data.get(), 261 packet.data->size(), 262 packet.address, 263 base::Bind(&UdpPacketSocket::OnSendCompleted, base::Unretained(this))); 264 if (result == net::ERR_IO_PENDING) { 265 send_pending_ = true; 266 } else { 267 OnSendCompleted(result); 268 } 269 } 270 271 void UdpPacketSocket::OnSendCompleted(int result) { 272 send_pending_ = false; 273 274 if (result < 0) { 275 if (!IsTransientError(result)) { 276 LOG(ERROR) << "Send failed on a UDP socket: " << result; 277 error_ = EINVAL; 278 return; 279 } 280 } 281 282 // Don't need to worry about partial sends because this is a datagram 283 // socket. 284 send_queue_size_ -= send_queue_.front().data->size(); 285 send_queue_.pop_front(); 286 DoSend(); 287 } 288 289 void UdpPacketSocket::DoRead() { 290 int result = 0; 291 while (result >= 0) { 292 receive_buffer_ = new net::IOBuffer(kReceiveBufferSize); 293 result = socket_->RecvFrom( 294 receive_buffer_.get(), 295 kReceiveBufferSize, 296 &receive_address_, 297 base::Bind(&UdpPacketSocket::OnReadCompleted, base::Unretained(this))); 298 HandleReadResult(result); 299 } 300 } 301 302 void UdpPacketSocket::OnReadCompleted(int result) { 303 HandleReadResult(result); 304 if (result >= 0) { 305 DoRead(); 306 } 307 } 308 309 void UdpPacketSocket::HandleReadResult(int result) { 310 if (result == net::ERR_IO_PENDING) { 311 return; 312 } 313 314 if (result > 0) { 315 talk_base::SocketAddress address; 316 if (!jingle_glue::IPEndPointToSocketAddress(receive_address_, &address)) { 317 NOTREACHED(); 318 LOG(ERROR) << "Failed to convert address received from RecvFrom()."; 319 return; 320 } 321 SignalReadPacket(this, receive_buffer_->data(), result, address); 322 } else { 323 LOG(ERROR) << "Received error when reading from UDP socket: " << result; 324 } 325 } 326 327 } // namespace 328 329 ChromiumPacketSocketFactory::ChromiumPacketSocketFactory() { 330 } 331 332 ChromiumPacketSocketFactory::~ChromiumPacketSocketFactory() { 333 } 334 335 talk_base::AsyncPacketSocket* ChromiumPacketSocketFactory::CreateUdpSocket( 336 const talk_base::SocketAddress& local_address, 337 int min_port, int max_port) { 338 scoped_ptr<UdpPacketSocket> result(new UdpPacketSocket()); 339 if (!result->Init(local_address, min_port, max_port)) 340 return NULL; 341 return result.release(); 342 } 343 344 talk_base::AsyncPacketSocket* 345 ChromiumPacketSocketFactory::CreateServerTcpSocket( 346 const talk_base::SocketAddress& local_address, 347 int min_port, int max_port, 348 int opts) { 349 // We don't use TCP sockets for remoting connections. 350 NOTREACHED(); 351 return NULL; 352 } 353 354 talk_base::AsyncPacketSocket* 355 ChromiumPacketSocketFactory::CreateClientTcpSocket( 356 const talk_base::SocketAddress& local_address, 357 const talk_base::SocketAddress& remote_address, 358 const talk_base::ProxyInfo& proxy_info, 359 const std::string& user_agent, 360 int opts) { 361 // We don't use TCP sockets for remoting connections. 362 NOTREACHED(); 363 return NULL; 364 } 365 366 } // namespace remoting 367