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.
5 #include "media/cast/transport/transport/udp_transport.h"
10 #include "base/bind.h"
11 #include "base/logging.h"
12 #include "base/memory/ref_counted.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/rand_util.h"
16 #include "net/base/io_buffer.h"
17 #include "net/base/net_errors.h"
18 #include "net/base/rand_callback.h"
25 const int kMaxPacketSize = 1500;
27 bool IsEmpty(const net::IPEndPoint& addr) {
28 net::IPAddressNumber empty_addr(addr.address().size());
30 empty_addr.begin(), empty_addr.end(), addr.address().begin()) &&
34 bool IsEqual(const net::IPEndPoint& addr1, const net::IPEndPoint& addr2) {
35 return addr1.port() == addr2.port() && std::equal(addr1.address().begin(),
36 addr1.address().end(),
37 addr2.address().begin());
41 UdpTransport::UdpTransport(
42 const scoped_refptr<base::SingleThreadTaskRunner>& io_thread_proxy,
43 const net::IPEndPoint& local_end_point,
44 const net::IPEndPoint& remote_end_point,
45 const CastTransportStatusCallback& status_callback)
46 : io_thread_proxy_(io_thread_proxy),
47 local_addr_(local_end_point),
48 remote_addr_(remote_end_point),
49 udp_socket_(new net::UDPSocket(net::DatagramSocket::DEFAULT_BIND,
50 net::RandIntCallback(),
52 net::NetLog::Source())),
54 recv_buf_(new net::IOBuffer(kMaxPacketSize)),
55 status_callback_(status_callback),
57 DCHECK(!IsEmpty(local_end_point) || !IsEmpty(remote_end_point));
60 UdpTransport::~UdpTransport() {}
62 void UdpTransport::StartReceiving(
63 const PacketReceiverCallback& packet_receiver) {
64 DCHECK(io_thread_proxy_->RunsTasksOnCurrentThread());
66 packet_receiver_ = packet_receiver;
67 udp_socket_->AllowAddressReuse();
68 udp_socket_->SetMulticastLoopbackMode(true);
69 if (!IsEmpty(local_addr_)) {
70 if (udp_socket_->Bind(local_addr_) < 0) {
71 status_callback_.Run(TRANSPORT_SOCKET_ERROR);
72 LOG(ERROR) << "Failed to bind local address.";
75 } else if (!IsEmpty(remote_addr_)) {
76 if (udp_socket_->Connect(remote_addr_) < 0) {
77 status_callback_.Run(TRANSPORT_SOCKET_ERROR);
78 LOG(ERROR) << "Failed to connect to remote address.";
82 NOTREACHED() << "Either local or remote address has to be defined.";
87 void UdpTransport::ReceiveOnePacket() {
88 DCHECK(io_thread_proxy_->RunsTasksOnCurrentThread());
90 int result = udp_socket_->RecvFrom(
94 base::Bind(&UdpTransport::OnReceived, weak_factory_.GetWeakPtr()));
97 } else if (result != net::ERR_IO_PENDING) {
98 LOG(ERROR) << "Failed to receive packet: " << result << "."
99 << " Stop receiving packets.";
100 status_callback_.Run(TRANSPORT_SOCKET_ERROR);
104 void UdpTransport::OnReceived(int result) {
105 DCHECK(io_thread_proxy_->RunsTasksOnCurrentThread());
107 LOG(ERROR) << "Failed to receive packet: " << result << "."
108 << " Stop receiving packets.";
109 status_callback_.Run(TRANSPORT_SOCKET_ERROR);
113 if (IsEmpty(remote_addr_)) {
114 remote_addr_ = recv_addr_;
115 VLOG(1) << "First packet received from: " << remote_addr_.ToString() << ".";
116 } else if (!IsEqual(remote_addr_, recv_addr_)) {
117 LOG(ERROR) << "Received from an unrecognized address: "
118 << recv_addr_.ToString() << ".";
121 // TODO(hclam): The interfaces should use net::IOBuffer to eliminate memcpy.
122 scoped_ptr<Packet> packet(
123 new Packet(recv_buf_->data(), recv_buf_->data() + result));
124 packet_receiver_.Run(packet.Pass());
128 bool UdpTransport::SendPacket(const Packet& packet) {
129 DCHECK(io_thread_proxy_->RunsTasksOnCurrentThread());
132 VLOG(1) << "Cannot send because of pending IO.";
136 // TODO(hclam): This interface should take a net::IOBuffer to minimize
138 scoped_refptr<net::IOBuffer> buf =
139 new net::IOBuffer(static_cast<int>(packet.size()));
140 memcpy(buf->data(), &packet[0], packet.size());
141 int ret = udp_socket_->SendTo(
143 static_cast<int>(packet.size()),
145 base::Bind(&UdpTransport::OnSent, weak_factory_.GetWeakPtr(), buf));
146 if (ret == net::ERR_IO_PENDING)
147 send_pending_ = true;
148 // When ok, will return a positive value equal the number of bytes sent.
149 return ret >= net::OK;
152 void UdpTransport::OnSent(const scoped_refptr<net::IOBuffer>& buf, int result) {
153 DCHECK(io_thread_proxy_->RunsTasksOnCurrentThread());
155 send_pending_ = false;
157 LOG(ERROR) << "Failed to send packet: " << result << ".";
158 status_callback_.Run(TRANSPORT_SOCKET_ERROR);
162 } // namespace transport