1 /* 2 * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 #ifndef API_TEST_NETWORK_EMULATION_NETWORK_EMULATION_INTERFACES_H_ 11 #define API_TEST_NETWORK_EMULATION_NETWORK_EMULATION_INTERFACES_H_ 12 13 #include <map> 14 #include <vector> 15 16 #include "absl/types/optional.h" 17 #include "api/units/data_rate.h" 18 #include "api/units/data_size.h" 19 #include "api/units/timestamp.h" 20 #include "rtc_base/copy_on_write_buffer.h" 21 #include "rtc_base/ip_address.h" 22 #include "rtc_base/socket_address.h" 23 24 namespace webrtc { 25 26 struct EmulatedIpPacket { 27 public: 28 EmulatedIpPacket(const rtc::SocketAddress& from, 29 const rtc::SocketAddress& to, 30 rtc::CopyOnWriteBuffer data, 31 Timestamp arrival_time, 32 uint16_t application_overhead = 0); 33 ~EmulatedIpPacket() = default; 34 // This object is not copyable or assignable. 35 EmulatedIpPacket(const EmulatedIpPacket&) = delete; 36 EmulatedIpPacket& operator=(const EmulatedIpPacket&) = delete; 37 // This object is only moveable. 38 EmulatedIpPacket(EmulatedIpPacket&&) = default; 39 EmulatedIpPacket& operator=(EmulatedIpPacket&&) = default; 40 sizeEmulatedIpPacket41 size_t size() const { return data.size(); } cdataEmulatedIpPacket42 const uint8_t* cdata() const { return data.cdata(); } 43 ip_packet_sizeEmulatedIpPacket44 size_t ip_packet_size() const { return size() + headers_size; } 45 rtc::SocketAddress from; 46 rtc::SocketAddress to; 47 // Holds the UDP payload. 48 rtc::CopyOnWriteBuffer data; 49 uint16_t headers_size; 50 Timestamp arrival_time; 51 }; 52 53 // Interface for handling IP packets from an emulated network. This is used with 54 // EmulatedEndpoint to receive packets on a specific port. 55 class EmulatedNetworkReceiverInterface { 56 public: 57 virtual ~EmulatedNetworkReceiverInterface() = default; 58 59 virtual void OnPacketReceived(EmulatedIpPacket packet) = 0; 60 }; 61 62 struct EmulatedNetworkIncomingStats { 63 // Total amount of packets received with or without destination. 64 int64_t packets_received = 0; 65 // Total amount of bytes in received packets. 66 DataSize bytes_received = DataSize::Zero(); 67 // Total amount of packets that were received, but no destination was found. 68 int64_t packets_dropped = 0; 69 // Total amount of bytes in dropped packets. 70 DataSize bytes_dropped = DataSize::Zero(); 71 72 DataSize first_received_packet_size = DataSize::Zero(); 73 74 // Timestamps are initialized to different infinities for simplifying 75 // computations. Client have to assume that it is some infinite value 76 // if unset. Client mustn't consider sign of infinit value. 77 Timestamp first_packet_received_time = Timestamp::PlusInfinity(); 78 Timestamp last_packet_received_time = Timestamp::MinusInfinity(); 79 AverageReceiveRateEmulatedNetworkIncomingStats80 DataRate AverageReceiveRate() const { 81 RTC_DCHECK_GE(packets_received, 2); 82 RTC_DCHECK(first_packet_received_time.IsFinite()); 83 RTC_DCHECK(last_packet_received_time.IsFinite()); 84 return (bytes_received - first_received_packet_size) / 85 (last_packet_received_time - first_packet_received_time); 86 } 87 }; 88 89 struct EmulatedNetworkStats { 90 int64_t packets_sent = 0; 91 DataSize bytes_sent = DataSize::Zero(); 92 93 DataSize first_sent_packet_size = DataSize::Zero(); 94 Timestamp first_packet_sent_time = Timestamp::PlusInfinity(); 95 Timestamp last_packet_sent_time = Timestamp::MinusInfinity(); 96 97 // List of IP addresses that were used to send data considered in this stats 98 // object. 99 std::vector<rtc::IPAddress> local_addresses; 100 101 std::map<rtc::IPAddress, EmulatedNetworkIncomingStats> 102 incoming_stats_per_source; 103 AverageSendRateEmulatedNetworkStats104 DataRate AverageSendRate() const { 105 RTC_DCHECK_GE(packets_sent, 2); 106 return (bytes_sent - first_sent_packet_size) / 107 (last_packet_sent_time - first_packet_sent_time); 108 } 109 110 // Total amount of packets received regardless of the destination address. PacketsReceivedEmulatedNetworkStats111 int64_t PacketsReceived() const { 112 int64_t packets_received = 0; 113 for (const auto& incoming_stats : incoming_stats_per_source) { 114 packets_received += incoming_stats.second.packets_received; 115 } 116 return packets_received; 117 } 118 119 // Total amount of bytes in received packets. BytesReceivedEmulatedNetworkStats120 DataSize BytesReceived() const { 121 DataSize bytes_received = DataSize::Zero(); 122 for (const auto& incoming_stats : incoming_stats_per_source) { 123 bytes_received += incoming_stats.second.bytes_received; 124 } 125 return bytes_received; 126 } 127 128 // Total amount of packets that were received, but no destination was found. PacketsDroppedEmulatedNetworkStats129 int64_t PacketsDropped() const { 130 int64_t packets_dropped = 0; 131 for (const auto& incoming_stats : incoming_stats_per_source) { 132 packets_dropped += incoming_stats.second.packets_dropped; 133 } 134 return packets_dropped; 135 } 136 137 // Total amount of bytes in dropped packets. BytesDroppedEmulatedNetworkStats138 DataSize BytesDropped() const { 139 DataSize bytes_dropped = DataSize::Zero(); 140 for (const auto& incoming_stats : incoming_stats_per_source) { 141 bytes_dropped += incoming_stats.second.bytes_dropped; 142 } 143 return bytes_dropped; 144 } 145 FirstReceivedPacketSizeEmulatedNetworkStats146 DataSize FirstReceivedPacketSize() const { 147 Timestamp first_packet_received_time = Timestamp::PlusInfinity(); 148 DataSize first_received_packet_size = DataSize::Zero(); 149 for (const auto& incoming_stats : incoming_stats_per_source) { 150 if (first_packet_received_time > 151 incoming_stats.second.first_packet_received_time) { 152 first_packet_received_time = 153 incoming_stats.second.first_packet_received_time; 154 first_received_packet_size = 155 incoming_stats.second.first_received_packet_size; 156 } 157 } 158 return first_received_packet_size; 159 } 160 FirstPacketReceivedTimeEmulatedNetworkStats161 Timestamp FirstPacketReceivedTime() const { 162 Timestamp first_packet_received_time = Timestamp::PlusInfinity(); 163 for (const auto& incoming_stats : incoming_stats_per_source) { 164 if (first_packet_received_time > 165 incoming_stats.second.first_packet_received_time) { 166 first_packet_received_time = 167 incoming_stats.second.first_packet_received_time; 168 } 169 } 170 return first_packet_received_time; 171 } 172 LastPacketReceivedTimeEmulatedNetworkStats173 Timestamp LastPacketReceivedTime() const { 174 Timestamp last_packet_received_time = Timestamp::MinusInfinity(); 175 for (const auto& incoming_stats : incoming_stats_per_source) { 176 if (last_packet_received_time < 177 incoming_stats.second.last_packet_received_time) { 178 last_packet_received_time = 179 incoming_stats.second.last_packet_received_time; 180 } 181 } 182 return last_packet_received_time; 183 } 184 AverageReceiveRateEmulatedNetworkStats185 DataRate AverageReceiveRate() const { 186 RTC_DCHECK_GE(PacketsReceived(), 2); 187 return (BytesReceived() - FirstReceivedPacketSize()) / 188 (LastPacketReceivedTime() - FirstPacketReceivedTime()); 189 } 190 }; 191 192 // EmulatedEndpoint is an abstraction for network interface on device. Instances 193 // of this are created by NetworkEmulationManager::CreateEndpoint. 194 class EmulatedEndpoint : public EmulatedNetworkReceiverInterface { 195 public: 196 // Send packet into network. 197 // |from| will be used to set source address for the packet in destination 198 // socket. 199 // |to| will be used for routing verification and picking right socket by port 200 // on destination endpoint. 201 virtual void SendPacket(const rtc::SocketAddress& from, 202 const rtc::SocketAddress& to, 203 rtc::CopyOnWriteBuffer packet_data, 204 uint16_t application_overhead = 0) = 0; 205 206 // Binds receiver to this endpoint to send and receive data. 207 // |desired_port| is a port that should be used. If it is equal to 0, 208 // endpoint will pick the first available port starting from 209 // |kFirstEphemeralPort|. 210 // 211 // Returns the port, that should be used (it will be equals to desired, if 212 // |desired_port| != 0 and is free or will be the one, selected by endpoint) 213 // or absl::nullopt if desired_port in used. Also fails if there are no more 214 // free ports to bind to. 215 virtual absl::optional<uint16_t> BindReceiver( 216 uint16_t desired_port, 217 EmulatedNetworkReceiverInterface* receiver) = 0; 218 virtual void UnbindReceiver(uint16_t port) = 0; 219 virtual rtc::IPAddress GetPeerLocalAddress() const = 0; 220 221 virtual EmulatedNetworkStats stats() = 0; 222 223 private: 224 // Ensure that there can be no other subclass than EmulatedEndpointImpl. This 225 // means that it's always safe to downcast EmulatedEndpoint instances to 226 // EmulatedEndpointImpl. 227 friend class EmulatedEndpointImpl; 228 EmulatedEndpoint() = default; 229 }; 230 231 // Simulates a TCP connection, this roughly implements the Reno algorithm. In 232 // difference from TCP this only support sending messages with a fixed length, 233 // no streaming. This is useful to simulate signaling and cross traffic using 234 // message based protocols such as HTTP. It differs from UDP messages in that 235 // they are guranteed to be delivered eventually, even on lossy networks. 236 class TcpMessageRoute { 237 public: 238 // Sends a TCP message of the given |size| over the route, |on_received| is 239 // called when the message has been delivered. Note that the connection 240 // parameters are reset iff there's no currently pending message on the route. 241 virtual void SendMessage(size_t size, std::function<void()> on_received) = 0; 242 243 protected: 244 ~TcpMessageRoute() = default; 245 }; 246 } // namespace webrtc 247 248 #endif // API_TEST_NETWORK_EMULATION_NETWORK_EMULATION_INTERFACES_H_ 249