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