OLD | NEW |
(Empty) | |
| 1 // Copyright 2013 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 "media/cast/test/transport/transport.h" |
| 6 |
| 7 #include <string> |
| 8 |
| 9 #include "base/bind.h" |
| 10 #include "base/logging.h" |
| 11 #include "base/memory/ref_counted.h" |
| 12 #include "base/memory/scoped_ptr.h" |
| 13 #include "base/rand_util.h" |
| 14 #include "net/base/completion_callback.h" |
| 15 #include "net/base/io_buffer.h" |
| 16 #include "net/base/rand_callback.h" |
| 17 #include "net/base/test_completion_callback.h" |
| 18 |
| 19 namespace media { |
| 20 namespace cast { |
| 21 namespace test { |
| 22 |
| 23 const int kMaxPacketSize = 1500; |
| 24 |
| 25 class LocalUdpTransportData; |
| 26 |
| 27 void CreateUDPAddress(std::string ip_str, int port, net::IPEndPoint* address) { |
| 28 net::IPAddressNumber ip_number; |
| 29 bool rv = net::ParseIPLiteralToNumber(ip_str, &ip_number); |
| 30 if (!rv) |
| 31 return; |
| 32 *address = net::IPEndPoint(ip_number, port); |
| 33 } |
| 34 |
| 35 class LocalUdpTransportData { |
| 36 public: |
| 37 LocalUdpTransportData(net::DatagramServerSocket* udp_socket) |
| 38 : udp_socket_(udp_socket), |
| 39 buffer_(new net::IOBufferWithSize(kMaxPacketSize)), |
| 40 weak_factory_(this) { |
| 41 } |
| 42 |
| 43 void ListenTo(net::IPEndPoint bind_address) { |
| 44 bind_address_ = bind_address; |
| 45 RecvFromSocketLoop(); |
| 46 } |
| 47 |
| 48 void PacketReceived(int result) { |
| 49 // Got a packet with length result. |
| 50 uint8* data = reinterpret_cast<uint8*>(buffer_->data()); |
| 51 packet_receiver_->ReceivedPacket(data, result, |
| 52 base::Bind(&LocalUdpTransportData::DeletePacket, |
| 53 weak_factory_.GetWeakPtr(), data)); |
| 54 } |
| 55 |
| 56 void RecvFromSocketLoop() { |
| 57 // Callback should always trigger with a packet. |
| 58 int res = udp_socket_->RecvFrom(buffer_.get(), kMaxPacketSize, |
| 59 &bind_address_, base::Bind(&LocalUdpTransportData::RecvFromSocketLoop, |
| 60 weak_factory_.GetWeakPtr())); |
| 61 DCHECK(res >= net::IO_PENDING); |
| 62 if (res > 0) { |
| 63 PacketReceived(res); |
| 64 } |
| 65 } |
| 66 |
| 67 void set_packet_receiver(PacketReceiver* packet_receiver) { |
| 68 packet_receiver_ = packet_receiver; |
| 69 } |
| 70 |
| 71 void Close() { |
| 72 udp_socket_->Close(); |
| 73 } |
| 74 |
| 75 private: |
| 76 net::DatagramServerSocket* udp_socket_; |
| 77 net::IPEndPoint bind_address_; |
| 78 PacketReceiver* packet_receiver_; |
| 79 scoped_refptr<net::IOBufferWithSize> buffer_; |
| 80 base::WeakPtrFactory<LocalUdpTransportData> weak_factory_; |
| 81 DISALLOW_COPY_AND_ASSIGN(LocalUdpTransportData); |
| 82 }; |
| 83 |
| 84 class LocalPacketSender : public PacketSender { |
| 85 public: |
| 86 explicit LocalPacketSender(net::DatagramServerSocket* udp_socket) |
| 87 : udp_socket_(udp_socket), |
| 88 send_address_(), |
| 89 loss_limit_(0) {} |
| 90 |
| 91 virtual bool SendPacket(const Packet& packet) { |
| 92 const uint8* data = packet.data(); |
| 93 if (loss_limit_ > 0) { |
| 94 int r = base::RandInt(0, 100); |
| 95 if (r < loss_limit_) { |
| 96 VLOG(1) << "Drop packet f:" << static_cast<int>(data[12 + 1]) |
| 97 << " p:" << static_cast<int>(data[12 + 3]) |
| 98 << " m:" << static_cast<int>(data[12 + 5]); |
| 99 return true; |
| 100 } |
| 101 } |
| 102 net::TestCompletionCallback callback; |
| 103 scoped_refptr<net::WrappedIOBuffer> buffer( |
| 104 new net::WrappedIOBuffer(reinterpret_cast<const char*>(data))); |
| 105 int rv = udp_socket_->SendTo( |
| 106 buffer.get(), packet.size(), send_address_, callback.callback()); |
| 107 return (rv == packet.size()); |
| 108 } |
| 109 |
| 110 virtual bool SendPackets(const PacketList& packets) { |
| 111 bool out_val = true; |
| 112 for (size_t i = 0; i < packets.size(); ++i) { |
| 113 const Packet& packet = packets[i]; |
| 114 out_val |= SendPacket(packet); |
| 115 } |
| 116 return out_val; |
| 117 } |
| 118 |
| 119 void SetPacketLoss(int percentage) { |
| 120 DCHECK(percentage >= 0); |
| 121 DCHECK(percentage < 100); |
| 122 loss_limit_ = percentage; |
| 123 } |
| 124 |
| 125 void SetSendAddress(net::IPEndPoint& send_address) { |
| 126 send_address_ = send_address; |
| 127 } |
| 128 |
| 129 private: |
| 130 net::DatagramServerSocket* udp_socket_; // Not owned by this class. |
| 131 net::IPEndPoint send_address_; |
| 132 int loss_limit_; |
| 133 }; |
| 134 |
| 135 Transport::Transport(scoped_refptr<CastEnvironment> cast_environment) |
| 136 : udp_socket_(new net::UDPServerSocket(NULL, net::NetLog::Source())), |
| 137 local_udp_transport_data_(new LocalUdpTransportData(udp_socket_.get())), |
| 138 packet_sender_(new LocalPacketSender(udp_socket_.get())) {} |
| 139 |
| 140 Transport::~Transport() {} |
| 141 |
| 142 PacketSender* Transport::packet_sender() { |
| 143 return static_cast<PacketSender*>(packet_sender_.get()); |
| 144 } |
| 145 |
| 146 void Transport::SetSendSidePacketLoss(int percentage) { |
| 147 packet_sender_->SetPacketLoss(percentage); |
| 148 } |
| 149 |
| 150 void Transport::StopReceiving() { |
| 151 local_udp_transport_data_->Close(); |
| 152 } |
| 153 |
| 154 void Transport::SetLocalReceiver(PacketReceiver* packet_receiver, |
| 155 std::string ip_address, |
| 156 int port) { |
| 157 net::IPEndPoint bind_address; |
| 158 CreateUDPAddress(ip_address, port, &bind_address); |
| 159 local_udp_transport_data_->set_packet_receiver(packet_receiver); |
| 160 udp_socket_->AllowAddressReuse(); |
| 161 udp_socket_->SetMulticastLoopbackMode(true); |
| 162 udp_socket_->Listen(bind_address); |
| 163 |
| 164 // Start listening once receiver has been set. |
| 165 local_udp_transport_data_->ListenTo(bind_address); |
| 166 } |
| 167 |
| 168 void Transport::SetSendDestination(std::string ip_address, int port) { |
| 169 net::IPEndPoint send_address; |
| 170 CreateUDPAddress(ip_address, port, &send_address); |
| 171 packet_sender_->SetSendAddress(send_address); |
| 172 } |
| 173 |
| 174 } // namespace test |
| 175 } // namespace cast |
| 176 } // namespace media |
OLD | NEW |