123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467 |
- // Copyright 2014 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "remoting/protocol/chromium_socket_factory.h"
- #include <stddef.h>
- #include <list>
- #include <memory>
- #include <string>
- #include "base/bind.h"
- #include "base/logging.h"
- #include "base/rand_util.h"
- #include "base/time/time.h"
- #include "components/webrtc/net_address_utils.h"
- #include "net/base/io_buffer.h"
- #include "net/base/ip_endpoint.h"
- #include "net/base/net_errors.h"
- #include "net/log/net_log_source.h"
- #include "net/socket/udp_server_socket.h"
- #include "remoting/base/logging.h"
- #include "remoting/base/session_options.h"
- #include "remoting/protocol/session_options_provider.h"
- #include "remoting/protocol/socket_util.h"
- #include "remoting/protocol/stream_packet_socket.h"
- #include "third_party/webrtc/media/base/rtp_utils.h"
- #include "third_party/webrtc/rtc_base/async_packet_socket.h"
- #include "third_party/webrtc/rtc_base/async_resolver.h"
- #include "third_party/webrtc/rtc_base/net_helpers.h"
- #include "third_party/webrtc/rtc_base/socket.h"
- namespace remoting {
- namespace protocol {
- namespace {
- // Size of the buffer to allocate for RecvFrom().
- const int kReceiveBufferSize = 65536;
- // Maximum amount of data in the send buffers. This is necessary to
- // prevent out-of-memory crashes if the caller sends data faster than
- // Pepper's UDP API can handle it. This maximum should never be
- // reached under normal conditions.
- const int kMaxSendBufferSize = 256 * 1024;
- // Creates a UDP socket and make it listen at |local_address| and |port|.
- // Returns nullptr if the socket fails to listen.
- std::unique_ptr<net::UDPServerSocket> CreateUdpSocketAndListen(
- const net::IPAddress& local_address,
- uint16_t port) {
- auto socket =
- std::make_unique<net::UDPServerSocket>(nullptr, net::NetLogSource());
- int result = socket->Listen(net::IPEndPoint(local_address, port));
- if (result != net::OK) {
- socket.reset();
- }
- return socket;
- }
- class UdpPacketSocket : public rtc::AsyncPacketSocket {
- public:
- UdpPacketSocket();
- UdpPacketSocket(const UdpPacketSocket&) = delete;
- UdpPacketSocket& operator=(const UdpPacketSocket&) = delete;
- ~UdpPacketSocket() override;
- bool Init(const rtc::SocketAddress& local_address,
- uint16_t min_port,
- uint16_t max_port);
- // rtc::AsyncPacketSocket interface.
- rtc::SocketAddress GetLocalAddress() const override;
- rtc::SocketAddress GetRemoteAddress() const override;
- int Send(const void* data,
- size_t data_size,
- const rtc::PacketOptions& options) override;
- int SendTo(const void* data,
- size_t data_size,
- const rtc::SocketAddress& address,
- const rtc::PacketOptions& options) override;
- int Close() override;
- State GetState() const override;
- int GetOption(rtc::Socket::Option option, int* value) override;
- int SetOption(rtc::Socket::Option option, int value) override;
- int GetError() const override;
- void SetError(int error) override;
- private:
- struct PendingPacket {
- PendingPacket(const void* buffer,
- int buffer_size,
- const net::IPEndPoint& address,
- const rtc::PacketOptions& options);
- scoped_refptr<net::IOBufferWithSize> data;
- net::IPEndPoint address;
- bool retried;
- rtc::PacketOptions options;
- };
- void OnBindCompleted(int error);
- void DoSend();
- void OnSendCompleted(int result);
- void DoRead();
- void OnReadCompleted(int result);
- void HandleReadResult(int result);
- std::unique_ptr<net::UDPServerSocket> socket_;
- State state_;
- int error_;
- rtc::SocketAddress local_address_;
- // Receive buffer and address are populated by asynchronous reads.
- scoped_refptr<net::IOBuffer> receive_buffer_;
- net::IPEndPoint receive_address_;
- bool send_pending_;
- std::list<PendingPacket> send_queue_;
- int send_queue_size_;
- };
- UdpPacketSocket::PendingPacket::PendingPacket(const void* buffer,
- int buffer_size,
- const net::IPEndPoint& address,
- const rtc::PacketOptions& options)
- : data(base::MakeRefCounted<net::IOBufferWithSize>(buffer_size)),
- address(address),
- retried(false),
- options(options) {
- memcpy(data->data(), buffer, buffer_size);
- }
- UdpPacketSocket::UdpPacketSocket()
- : state_(STATE_CLOSED),
- error_(0),
- send_pending_(false),
- send_queue_size_(0) {
- }
- UdpPacketSocket::~UdpPacketSocket() {
- Close();
- }
- bool UdpPacketSocket::Init(const rtc::SocketAddress& local_address,
- uint16_t min_port,
- uint16_t max_port) {
- DCHECK_LE(min_port, max_port);
- net::IPEndPoint local_endpoint;
- if (!webrtc::SocketAddressToIPEndPoint(local_address, &local_endpoint)) {
- return false;
- }
- if (min_port == 0 && max_port == 0) {
- // Just listen to any port that is available.
- socket_ = CreateUdpSocketAndListen(local_endpoint.address(), 0u);
- } else {
- // Randomly pick a port to start trying with so that we will less likely
- // pick the same port for relay. TURN server doesn't allow allocating relay
- // session from the same port until the old session is timed out.
- uint32_t port_count = max_port - min_port + 1;
- uint32_t starting_offset = base::RandGenerator(port_count);
- for (uint32_t i = 0; i < port_count; i++) {
- uint16_t port = static_cast<uint16_t>(
- min_port + ((starting_offset + i) % port_count));
- DCHECK_LE(min_port, port);
- DCHECK_LE(port, max_port);
- socket_ = CreateUdpSocketAndListen(local_endpoint.address(), port);
- if (socket_) {
- break;
- }
- }
- }
- if (!socket_.get()) {
- // Failed to bind the socket.
- return false;
- }
- if (socket_->GetLocalAddress(&local_endpoint) != net::OK ||
- !webrtc::IPEndPointToSocketAddress(local_endpoint, &local_address_)) {
- return false;
- }
- state_ = STATE_BOUND;
- DoRead();
- return true;
- }
- rtc::SocketAddress UdpPacketSocket::GetLocalAddress() const {
- DCHECK_EQ(state_, STATE_BOUND);
- return local_address_;
- }
- rtc::SocketAddress UdpPacketSocket::GetRemoteAddress() const {
- // UDP sockets are not connected - this method should never be called.
- NOTREACHED();
- return rtc::SocketAddress();
- }
- int UdpPacketSocket::Send(const void* data, size_t data_size,
- const rtc::PacketOptions& options) {
- // UDP sockets are not connected - this method should never be called.
- NOTREACHED();
- return EWOULDBLOCK;
- }
- int UdpPacketSocket::SendTo(const void* data, size_t data_size,
- const rtc::SocketAddress& address,
- const rtc::PacketOptions& options) {
- if (state_ != STATE_BOUND) {
- NOTREACHED();
- return EINVAL;
- }
- if (error_ != 0) {
- return error_;
- }
- net::IPEndPoint endpoint;
- if (!webrtc::SocketAddressToIPEndPoint(address, &endpoint)) {
- return EINVAL;
- }
- if (send_queue_size_ >= kMaxSendBufferSize) {
- return EWOULDBLOCK;
- }
- PendingPacket packet(data, data_size, endpoint, options);
- send_queue_.push_back(packet);
- send_queue_size_ += data_size;
- DoSend();
- return data_size;
- }
- int UdpPacketSocket::Close() {
- state_ = STATE_CLOSED;
- socket_.reset();
- return 0;
- }
- rtc::AsyncPacketSocket::State UdpPacketSocket::GetState() const {
- return state_;
- }
- int UdpPacketSocket::GetOption(rtc::Socket::Option option, int* value) {
- // This method is never called by libjingle.
- NOTIMPLEMENTED();
- return -1;
- }
- int UdpPacketSocket::SetOption(rtc::Socket::Option option, int value) {
- if (state_ != STATE_BOUND) {
- NOTREACHED();
- return EINVAL;
- }
- switch (option) {
- case rtc::Socket::OPT_DONTFRAGMENT:
- NOTIMPLEMENTED();
- return -1;
- case rtc::Socket::OPT_RCVBUF: {
- int net_error = socket_->SetReceiveBufferSize(value);
- return (net_error == net::OK) ? 0 : -1;
- }
- case rtc::Socket::OPT_SNDBUF: {
- int net_error = socket_->SetSendBufferSize(value);
- return (net_error == net::OK) ? 0 : -1;
- }
- case rtc::Socket::OPT_NODELAY:
- // OPT_NODELAY is only for TCP sockets.
- NOTREACHED();
- return -1;
- case rtc::Socket::OPT_IPV6_V6ONLY:
- NOTIMPLEMENTED();
- return -1;
- case rtc::Socket::OPT_DSCP:
- NOTIMPLEMENTED();
- return -1;
- case rtc::Socket::OPT_RTP_SENDTIME_EXTN_ID:
- NOTIMPLEMENTED();
- return -1;
- }
- NOTREACHED();
- return -1;
- }
- int UdpPacketSocket::GetError() const {
- return error_;
- }
- void UdpPacketSocket::SetError(int error) {
- error_ = error;
- }
- void UdpPacketSocket::DoSend() {
- if (send_pending_ || send_queue_.empty())
- return;
- PendingPacket& packet = send_queue_.front();
- cricket::ApplyPacketOptions(
- reinterpret_cast<uint8_t*>(packet.data->data()), packet.data->size(),
- packet.options.packet_time_params,
- (base::TimeTicks::Now() - base::TimeTicks()).InMicroseconds());
- int result =
- socket_->SendTo(packet.data.get(), packet.data->size(), packet.address,
- base::BindOnce(&UdpPacketSocket::OnSendCompleted,
- base::Unretained(this)));
- if (result == net::ERR_IO_PENDING) {
- send_pending_ = true;
- } else {
- OnSendCompleted(result);
- }
- }
- void UdpPacketSocket::OnSendCompleted(int result) {
- send_pending_ = false;
- if (result < 0) {
- SocketErrorAction action = GetSocketErrorAction(result);
- switch (action) {
- case SOCKET_ERROR_ACTION_FAIL:
- LOG(ERROR) << "Send failed on a UDP socket: " << result;
- error_ = EINVAL;
- return;
- case SOCKET_ERROR_ACTION_RETRY:
- // Retry resending only once.
- if (!send_queue_.front().retried) {
- send_queue_.front().retried = true;
- DoSend();
- return;
- }
- break;
- case SOCKET_ERROR_ACTION_IGNORE:
- break;
- }
- }
- // Don't need to worry about partial sends because this is a datagram
- // socket.
- send_queue_size_ -= send_queue_.front().data->size();
- SignalSentPacket(this, rtc::SentPacket(send_queue_.front().options.packet_id,
- rtc::TimeMillis()));
- send_queue_.pop_front();
- DoSend();
- }
- void UdpPacketSocket::DoRead() {
- int result = 0;
- while (result >= 0) {
- receive_buffer_ = base::MakeRefCounted<net::IOBuffer>(kReceiveBufferSize);
- result = socket_->RecvFrom(receive_buffer_.get(), kReceiveBufferSize,
- &receive_address_,
- base::BindOnce(&UdpPacketSocket::OnReadCompleted,
- base::Unretained(this)));
- HandleReadResult(result);
- }
- }
- void UdpPacketSocket::OnReadCompleted(int result) {
- HandleReadResult(result);
- if (result >= 0) {
- DoRead();
- }
- }
- void UdpPacketSocket::HandleReadResult(int result) {
- if (result == net::ERR_IO_PENDING) {
- return;
- }
- if (result > 0) {
- rtc::SocketAddress address;
- if (!webrtc::IPEndPointToSocketAddress(receive_address_, &address)) {
- NOTREACHED();
- LOG(ERROR) << "Failed to convert address received from RecvFrom().";
- return;
- }
- SignalReadPacket(this, receive_buffer_->data(), result, address,
- rtc::TimeMicros());
- } else {
- LOG(ERROR) << "Received error when reading from UDP socket: " << result;
- }
- }
- } // namespace
- ChromiumPacketSocketFactory::ChromiumPacketSocketFactory(
- base::WeakPtr<SessionOptionsProvider> session_options_provider)
- : session_options_provider_(session_options_provider) {}
- ChromiumPacketSocketFactory::~ChromiumPacketSocketFactory() = default;
- rtc::AsyncPacketSocket* ChromiumPacketSocketFactory::CreateUdpSocket(
- const rtc::SocketAddress& local_address,
- uint16_t min_port,
- uint16_t max_port) {
- if (session_options_provider_ &&
- session_options_provider_->session_options().GetBoolValue(
- "Disable-UDP")) {
- HOST_LOG
- << "Disable-UDP experiment is enabled. UDP socket won't be created.";
- return nullptr;
- }
- std::unique_ptr<UdpPacketSocket> result(new UdpPacketSocket());
- if (!result->Init(local_address, min_port, max_port))
- return nullptr;
- return result.release();
- }
- rtc::AsyncListenSocket* ChromiumPacketSocketFactory::CreateServerTcpSocket(
- const rtc::SocketAddress& local_address,
- uint16_t min_port,
- uint16_t max_port,
- int opts) {
- // TCP sockets are not supported.
- // TODO(yuweih): Implement server side TCP support crbug.com/600032 .
- NOTIMPLEMENTED();
- return nullptr;
- }
- rtc::AsyncPacketSocket* ChromiumPacketSocketFactory::CreateClientTcpSocket(
- const rtc::SocketAddress& local_address,
- const rtc::SocketAddress& remote_address,
- const rtc::ProxyInfo& proxy_info,
- const std::string& user_agent,
- const rtc::PacketSocketTcpOptions& opts) {
- if (session_options_provider_ &&
- session_options_provider_->session_options().GetBoolValue(
- "Disable-TCP")) {
- HOST_LOG << "Disable-TCP experiment is enabled. Client TCP socket won't be "
- << "created.";
- return nullptr;
- }
- auto socket = std::make_unique<StreamPacketSocket>();
- if (!socket->InitClientTcp(local_address, remote_address, proxy_info,
- user_agent, opts)) {
- return nullptr;
- }
- return socket.release();
- }
- rtc::AsyncResolverInterface*
- ChromiumPacketSocketFactory::CreateAsyncResolver() {
- return new rtc::AsyncResolver();
- }
- } // namespace protocol
- } // namespace remoting
|