Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(977)

Side by Side Diff: remoting/test/fake_socket_factory.cc

Issue 427613005: Implement network performance simulation for remoting perf tests. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698