Skip to content

Commit

Permalink
Implement network performance simulation for remoting perf tests.
Browse files Browse the repository at this point in the history
The new FakePacketSocketFactory allows to simulate fake 
network with given latency/bandwidth parameters.

BUG=394067

Review URL: https://codereview.chromium.org/427613005

Cr-Commit-Position: refs/heads/master@{#290128}
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@290128 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
sergeyu@chromium.org committed Aug 16, 2014
1 parent c4f1833 commit c44593f
Show file tree
Hide file tree
Showing 12 changed files with 1,064 additions and 24 deletions.
10 changes: 10 additions & 0 deletions remoting/remoting_test.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,16 @@
'signaling/fake_signal_strategy.h',
'signaling/mock_signal_strategy.cc',
'signaling/mock_signal_strategy.h',
'test/fake_network_dispatcher.cc',
'test/fake_network_dispatcher.h',
'test/fake_network_manager.cc',
'test/fake_network_manager.h',
'test/fake_port_allocator.cc',
'test/fake_port_allocator.h',
'test/fake_socket_factory.cc',
'test/fake_socket_factory.h',
'test/leaky_bucket.cc',
'test/leaky_bucket.h',
],
'conditions': [
['enable_remoting_host == 0', {
Expand Down
88 changes: 88 additions & 0 deletions remoting/test/fake_network_dispatcher.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// 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_network_dispatcher.h"

#include "base/bind.h"
#include "base/location.h"
#include "base/single_thread_task_runner.h"
#include "net/base/io_buffer.h"

namespace remoting {

FakeNetworkDispatcher::FakeNetworkDispatcher()
: allocated_address_(0) {
}

FakeNetworkDispatcher::~FakeNetworkDispatcher() {
CHECK(nodes_.empty());
}

rtc::IPAddress FakeNetworkDispatcher::AllocateAddress() {
in6_addr addr;
memset(&addr, 0, sizeof(addr));

// fc00::/7 is reserved for unique local addresses.
addr.s6_addr[0] = 0xfc;

// Copy |allocated_address_| to the end of |addr|.
++allocated_address_;
for (size_t i = 0; i < sizeof(allocated_address_); ++i) {
addr.s6_addr[15 - i] = (allocated_address_ >> (8 * i)) & 0xff;
}

return rtc::IPAddress(addr);
}

void FakeNetworkDispatcher::AddNode(Node* node) {
DCHECK(node->GetThread()->BelongsToCurrentThread());

base::AutoLock auto_lock(nodes_lock_);
DCHECK(nodes_.find(node->GetAddress()) == nodes_.end());
nodes_[node->GetAddress()] = node;
}

void FakeNetworkDispatcher::RemoveNode(Node* node) {
DCHECK(node->GetThread()->BelongsToCurrentThread());

base::AutoLock auto_lock(nodes_lock_);
DCHECK(nodes_[node->GetAddress()] == node);
nodes_.erase(node->GetAddress());
}

void FakeNetworkDispatcher::DeliverPacket(
const rtc::SocketAddress& from,
const rtc::SocketAddress& to,
const scoped_refptr<net::IOBuffer>& data,
int data_size) {
Node* node;
{
base::AutoLock auto_lock(nodes_lock_);

NodesMap::iterator node_it = nodes_.find(to.ipaddr());
if (node_it == nodes_.end()) {
LOG(ERROR) << "Tried to deliver packet to unknown target: "
<< to.ToString();
return;
}

node = node_it->second;

// Check if |node| belongs to a different thread and post a task in that
// case.
scoped_refptr<base::SingleThreadTaskRunner> task_runner = node->GetThread();
if (!task_runner->BelongsToCurrentThread()) {
task_runner->PostTask(FROM_HERE,
base::Bind(&FakeNetworkDispatcher::DeliverPacket,
this, from, to, data, data_size));
return;
}
}

// Call ReceivePacket() without lock held. It's safe because at this point we
// know that |node| belongs to the current thread.
node->ReceivePacket(from, to, data, data_size);
}

} // namespace remoting
74 changes: 74 additions & 0 deletions remoting/test/fake_network_dispatcher.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// 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.

#ifndef REMOTING_TEST_FAKE_NETWORK_DISPATCHER_H_
#define REMOTING_TEST_FAKE_NETWORK_DISPATCHER_H_

#include <map>

#include "base/compiler_specific.h"
#include "base/memory/ref_counted.h"
#include "base/synchronization/lock.h"
#include "third_party/libjingle/source/talk/p2p/base/packetsocketfactory.h"

namespace base {
class SingleThreadTaskRunner;
} // namespace base

namespace net {
class IOBuffer;
} // namespace net

namespace remoting {

class FakeNetworkDispatcher
: public base::RefCountedThreadSafe<FakeNetworkDispatcher> {
public:
class Node {
public:
virtual ~Node() {};

// Return thread on which ReceivePacket() should be called.
virtual const scoped_refptr<base::SingleThreadTaskRunner>& GetThread()
const = 0;
virtual const rtc::IPAddress& GetAddress() const = 0;

// Deliver a packet sent by a different node.
virtual void ReceivePacket(const rtc::SocketAddress& from,
const rtc::SocketAddress& to,
const scoped_refptr<net::IOBuffer>& data,
int data_size) = 0;
};

FakeNetworkDispatcher();

rtc::IPAddress AllocateAddress();

// Must be called on the thread that the |node| works on.
void AddNode(Node* node);
void RemoveNode(Node* node);

void DeliverPacket(const rtc::SocketAddress& from,
const rtc::SocketAddress& to,
const scoped_refptr<net::IOBuffer>& data,
int data_size);

private:
typedef std::map<rtc::IPAddress, Node*> NodesMap;

friend class base::RefCountedThreadSafe<FakeNetworkDispatcher>;
virtual ~FakeNetworkDispatcher();

NodesMap nodes_;
base::Lock nodes_lock_;

// A counter used to allocate unique addresses in AllocateAddress().
int allocated_address_;

DISALLOW_COPY_AND_ASSIGN(FakeNetworkDispatcher);
};

} // namespace remoting

#endif // REMOTING_TEST_FAKE_NETWORK_DISPATCHER_H_
46 changes: 46 additions & 0 deletions remoting/test/fake_network_manager.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// 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_network_manager.h"

#include "base/bind.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "jingle/glue/utils.h"
#include "third_party/webrtc/base/socketaddress.h"

namespace remoting {

FakeNetworkManager::FakeNetworkManager(const rtc::IPAddress& address)
: started_(false),
weak_factory_(this) {
network_.reset(new rtc::Network("fake", "Fake Network", address, 32));
network_->AddIP(address);
}

FakeNetworkManager::~FakeNetworkManager() {
}

void FakeNetworkManager::StartUpdating() {
started_ = true;
base::MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(&FakeNetworkManager::SendNetworksChangedSignal,
weak_factory_.GetWeakPtr()));
}

void FakeNetworkManager::StopUpdating() {
started_ = false;
}

void FakeNetworkManager::GetNetworks(NetworkList* networks) const {
networks->clear();
networks->push_back(network_.get());
}

void FakeNetworkManager::SendNetworksChangedSignal() {
SignalNetworksChanged();
}

} // namespace remoting
37 changes: 37 additions & 0 deletions remoting/test/fake_network_manager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// 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.

#ifndef REMOTING_TEST_FAKE_NETWORK_MANAGER_H_
#define REMOTING_TEST_FAKE_NETWORK_MANAGER_H_

#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "third_party/webrtc/base/network.h"

namespace remoting {

// FakeNetworkManager always returns one interface with the IP address
// specified in the constructor.
class FakeNetworkManager : public rtc::NetworkManager {
public:
FakeNetworkManager(const rtc::IPAddress& address);
virtual ~FakeNetworkManager();

// rtc::NetworkManager interface.
virtual void StartUpdating() OVERRIDE;
virtual void StopUpdating() OVERRIDE;
virtual void GetNetworks(NetworkList* networks) const OVERRIDE;

protected:
void SendNetworksChangedSignal();

bool started_;
scoped_ptr<rtc::Network> network_;

base::WeakPtrFactory<FakeNetworkManager> weak_factory_;
};

} // namespace remoting

#endif // REMOTING_TEST_FAKE_NETWORK_MANAGER_H_
124 changes: 124 additions & 0 deletions remoting/test/fake_port_allocator.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// 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_port_allocator.h"

#include "remoting/test/fake_network_dispatcher.h"
#include "remoting/test/fake_network_manager.h"
#include "remoting/test/fake_socket_factory.h"

namespace remoting {

namespace {

class FakePortAllocatorSession
: public cricket::HttpPortAllocatorSessionBase {
public:
FakePortAllocatorSession(
cricket::HttpPortAllocatorBase* allocator,
const std::string& content_name,
int component,
const std::string& ice_username_fragment,
const std::string& ice_password,
const std::vector<rtc::SocketAddress>& stun_hosts,
const std::vector<std::string>& relay_hosts,
const std::string& relay);
virtual ~FakePortAllocatorSession();

// cricket::HttpPortAllocatorBase overrides.
virtual void ConfigReady(cricket::PortConfiguration* config) OVERRIDE;
virtual void SendSessionRequest(const std::string& host, int port) OVERRIDE;

private:
DISALLOW_COPY_AND_ASSIGN(FakePortAllocatorSession);
};

FakePortAllocatorSession::FakePortAllocatorSession(
cricket::HttpPortAllocatorBase* allocator,
const std::string& content_name,
int component,
const std::string& ice_username_fragment,
const std::string& ice_password,
const std::vector<rtc::SocketAddress>& stun_hosts,
const std::vector<std::string>& relay_hosts,
const std::string& relay)
: HttpPortAllocatorSessionBase(allocator,
content_name,
component,
ice_username_fragment,
ice_password,
stun_hosts,
relay_hosts,
relay,
std::string()) {
set_flags(cricket::PORTALLOCATOR_DISABLE_TCP |
cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
cricket::PORTALLOCATOR_ENABLE_IPV6 |
cricket::PORTALLOCATOR_DISABLE_STUN |
cricket::PORTALLOCATOR_DISABLE_RELAY);
}

FakePortAllocatorSession::~FakePortAllocatorSession() {
}

void FakePortAllocatorSession::ConfigReady(
cricket::PortConfiguration* config) {
// Filter out non-UDP relay ports, so that we don't try using TCP.
for (cricket::PortConfiguration::RelayList::iterator relay =
config->relays.begin(); relay != config->relays.end(); ++relay) {
cricket::PortList filtered_ports;
for (cricket::PortList::iterator port =
relay->ports.begin(); port != relay->ports.end(); ++port) {
if (port->proto == cricket::PROTO_UDP) {
filtered_ports.push_back(*port);
}
}
relay->ports = filtered_ports;
}
cricket::BasicPortAllocatorSession::ConfigReady(config);
}

void FakePortAllocatorSession::SendSessionRequest(
const std::string& host,
int port) {
ReceiveSessionResponse(std::string());
}

} // namespace

// static
scoped_ptr<FakePortAllocator> FakePortAllocator::Create(
scoped_refptr<FakeNetworkDispatcher> fake_network_dispatcher) {
scoped_ptr<FakePacketSocketFactory> socket_factory(
new FakePacketSocketFactory(fake_network_dispatcher));
scoped_ptr<rtc::NetworkManager> network_manager(
new FakeNetworkManager(socket_factory->GetAddress()));

return scoped_ptr<FakePortAllocator>(
new FakePortAllocator(network_manager.Pass(), socket_factory.Pass()));
}

FakePortAllocator::FakePortAllocator(
scoped_ptr<rtc::NetworkManager> network_manager,
scoped_ptr<FakePacketSocketFactory> socket_factory)
: HttpPortAllocatorBase(network_manager.get(),
socket_factory.get(),
std::string()),
network_manager_(network_manager.Pass()),
socket_factory_(socket_factory.Pass()) {}

FakePortAllocator::~FakePortAllocator() {
}

cricket::PortAllocatorSession* FakePortAllocator::CreateSessionInternal(
const std::string& content_name,
int component,
const std::string& ice_username_fragment,
const std::string& ice_password) {
return new FakePortAllocatorSession(
this, content_name, component, ice_username_fragment, ice_password,
stun_hosts(), relay_hosts(), relay_token());
}

} // namespace remoting
Loading

0 comments on commit c44593f

Please sign in to comment.