Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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/test/fake_socket_factory.h" | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "base/callback.h" | |
| 9 #include "base/location.h" | |
| 10 #include "base/rand_util.h" | |
| 11 #include "base/single_thread_task_runner.h" | |
| 12 #include "base/thread_task_runner_handle.h" | |
| 13 #include "net/base/io_buffer.h" | |
| 14 #include "remoting/test/leaky_bucket.h" | |
| 15 #include "third_party/libjingle/source/talk/base/asyncpacketsocket.h" | |
| 16 | |
| 17 namespace remoting { | |
| 18 | |
| 19 namespace { | |
| 20 | |
| 21 double GetNormalRandom(double average, double variance) { | |
| 22 // Based on Box-Muller transform, see | |
| 23 // http://en.wikipedia.org/wiki/Box_Muller_transform . | |
| 24 return average + | |
| 25 variance * sqrt(-2.0 * log(1.0 - base::RandDouble())) * | |
|
rmsousa
2014/08/12 20:42:10
This should be named stddev. variance is stddev^2
Sergey Ulanov
2014/08/16 00:03:34
Done.
| |
| 26 cos(base::RandDouble() * 2.0 * M_PI); | |
| 27 } | |
| 28 | |
| 29 class FakeUdpSocket : public talk_base::AsyncPacketSocket { | |
| 30 public: | |
| 31 FakeUdpSocket(FakePacketSocketFactory* factory, | |
| 32 scoped_refptr<FakeNetworkDispatcher> dispatcher, | |
| 33 const talk_base::SocketAddress& local_address); | |
| 34 virtual ~FakeUdpSocket(); | |
| 35 | |
| 36 void ReceivePacket(const talk_base::SocketAddress& from, | |
| 37 const talk_base::SocketAddress& to, | |
| 38 const scoped_refptr<net::IOBuffer>& data, | |
| 39 int data_size); | |
| 40 | |
| 41 // talk_base::AsyncPacketSocket interface. | |
| 42 virtual talk_base::SocketAddress GetLocalAddress() const OVERRIDE; | |
| 43 virtual talk_base::SocketAddress GetRemoteAddress() const OVERRIDE; | |
| 44 virtual int Send(const void* data, size_t data_size, | |
| 45 const talk_base::PacketOptions& options) OVERRIDE; | |
| 46 virtual int SendTo(const void* data, size_t data_size, | |
| 47 const talk_base::SocketAddress& address, | |
| 48 const talk_base::PacketOptions& options) OVERRIDE; | |
| 49 virtual int Close() OVERRIDE; | |
| 50 virtual State GetState() const OVERRIDE; | |
| 51 virtual int GetOption(talk_base::Socket::Option option, int* value) OVERRIDE; | |
| 52 virtual int SetOption(talk_base::Socket::Option option, int value) OVERRIDE; | |
| 53 virtual int GetError() const OVERRIDE; | |
| 54 virtual void SetError(int error) OVERRIDE; | |
| 55 | |
| 56 private: | |
| 57 FakePacketSocketFactory* factory_; | |
| 58 scoped_refptr<FakeNetworkDispatcher> dispatcher_; | |
| 59 talk_base::SocketAddress local_address_; | |
| 60 State state_; | |
| 61 | |
| 62 DISALLOW_COPY_AND_ASSIGN(FakeUdpSocket); | |
| 63 }; | |
| 64 | |
| 65 FakeUdpSocket::FakeUdpSocket(FakePacketSocketFactory* factory, | |
| 66 scoped_refptr<FakeNetworkDispatcher> dispatcher, | |
| 67 const talk_base::SocketAddress& local_address) | |
| 68 : factory_(factory), | |
| 69 dispatcher_(dispatcher), | |
| 70 local_address_(local_address), | |
| 71 state_(STATE_BOUND) { | |
| 72 } | |
| 73 | |
| 74 FakeUdpSocket::~FakeUdpSocket() { | |
| 75 factory_->OnSocketDestroyed(local_address_.port()); | |
| 76 } | |
| 77 | |
| 78 void FakeUdpSocket::ReceivePacket(const talk_base::SocketAddress& from, | |
| 79 const talk_base::SocketAddress& to, | |
| 80 const scoped_refptr<net::IOBuffer>& data, | |
| 81 int data_size) { | |
| 82 SignalReadPacket( | |
| 83 this, data->data(), data_size, from, talk_base::CreatePacketTime(0)); | |
| 84 } | |
| 85 | |
| 86 talk_base::SocketAddress FakeUdpSocket::GetLocalAddress() const { | |
| 87 return local_address_; | |
| 88 } | |
| 89 | |
| 90 talk_base::SocketAddress FakeUdpSocket::GetRemoteAddress() const { | |
| 91 NOTREACHED(); | |
| 92 return talk_base::SocketAddress(); | |
| 93 } | |
| 94 | |
| 95 int FakeUdpSocket::Send(const void* data, size_t data_size, | |
| 96 const talk_base::PacketOptions& options) { | |
| 97 NOTREACHED(); | |
| 98 return EINVAL; | |
| 99 } | |
| 100 | |
| 101 int FakeUdpSocket::SendTo(const void* data, size_t data_size, | |
| 102 const talk_base::SocketAddress& address, | |
| 103 const talk_base::PacketOptions& options) { | |
| 104 scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(data_size); | |
| 105 memcpy(buffer->data(), data, data_size); | |
| 106 dispatcher_->DeliverPacket(local_address_, address, buffer, data_size); | |
| 107 return data_size; | |
| 108 } | |
| 109 | |
| 110 int FakeUdpSocket::Close() { | |
| 111 state_ = STATE_CLOSED; | |
| 112 return 0; | |
| 113 } | |
| 114 | |
| 115 talk_base::AsyncPacketSocket::State FakeUdpSocket::GetState() const { | |
| 116 return state_; | |
| 117 } | |
| 118 | |
| 119 int FakeUdpSocket::GetOption(talk_base::Socket::Option option, int* value) { | |
| 120 NOTIMPLEMENTED(); | |
| 121 return -1; | |
| 122 } | |
| 123 | |
| 124 int FakeUdpSocket::SetOption(talk_base::Socket::Option option, int value) { | |
| 125 NOTIMPLEMENTED(); | |
| 126 return -1; | |
| 127 } | |
| 128 | |
| 129 int FakeUdpSocket::GetError() const { | |
| 130 return 0; | |
| 131 } | |
| 132 | |
| 133 void FakeUdpSocket::SetError(int error) { | |
| 134 NOTREACHED(); | |
| 135 } | |
| 136 | |
| 137 } // namespace | |
| 138 | |
| 139 FakePacketSocketFactory::PendingPacket::PendingPacket() | |
| 140 : data_size(0) { | |
| 141 } | |
| 142 | |
| 143 FakePacketSocketFactory::PendingPacket::PendingPacket( | |
| 144 const talk_base::SocketAddress& from, | |
| 145 const talk_base::SocketAddress& to, | |
| 146 const scoped_refptr<net::IOBuffer>& data, | |
| 147 int data_size) | |
| 148 : from(from), to(to), data(data), data_size(data_size) { | |
| 149 } | |
| 150 | |
| 151 FakePacketSocketFactory::PendingPacket::~PendingPacket() { | |
| 152 } | |
| 153 | |
| 154 FakePacketSocketFactory::FakePacketSocketFactory( | |
| 155 FakeNetworkDispatcher* dispatcher) | |
| 156 : task_runner_(base::ThreadTaskRunnerHandle::Get()), | |
| 157 dispatcher_(dispatcher), | |
| 158 address_(dispatcher_->AllocateAddress()), | |
| 159 out_of_order_rate_(0.0), | |
| 160 next_port_(1000), | |
|
rmsousa
2014/08/12 20:42:10
nit: 1024 (if the intention is to emulate unix "hi
Sergey Ulanov
2014/08/16 00:03:34
Done.
| |
| 161 weak_factory_(this) { | |
| 162 dispatcher_->AddNode(this); | |
| 163 } | |
| 164 | |
| 165 FakePacketSocketFactory::~FakePacketSocketFactory() { | |
| 166 CHECK(udp_sockets_.empty()); | |
| 167 dispatcher_->RemoveNode(this); | |
| 168 } | |
| 169 | |
| 170 void FakePacketSocketFactory::OnSocketDestroyed(int port) { | |
| 171 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 172 udp_sockets_.erase(port); | |
| 173 } | |
| 174 | |
| 175 void FakePacketSocketFactory::SetBandwidth(int bandwidth, int max_buffer) { | |
| 176 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 177 if (bandwidth <= 0) { | |
| 178 leaky_bucket_.reset(); | |
| 179 } else { | |
| 180 leaky_bucket_.reset(new LeakyBucket(max_buffer, bandwidth)); | |
| 181 } | |
| 182 } | |
| 183 | |
| 184 void FakePacketSocketFactory::SetLatency(base::TimeDelta average, | |
| 185 base::TimeDelta variance) { | |
| 186 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 187 latency_average_ = average; | |
| 188 latency_variance_ = variance; | |
| 189 } | |
| 190 | |
| 191 talk_base::AsyncPacketSocket* FakePacketSocketFactory::CreateUdpSocket( | |
| 192 const talk_base::SocketAddress& local_address, | |
| 193 int min_port, int max_port) { | |
| 194 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 195 | |
| 196 int port = -1; | |
| 197 if (min_port > 0 && max_port > 0) { | |
| 198 for (int i = min_port; i <= max_port; ++i) { | |
| 199 if (udp_sockets_.find(i) == udp_sockets_.end()) { | |
| 200 port = i; | |
| 201 break; | |
| 202 } | |
| 203 } | |
| 204 if (port < 0) | |
| 205 return NULL; | |
| 206 } else { | |
| 207 do { | |
| 208 port = next_port_; | |
| 209 next_port_ = (next_port_ == 65535) ? 1000 : next_port_ + 1; | |
|
rmsousa
2014/08/12 20:42:10
nit: 1024 here as well (probably should define a c
Sergey Ulanov
2014/08/16 00:03:34
Done.
| |
| 210 } while (udp_sockets_.find(port) != udp_sockets_.end()); | |
| 211 } | |
| 212 | |
| 213 CHECK(local_address.ipaddr() == address_); | |
| 214 | |
| 215 FakeUdpSocket* result = | |
| 216 new FakeUdpSocket(this, dispatcher_, | |
| 217 talk_base::SocketAddress(local_address.ipaddr(), port)); | |
| 218 | |
| 219 udp_sockets_[port] = | |
| 220 base::Bind(&FakeUdpSocket::ReceivePacket, base::Unretained(result)); | |
| 221 | |
| 222 return result; | |
| 223 } | |
| 224 | |
| 225 talk_base::AsyncPacketSocket* FakePacketSocketFactory::CreateServerTcpSocket( | |
| 226 const talk_base::SocketAddress& local_address, | |
| 227 int min_port, int max_port, | |
| 228 int opts) { | |
| 229 return NULL; | |
| 230 } | |
| 231 | |
| 232 talk_base::AsyncPacketSocket* FakePacketSocketFactory::CreateClientTcpSocket( | |
| 233 const talk_base::SocketAddress& local_address, | |
| 234 const talk_base::SocketAddress& remote_address, | |
| 235 const talk_base::ProxyInfo& proxy_info, | |
| 236 const std::string& user_agent, | |
| 237 int opts) { | |
| 238 return NULL; | |
| 239 } | |
| 240 | |
| 241 talk_base::AsyncResolverInterface* | |
| 242 FakePacketSocketFactory::CreateAsyncResolver() { | |
| 243 return NULL; | |
| 244 } | |
| 245 | |
| 246 const scoped_refptr<base::SingleThreadTaskRunner>& | |
| 247 FakePacketSocketFactory::GetThread() const { | |
| 248 return task_runner_; | |
| 249 } | |
| 250 | |
| 251 const talk_base::IPAddress& FakePacketSocketFactory::GetAddress() const { | |
| 252 return address_; | |
| 253 } | |
| 254 | |
| 255 void FakePacketSocketFactory::ReceivePacket( | |
| 256 const talk_base::SocketAddress& from, | |
| 257 const talk_base::SocketAddress& to, | |
| 258 const scoped_refptr<net::IOBuffer>& data, | |
| 259 int data_size) { | |
| 260 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 261 DCHECK(to.ipaddr() == address_); | |
| 262 | |
| 263 base::TimeDelta delay; | |
| 264 | |
| 265 if (leaky_bucket_) { | |
| 266 delay = leaky_bucket_->AddPacket(data_size); | |
| 267 if (delay.is_max()) { | |
| 268 // Drop the packet. | |
| 269 return; | |
| 270 } | |
| 271 } | |
| 272 | |
| 273 if (latency_average_ > base::TimeDelta()) { | |
| 274 delay += base::TimeDelta::FromMillisecondsD( | |
| 275 GetNormalRandom(latency_average_.InMillisecondsF(), | |
| 276 latency_variance_.InMillisecondsF())); | |
| 277 } | |
| 278 if (delay < base::TimeDelta()) | |
| 279 delay = base::TimeDelta(); | |
| 280 | |
| 281 PendingPacket packet(from, to, data, data_size); | |
| 282 pending_packets_.push_back(packet); | |
| 283 task_runner_->PostDelayedTask( | |
| 284 FROM_HERE, | |
| 285 base::Bind(&FakePacketSocketFactory::DoReceivePacket, | |
|
rmsousa
2014/08/12 20:42:10
This is a bit weird - since delay has a random com
Sergey Ulanov
2014/08/16 00:03:34
Yes, that's by design. I actually implemented it w
| |
| 286 weak_factory_.GetWeakPtr()), | |
| 287 delay); | |
| 288 } | |
| 289 | |
| 290 void FakePacketSocketFactory::DoReceivePacket() { | |
| 291 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 292 | |
| 293 PendingPacket packet; | |
| 294 if (pending_packets_.size() > 1 && base::RandDouble() < out_of_order_rate_) { | |
| 295 std::list<PendingPacket>::iterator it = pending_packets_.begin(); | |
| 296 ++it; | |
| 297 packet = *it; | |
| 298 pending_packets_.erase(it); | |
| 299 } else { | |
| 300 packet = pending_packets_.front(); | |
| 301 pending_packets_.pop_front(); | |
| 302 } | |
| 303 | |
| 304 UdpSocketsMap::iterator iter = udp_sockets_.find(packet.to.port()); | |
| 305 if (iter == udp_sockets_.end()) { | |
| 306 // Invalid port number. | |
| 307 return; | |
| 308 } | |
| 309 | |
| 310 iter->second.Run(packet.from, packet.to, packet.data, packet.data_size); | |
| 311 } | |
| 312 | |
| 313 } // namespace remoting | |
| OLD | NEW |