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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: remoting/test/fake_socket_factory.cc
diff --git a/remoting/test/fake_socket_factory.cc b/remoting/test/fake_socket_factory.cc
new file mode 100644
index 0000000000000000000000000000000000000000..63a804235b4e8992ae4c5e2347aa787e431f8f43
--- /dev/null
+++ b/remoting/test/fake_socket_factory.cc
@@ -0,0 +1,313 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "remoting/test/fake_socket_factory.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/location.h"
+#include "base/rand_util.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
+#include "net/base/io_buffer.h"
+#include "remoting/test/leaky_bucket.h"
+#include "third_party/libjingle/source/talk/base/asyncpacketsocket.h"
+
+namespace remoting {
+
+namespace {
+
+double GetNormalRandom(double average, double variance) {
+ // Based on Box-Muller transform, see
+ // http://en.wikipedia.org/wiki/Box_Muller_transform .
+ return average +
+ 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.
+ cos(base::RandDouble() * 2.0 * M_PI);
+}
+
+class FakeUdpSocket : public talk_base::AsyncPacketSocket {
+ public:
+ FakeUdpSocket(FakePacketSocketFactory* factory,
+ scoped_refptr<FakeNetworkDispatcher> dispatcher,
+ const talk_base::SocketAddress& local_address);
+ virtual ~FakeUdpSocket();
+
+ void ReceivePacket(const talk_base::SocketAddress& from,
+ const talk_base::SocketAddress& to,
+ const scoped_refptr<net::IOBuffer>& data,
+ int data_size);
+
+ // talk_base::AsyncPacketSocket interface.
+ virtual talk_base::SocketAddress GetLocalAddress() const OVERRIDE;
+ virtual talk_base::SocketAddress GetRemoteAddress() const OVERRIDE;
+ virtual int Send(const void* data, size_t data_size,
+ const talk_base::PacketOptions& options) OVERRIDE;
+ virtual int SendTo(const void* data, size_t data_size,
+ const talk_base::SocketAddress& address,
+ const talk_base::PacketOptions& options) OVERRIDE;
+ virtual int Close() OVERRIDE;
+ virtual State GetState() const OVERRIDE;
+ virtual int GetOption(talk_base::Socket::Option option, int* value) OVERRIDE;
+ virtual int SetOption(talk_base::Socket::Option option, int value) OVERRIDE;
+ virtual int GetError() const OVERRIDE;
+ virtual void SetError(int error) OVERRIDE;
+
+ private:
+ FakePacketSocketFactory* factory_;
+ scoped_refptr<FakeNetworkDispatcher> dispatcher_;
+ talk_base::SocketAddress local_address_;
+ State state_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeUdpSocket);
+};
+
+FakeUdpSocket::FakeUdpSocket(FakePacketSocketFactory* factory,
+ scoped_refptr<FakeNetworkDispatcher> dispatcher,
+ const talk_base::SocketAddress& local_address)
+ : factory_(factory),
+ dispatcher_(dispatcher),
+ local_address_(local_address),
+ state_(STATE_BOUND) {
+}
+
+FakeUdpSocket::~FakeUdpSocket() {
+ factory_->OnSocketDestroyed(local_address_.port());
+}
+
+void FakeUdpSocket::ReceivePacket(const talk_base::SocketAddress& from,
+ const talk_base::SocketAddress& to,
+ const scoped_refptr<net::IOBuffer>& data,
+ int data_size) {
+ SignalReadPacket(
+ this, data->data(), data_size, from, talk_base::CreatePacketTime(0));
+}
+
+talk_base::SocketAddress FakeUdpSocket::GetLocalAddress() const {
+ return local_address_;
+}
+
+talk_base::SocketAddress FakeUdpSocket::GetRemoteAddress() const {
+ NOTREACHED();
+ return talk_base::SocketAddress();
+}
+
+int FakeUdpSocket::Send(const void* data, size_t data_size,
+ const talk_base::PacketOptions& options) {
+ NOTREACHED();
+ return EINVAL;
+}
+
+int FakeUdpSocket::SendTo(const void* data, size_t data_size,
+ const talk_base::SocketAddress& address,
+ const talk_base::PacketOptions& options) {
+ scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(data_size);
+ memcpy(buffer->data(), data, data_size);
+ dispatcher_->DeliverPacket(local_address_, address, buffer, data_size);
+ return data_size;
+}
+
+int FakeUdpSocket::Close() {
+ state_ = STATE_CLOSED;
+ return 0;
+}
+
+talk_base::AsyncPacketSocket::State FakeUdpSocket::GetState() const {
+ return state_;
+}
+
+int FakeUdpSocket::GetOption(talk_base::Socket::Option option, int* value) {
+ NOTIMPLEMENTED();
+ return -1;
+}
+
+int FakeUdpSocket::SetOption(talk_base::Socket::Option option, int value) {
+ NOTIMPLEMENTED();
+ return -1;
+}
+
+int FakeUdpSocket::GetError() const {
+ return 0;
+}
+
+void FakeUdpSocket::SetError(int error) {
+ NOTREACHED();
+}
+
+} // namespace
+
+FakePacketSocketFactory::PendingPacket::PendingPacket()
+ : data_size(0) {
+}
+
+FakePacketSocketFactory::PendingPacket::PendingPacket(
+ const talk_base::SocketAddress& from,
+ const talk_base::SocketAddress& to,
+ const scoped_refptr<net::IOBuffer>& data,
+ int data_size)
+ : from(from), to(to), data(data), data_size(data_size) {
+}
+
+FakePacketSocketFactory::PendingPacket::~PendingPacket() {
+}
+
+FakePacketSocketFactory::FakePacketSocketFactory(
+ FakeNetworkDispatcher* dispatcher)
+ : task_runner_(base::ThreadTaskRunnerHandle::Get()),
+ dispatcher_(dispatcher),
+ address_(dispatcher_->AllocateAddress()),
+ out_of_order_rate_(0.0),
+ 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.
+ weak_factory_(this) {
+ dispatcher_->AddNode(this);
+}
+
+FakePacketSocketFactory::~FakePacketSocketFactory() {
+ CHECK(udp_sockets_.empty());
+ dispatcher_->RemoveNode(this);
+}
+
+void FakePacketSocketFactory::OnSocketDestroyed(int port) {
+ DCHECK(task_runner_->BelongsToCurrentThread());
+ udp_sockets_.erase(port);
+}
+
+void FakePacketSocketFactory::SetBandwidth(int bandwidth, int max_buffer) {
+ DCHECK(task_runner_->BelongsToCurrentThread());
+ if (bandwidth <= 0) {
+ leaky_bucket_.reset();
+ } else {
+ leaky_bucket_.reset(new LeakyBucket(max_buffer, bandwidth));
+ }
+}
+
+void FakePacketSocketFactory::SetLatency(base::TimeDelta average,
+ base::TimeDelta variance) {
+ DCHECK(task_runner_->BelongsToCurrentThread());
+ latency_average_ = average;
+ latency_variance_ = variance;
+}
+
+talk_base::AsyncPacketSocket* FakePacketSocketFactory::CreateUdpSocket(
+ const talk_base::SocketAddress& local_address,
+ int min_port, int max_port) {
+ DCHECK(task_runner_->BelongsToCurrentThread());
+
+ int port = -1;
+ if (min_port > 0 && max_port > 0) {
+ for (int i = min_port; i <= max_port; ++i) {
+ if (udp_sockets_.find(i) == udp_sockets_.end()) {
+ port = i;
+ break;
+ }
+ }
+ if (port < 0)
+ return NULL;
+ } else {
+ do {
+ port = next_port_;
+ 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.
+ } while (udp_sockets_.find(port) != udp_sockets_.end());
+ }
+
+ CHECK(local_address.ipaddr() == address_);
+
+ FakeUdpSocket* result =
+ new FakeUdpSocket(this, dispatcher_,
+ talk_base::SocketAddress(local_address.ipaddr(), port));
+
+ udp_sockets_[port] =
+ base::Bind(&FakeUdpSocket::ReceivePacket, base::Unretained(result));
+
+ return result;
+}
+
+talk_base::AsyncPacketSocket* FakePacketSocketFactory::CreateServerTcpSocket(
+ const talk_base::SocketAddress& local_address,
+ int min_port, int max_port,
+ int opts) {
+ return NULL;
+}
+
+talk_base::AsyncPacketSocket* FakePacketSocketFactory::CreateClientTcpSocket(
+ const talk_base::SocketAddress& local_address,
+ const talk_base::SocketAddress& remote_address,
+ const talk_base::ProxyInfo& proxy_info,
+ const std::string& user_agent,
+ int opts) {
+ return NULL;
+}
+
+talk_base::AsyncResolverInterface*
+FakePacketSocketFactory::CreateAsyncResolver() {
+ return NULL;
+}
+
+const scoped_refptr<base::SingleThreadTaskRunner>&
+FakePacketSocketFactory::GetThread() const {
+ return task_runner_;
+}
+
+const talk_base::IPAddress& FakePacketSocketFactory::GetAddress() const {
+ return address_;
+}
+
+void FakePacketSocketFactory::ReceivePacket(
+ const talk_base::SocketAddress& from,
+ const talk_base::SocketAddress& to,
+ const scoped_refptr<net::IOBuffer>& data,
+ int data_size) {
+ DCHECK(task_runner_->BelongsToCurrentThread());
+ DCHECK(to.ipaddr() == address_);
+
+ base::TimeDelta delay;
+
+ if (leaky_bucket_) {
+ delay = leaky_bucket_->AddPacket(data_size);
+ if (delay.is_max()) {
+ // Drop the packet.
+ return;
+ }
+ }
+
+ if (latency_average_ > base::TimeDelta()) {
+ delay += base::TimeDelta::FromMillisecondsD(
+ GetNormalRandom(latency_average_.InMillisecondsF(),
+ latency_variance_.InMillisecondsF()));
+ }
+ if (delay < base::TimeDelta())
+ delay = base::TimeDelta();
+
+ PendingPacket packet(from, to, data, data_size);
+ pending_packets_.push_back(packet);
+ task_runner_->PostDelayedTask(
+ FROM_HERE,
+ 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
+ weak_factory_.GetWeakPtr()),
+ delay);
+}
+
+void FakePacketSocketFactory::DoReceivePacket() {
+ DCHECK(task_runner_->BelongsToCurrentThread());
+
+ PendingPacket packet;
+ if (pending_packets_.size() > 1 && base::RandDouble() < out_of_order_rate_) {
+ std::list<PendingPacket>::iterator it = pending_packets_.begin();
+ ++it;
+ packet = *it;
+ pending_packets_.erase(it);
+ } else {
+ packet = pending_packets_.front();
+ pending_packets_.pop_front();
+ }
+
+ UdpSocketsMap::iterator iter = udp_sockets_.find(packet.to.port());
+ if (iter == udp_sockets_.end()) {
+ // Invalid port number.
+ return;
+ }
+
+ iter->second.Run(packet.from, packet.to, packet.data, packet.data_size);
+}
+
+} // namespace remoting

Powered by Google App Engine
This is Rietveld 408576698