Introduce dynamic endpoints

Bug: webrtc:10138
Change-Id: I7f6922adb93680cada6bea014539fc3089735834
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/128480
Reviewed-by: Sebastian Jansson <srte@webrtc.org>
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Commit-Queue: Artem Titov <titovartem@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#27336}
diff --git a/api/test/network_emulation_manager.h b/api/test/network_emulation_manager.h
index 3cb329c..0049eb6 100644
--- a/api/test/network_emulation_manager.h
+++ b/api/test/network_emulation_manager.h
@@ -46,6 +46,19 @@
   // If specified will be used as IP address for endpoint node. Must be unique
   // among all created nodes.
   absl::optional<rtc::IPAddress> ip;
+  // Should endpoint be enabled or not, when it will be created.
+  // Enabled endpoints will be available for webrtc to send packets.
+  bool start_as_enabled = true;
+};
+
+// Provide interface to obtain all required objects to inject network emulation
+// layer into PeerConnection.
+class EmulatedNetworkManagerInterface {
+ public:
+  virtual ~EmulatedNetworkManagerInterface() = default;
+
+  virtual rtc::Thread* network_thread() = 0;
+  virtual rtc::NetworkManager* network_manager() = 0;
 };
 
 // Provides an API for creating and configuring emulated network layer.
@@ -63,6 +76,12 @@
   // Creates an emulated endpoint, which represents single network interface on
   // the peer's device.
   virtual EmulatedEndpoint* CreateEndpoint(EmulatedEndpointConfig config) = 0;
+  // Enable emulated endpoint to make it available for webrtc.
+  // Caller mustn't enable currently enabled endpoint.
+  virtual void EnableEndpoint(EmulatedEndpoint* endpoint) = 0;
+  // Disable emulated endpoint to make it unavailable for webrtc.
+  // Caller mustn't disable currently disabled endpoint.
+  virtual void DisableEndpoint(EmulatedEndpoint* endpoint) = 0;
 
   // Creates a route between endpoints going through specified network nodes.
   // This route is single direction only and describe how traffic that was
@@ -88,16 +107,13 @@
   // removed earlier.
   virtual void ClearRoute(EmulatedRoute* route) = 0;
 
-  // Creates rtc::Thread that should be used as network thread for peer
-  // connection. Created thread contains special rtc::SocketServer inside it
-  // to enable correct integration between peer connection and emulated network
-  // layer.
-  virtual rtc::Thread* CreateNetworkThread(
-      const std::vector<EmulatedEndpoint*>& endpoints) = 0;
-  // Creates rtc::NetworkManager that should be used inside
-  // cricket::PortAllocator for peer connection to provide correct list of
-  // network interfaces, that exists in emulated network later.
-  virtual rtc::NetworkManager* CreateNetworkManager(
+  // Creates EmulatedNetworkManagerInterface which can be used then to inject
+  // network emulation layer into PeerConnection. |endpoints| - are available
+  // network interfaces for PeerConnection. If endpoint is enabled, it will be
+  // immediately available for PeerConnection, otherwise user will be able to
+  // enable endpoint later to make it available for PeerConnection.
+  virtual EmulatedNetworkManagerInterface*
+  CreateEmulatedNetworkManagerInterface(
       const std::vector<EmulatedEndpoint*>& endpoints) = 0;
 };
 
diff --git a/test/pc/e2e/peer_connection_e2e_smoke_test.cc b/test/pc/e2e/peer_connection_e2e_smoke_test.cc
index 75eb472..6c566e4 100644
--- a/test/pc/e2e/peer_connection_e2e_smoke_test.cc
+++ b/test/pc/e2e/peer_connection_e2e_smoke_test.cc
@@ -75,25 +75,27 @@
 
   // Setup components. We need to provide rtc::NetworkManager compatible with
   // emulated network layer.
-  fixture->AddPeer(
-      network_emulation_manager->CreateNetworkThread({alice_endpoint}),
-      network_emulation_manager->CreateNetworkManager({alice_endpoint}),
-      [](PeerConfigurer* alice) {
-        VideoConfig alice_video_config(640, 360, 30);
-        alice_video_config.stream_label = "alice-video";
-        alice->AddVideoConfig(std::move(alice_video_config));
-        alice->SetAudioConfig(AudioConfig());
-      });
+  EmulatedNetworkManagerInterface* alice_network =
+      network_emulation_manager->CreateEmulatedNetworkManagerInterface(
+          {alice_endpoint});
+  fixture->AddPeer(alice_network->network_thread(),
+                   alice_network->network_manager(), [](PeerConfigurer* alice) {
+                     VideoConfig alice_video_config(640, 360, 30);
+                     alice_video_config.stream_label = "alice-video";
+                     alice->AddVideoConfig(std::move(alice_video_config));
+                     alice->SetAudioConfig(AudioConfig());
+                   });
 
-  fixture->AddPeer(
-      network_emulation_manager->CreateNetworkThread({bob_endpoint}),
-      network_emulation_manager->CreateNetworkManager({bob_endpoint}),
-      [](PeerConfigurer* bob) {
-        VideoConfig bob_video_config(640, 360, 30);
-        bob_video_config.stream_label = "bob-video";
-        bob->AddVideoConfig(std::move(bob_video_config));
-        bob->SetAudioConfig(AudioConfig());
-      });
+  EmulatedNetworkManagerInterface* bob_network =
+      network_emulation_manager->CreateEmulatedNetworkManagerInterface(
+          {bob_endpoint});
+  fixture->AddPeer(bob_network->network_thread(),
+                   bob_network->network_manager(), [](PeerConfigurer* bob) {
+                     VideoConfig bob_video_config(640, 360, 30);
+                     bob_video_config.stream_label = "bob-video";
+                     bob->AddVideoConfig(std::move(bob_video_config));
+                     bob->SetAudioConfig(AudioConfig());
+                   });
 
   fixture->Run(RunParams{TimeDelta::seconds(5)});
 
diff --git a/test/scenario/network/BUILD.gn b/test/scenario/network/BUILD.gn
index dc01f79..fb3dd3e 100644
--- a/test/scenario/network/BUILD.gn
+++ b/test/scenario/network/BUILD.gn
@@ -13,6 +13,8 @@
   sources = [
     "cross_traffic.cc",
     "cross_traffic.h",
+    "emulated_network_manager.cc",
+    "emulated_network_manager.h",
     "fake_network_socket.cc",
     "fake_network_socket.h",
     "fake_network_socket_server.cc",
diff --git a/test/scenario/network/emulated_network_manager.cc b/test/scenario/network/emulated_network_manager.cc
new file mode 100644
index 0000000..539ed41
--- /dev/null
+++ b/test/scenario/network/emulated_network_manager.cc
@@ -0,0 +1,108 @@
+/*
+ *  Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "test/scenario/network/emulated_network_manager.h"
+
+#include <memory>
+#include <utility>
+
+#include "absl/memory/memory.h"
+
+namespace webrtc {
+namespace test {
+
+EmulatedNetworkManager::EmulatedNetworkManager(
+    Clock* clock,
+    EndpointsContainer* endpoints_controller)
+    : endpoints_controller_(endpoints_controller),
+      socket_server_(clock, endpoints_controller),
+      network_thread_(&socket_server_),
+      sent_first_update_(false),
+      start_count_(0) {
+  network_thread_.SetName("net_thread", nullptr);
+  network_thread_.Start();
+}
+
+void EmulatedNetworkManager::EnableEndpoint(EmulatedEndpoint* endpoint) {
+  RTC_CHECK(endpoints_controller_->HasEndpoint(endpoint))
+      << "No such interface: " << endpoint->GetPeerLocalAddress().ToString();
+  network_thread_.PostTask(RTC_FROM_HERE, [this, endpoint]() {
+    endpoint->Enable();
+    UpdateNetworksOnce();
+  });
+}
+
+void EmulatedNetworkManager::DisableEndpoint(EmulatedEndpoint* endpoint) {
+  RTC_CHECK(endpoints_controller_->HasEndpoint(endpoint))
+      << "No such interface: " << endpoint->GetPeerLocalAddress().ToString();
+  network_thread_.PostTask(RTC_FROM_HERE, [this, endpoint]() {
+    endpoint->Disable();
+    UpdateNetworksOnce();
+  });
+}
+
+// Network manager interface. All these methods are supposed to be called from
+// the same thread.
+void EmulatedNetworkManager::StartUpdating() {
+  RTC_DCHECK_RUN_ON(&network_thread_);
+
+  if (start_count_) {
+    // If network interfaces are already discovered and signal is sent,
+    // we should trigger network signal immediately for the new clients
+    // to start allocating ports.
+    if (sent_first_update_)
+      network_thread_.PostTask(RTC_FROM_HERE,
+                               [this]() { MaybeSignalNetworksChanged(); });
+  } else {
+    network_thread_.PostTask(RTC_FROM_HERE, [this]() { UpdateNetworksOnce(); });
+  }
+  ++start_count_;
+}
+
+void EmulatedNetworkManager::StopUpdating() {
+  RTC_DCHECK_RUN_ON(&network_thread_);
+  if (!start_count_)
+    return;
+
+  --start_count_;
+  if (!start_count_) {
+    sent_first_update_ = false;
+  }
+}
+
+void EmulatedNetworkManager::UpdateNetworksOnce() {
+  RTC_DCHECK_RUN_ON(&network_thread_);
+
+  std::vector<rtc::Network*> networks;
+  for (std::unique_ptr<rtc::Network>& net :
+       endpoints_controller_->GetEnabledNetworks()) {
+    net->set_default_local_address_provider(this);
+    networks.push_back(net.release());
+  }
+
+  bool changed;
+  MergeNetworkList(networks, &changed);
+  if (changed || !sent_first_update_) {
+    MaybeSignalNetworksChanged();
+    sent_first_update_ = true;
+  }
+}
+
+void EmulatedNetworkManager::MaybeSignalNetworksChanged() {
+  RTC_DCHECK_RUN_ON(&network_thread_);
+  // If manager is stopped we don't need to signal anything.
+  if (start_count_ == 0) {
+    return;
+  }
+  SignalNetworksChanged();
+}
+
+}  // namespace test
+}  // namespace webrtc
diff --git a/test/scenario/network/emulated_network_manager.h b/test/scenario/network/emulated_network_manager.h
new file mode 100644
index 0000000..27ba2f5
--- /dev/null
+++ b/test/scenario/network/emulated_network_manager.h
@@ -0,0 +1,65 @@
+/*
+ *  Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef TEST_SCENARIO_NETWORK_EMULATED_NETWORK_MANAGER_H_
+#define TEST_SCENARIO_NETWORK_EMULATED_NETWORK_MANAGER_H_
+
+#include <memory>
+#include <vector>
+
+#include "api/test/network_emulation_manager.h"
+#include "rtc_base/critical_section.h"
+#include "rtc_base/ip_address.h"
+#include "rtc_base/network.h"
+#include "rtc_base/socket_server.h"
+#include "rtc_base/thread.h"
+#include "rtc_base/thread_checker.h"
+#include "test/scenario/network/fake_network_socket_server.h"
+#include "test/scenario/network/network_emulation.h"
+
+namespace webrtc {
+namespace test {
+
+// Framework assumes that rtc::NetworkManager is called from network thread.
+class EmulatedNetworkManager : public rtc::NetworkManagerBase,
+                               public sigslot::has_slots<>,
+                               public EmulatedNetworkManagerInterface {
+ public:
+  EmulatedNetworkManager(Clock* clock,
+                         EndpointsContainer* endpoints_controller);
+
+  void EnableEndpoint(EmulatedEndpoint* endpoint);
+  void DisableEndpoint(EmulatedEndpoint* endpoint);
+
+  // NetworkManager interface. All these methods are supposed to be called from
+  // the same thread.
+  void StartUpdating() override;
+  void StopUpdating() override;
+
+  // EmulatedNetworkManagerInterface API
+  rtc::Thread* network_thread() override { return &network_thread_; }
+  rtc::NetworkManager* network_manager() override { return this; }
+
+ private:
+  void UpdateNetworksOnce();
+  void MaybeSignalNetworksChanged();
+
+  EndpointsContainer* const endpoints_controller_;
+  FakeNetworkSocketServer socket_server_;
+  rtc::Thread network_thread_;
+
+  bool sent_first_update_ RTC_GUARDED_BY(network_thread_);
+  int start_count_ RTC_GUARDED_BY(network_thread_);
+};
+
+}  // namespace test
+}  // namespace webrtc
+
+#endif  // TEST_SCENARIO_NETWORK_EMULATED_NETWORK_MANAGER_H_
diff --git a/test/scenario/network/fake_network_socket_server.cc b/test/scenario/network/fake_network_socket_server.cc
index 6447e65..bce1206 100644
--- a/test/scenario/network/fake_network_socket_server.cc
+++ b/test/scenario/network/fake_network_socket_server.cc
@@ -17,9 +17,9 @@
 
 FakeNetworkSocketServer::FakeNetworkSocketServer(
     Clock* clock,
-    std::vector<EmulatedEndpoint*> endpoints)
+    EndpointsContainer* endpoints_container)
     : clock_(clock),
-      endpoints_(std::move(endpoints)),
+      endpoints_container_(endpoints_container),
       wakeup_(/*manual_reset=*/false, /*initially_signaled=*/false) {}
 FakeNetworkSocketServer::~FakeNetworkSocketServer() = default;
 
@@ -29,13 +29,7 @@
 
 EmulatedEndpoint* FakeNetworkSocketServer::GetEndpointNode(
     const rtc::IPAddress& ip) {
-  for (auto* endpoint : endpoints_) {
-    rtc::IPAddress peerLocalAddress = endpoint->GetPeerLocalAddress();
-    if (peerLocalAddress == ip) {
-      return endpoint;
-    }
-  }
-  RTC_CHECK(false) << "No network found for address" << ip.ToString();
+  return endpoints_container_->LookupByLocalAddress(ip);
 }
 
 void FakeNetworkSocketServer::Unregister(SocketIoProcessor* io_processor) {
diff --git a/test/scenario/network/fake_network_socket_server.h b/test/scenario/network/fake_network_socket_server.h
index 76b1369..d36b8f0 100644
--- a/test/scenario/network/fake_network_socket_server.h
+++ b/test/scenario/network/fake_network_socket_server.h
@@ -35,7 +35,7 @@
                                 public SocketManager {
  public:
   FakeNetworkSocketServer(Clock* clock,
-                          std::vector<EmulatedEndpoint*> endpoints);
+                          EndpointsContainer* endpoints_controller);
   ~FakeNetworkSocketServer() override;
 
   EmulatedEndpoint* GetEndpointNode(const rtc::IPAddress& ip) override;
@@ -57,7 +57,7 @@
   Timestamp Now() const;
 
   Clock* const clock_;
-  const std::vector<EmulatedEndpoint*> endpoints_;
+  const EndpointsContainer* endpoints_container_;
   rtc::Event wakeup_;
   rtc::MessageQueue* msg_queue_;
 
diff --git a/test/scenario/network/network_emulation.cc b/test/scenario/network/network_emulation.cc
index 98f5a06..2021248 100644
--- a/test/scenario/network/network_emulation.cc
+++ b/test/scenario/network/network_emulation.cc
@@ -128,13 +128,34 @@
   routing_.erase(dest_endpoint_id);
 }
 
-EmulatedEndpoint::EmulatedEndpoint(uint64_t id, rtc::IPAddress ip, Clock* clock)
+EmulatedEndpoint::EmulatedEndpoint(uint64_t id,
+                                   rtc::IPAddress ip,
+                                   bool is_enabled,
+                                   Clock* clock)
     : id_(id),
       peer_local_addr_(ip),
+      is_enabled_(is_enabled),
       send_node_(nullptr),
       clock_(clock),
       next_port_(kFirstEphemeralPort),
-      connected_endpoint_id_(absl::nullopt) {}
+      connected_endpoint_id_(absl::nullopt) {
+  constexpr int kIPv4NetworkPrefixLength = 24;
+  constexpr int kIPv6NetworkPrefixLength = 64;
+
+  int prefix_length = 0;
+  if (ip.family() == AF_INET) {
+    prefix_length = kIPv4NetworkPrefixLength;
+  } else if (ip.family() == AF_INET6) {
+    prefix_length = kIPv6NetworkPrefixLength;
+  }
+  rtc::IPAddress prefix = TruncateIP(ip, prefix_length);
+  network_ = absl::make_unique<rtc::Network>(
+      ip.ToString(), "Endpoint id=" + std::to_string(id_), prefix,
+      prefix_length, rtc::AdapterType::ADAPTER_TYPE_UNKNOWN);
+  network_->AddIP(ip);
+
+  enabled_state_checker_.DetachFromThread();
+}
 EmulatedEndpoint::~EmulatedEndpoint() = default;
 
 uint64_t EmulatedEndpoint::GetId() const {
@@ -226,6 +247,23 @@
   it->second->OnPacketReceived(std::move(packet));
 }
 
+void EmulatedEndpoint::Enable() {
+  RTC_DCHECK_RUN_ON(&enabled_state_checker_);
+  RTC_CHECK(!is_enabled_);
+  is_enabled_ = true;
+}
+
+void EmulatedEndpoint::Disable() {
+  RTC_DCHECK_RUN_ON(&enabled_state_checker_);
+  RTC_CHECK(is_enabled_);
+  is_enabled_ = false;
+}
+
+bool EmulatedEndpoint::Enabled() const {
+  RTC_DCHECK_RUN_ON(&enabled_state_checker_);
+  return is_enabled_;
+}
+
 EmulatedNetworkNode* EmulatedEndpoint::GetSendNode() const {
   return send_node_;
 }
@@ -234,4 +272,40 @@
   connected_endpoint_id_ = endpoint_id;
 }
 
+EndpointsContainer::EndpointsContainer(
+    const std::vector<EmulatedEndpoint*>& endpoints)
+    : endpoints_(endpoints) {}
+
+EmulatedEndpoint* EndpointsContainer::LookupByLocalAddress(
+    const rtc::IPAddress& local_ip) const {
+  for (auto* endpoint : endpoints_) {
+    rtc::IPAddress peerLocalAddress = endpoint->GetPeerLocalAddress();
+    if (peerLocalAddress == local_ip) {
+      return endpoint;
+    }
+  }
+  RTC_CHECK(false) << "No network found for address" << local_ip.ToString();
+}
+
+bool EndpointsContainer::HasEndpoint(EmulatedEndpoint* endpoint) const {
+  for (auto* e : endpoints_) {
+    if (e->GetId() == endpoint->GetId()) {
+      return true;
+    }
+  }
+  return false;
+}
+
+std::vector<std::unique_ptr<rtc::Network>>
+EndpointsContainer::GetEnabledNetworks() const {
+  std::vector<std::unique_ptr<rtc::Network>> networks;
+  for (auto* endpoint : endpoints_) {
+    if (endpoint->Enabled()) {
+      networks.emplace_back(
+          absl::make_unique<rtc::Network>(endpoint->network()));
+    }
+  }
+  return networks;
+}
+
 }  // namespace webrtc
diff --git a/test/scenario/network/network_emulation.h b/test/scenario/network/network_emulation.h
index 837ff38..309d511 100644
--- a/test/scenario/network/network_emulation.h
+++ b/test/scenario/network/network_emulation.h
@@ -24,8 +24,10 @@
 #include "rtc_base/async_socket.h"
 #include "rtc_base/copy_on_write_buffer.h"
 #include "rtc_base/critical_section.h"
+#include "rtc_base/network.h"
 #include "rtc_base/socket_address.h"
 #include "rtc_base/thread.h"
+#include "rtc_base/thread_checker.h"
 #include "system_wrappers/include/clock.h"
 
 namespace webrtc {
@@ -120,7 +122,10 @@
 // from other EmulatedNetworkNodes.
 class EmulatedEndpoint : public EmulatedNetworkReceiverInterface {
  public:
-  EmulatedEndpoint(uint64_t id, rtc::IPAddress, Clock* clock);
+  EmulatedEndpoint(uint64_t id,
+                   rtc::IPAddress ip,
+                   bool is_enabled,
+                   Clock* clock);
   ~EmulatedEndpoint() override;
 
   uint64_t GetId() const;
@@ -155,6 +160,12 @@
   // Will be called to deliver packet into endpoint from network node.
   void OnPacketReceived(EmulatedIpPacket packet) override;
 
+  void Enable();
+  void Disable();
+  bool Enabled() const;
+
+  const rtc::Network& network() const { return *network_.get(); }
+
  protected:
   friend class test::NetworkEmulationManagerImpl;
 
@@ -166,12 +177,15 @@
   uint16_t NextPort() RTC_EXCLUSIVE_LOCKS_REQUIRED(receiver_lock_);
 
   rtc::CriticalSection receiver_lock_;
+  rtc::ThreadChecker enabled_state_checker_;
 
   uint64_t id_;
   // Peer's local IP address for this endpoint network interface.
   const rtc::IPAddress peer_local_addr_;
+  bool is_enabled_ RTC_GUARDED_BY(enabled_state_checker_);
   EmulatedNetworkNode* send_node_;
   Clock* const clock_;
+  std::unique_ptr<rtc::Network> network_;
 
   uint16_t next_port_ RTC_GUARDED_BY(receiver_lock_);
   std::map<uint16_t, EmulatedNetworkReceiverInterface*> port_to_receiver_
@@ -193,6 +207,20 @@
   bool active;
 };
 
+class EndpointsContainer {
+ public:
+  EndpointsContainer(const std::vector<EmulatedEndpoint*>& endpoints);
+
+  EmulatedEndpoint* LookupByLocalAddress(const rtc::IPAddress& local_ip) const;
+  bool HasEndpoint(EmulatedEndpoint* endpoint) const;
+  // Returns list of networks for enabled endpoints. Caller takes ownership of
+  // returned rtc::Network objects.
+  std::vector<std::unique_ptr<rtc::Network>> GetEnabledNetworks() const;
+
+ private:
+  const std::vector<EmulatedEndpoint*> endpoints_;
+};
+
 }  // namespace webrtc
 
 #endif  // TEST_SCENARIO_NETWORK_NETWORK_EMULATION_H_
diff --git a/test/scenario/network/network_emulation_manager.cc b/test/scenario/network/network_emulation_manager.cc
index 577d968..9c634ea 100644
--- a/test/scenario/network/network_emulation_manager.cc
+++ b/test/scenario/network/network_emulation_manager.cc
@@ -80,12 +80,27 @@
 
   bool res = used_ip_addresses_.insert(*ip).second;
   RTC_CHECK(res) << "IP=" << ip->ToString() << " already in use";
-  auto node = absl::make_unique<EmulatedEndpoint>(next_node_id_++, *ip, clock_);
+  auto node = absl::make_unique<EmulatedEndpoint>(
+      next_node_id_++, *ip, config.start_as_enabled, clock_);
   EmulatedEndpoint* out = node.get();
   endpoints_.push_back(std::move(node));
   return out;
 }
 
+void NetworkEmulationManagerImpl::EnableEndpoint(EmulatedEndpoint* endpoint) {
+  EmulatedNetworkManager* network_manager =
+      endpoint_to_network_manager_[endpoint];
+  RTC_CHECK(network_manager);
+  network_manager->EnableEndpoint(endpoint);
+}
+
+void NetworkEmulationManagerImpl::DisableEndpoint(EmulatedEndpoint* endpoint) {
+  EmulatedNetworkManager* network_manager =
+      endpoint_to_network_manager_[endpoint];
+  RTC_CHECK(network_manager);
+  network_manager->DisableEndpoint(endpoint);
+}
+
 EmulatedRoute* NetworkEmulationManagerImpl::CreateRoute(
     EmulatedEndpoint* from,
     const std::vector<EmulatedNetworkNode*>& via_nodes,
@@ -182,37 +197,26 @@
   return out;
 }
 
-rtc::Thread* NetworkEmulationManagerImpl::CreateNetworkThread(
+EmulatedNetworkManagerInterface*
+NetworkEmulationManagerImpl::CreateEmulatedNetworkManagerInterface(
     const std::vector<EmulatedEndpoint*>& endpoints) {
-  FakeNetworkSocketServer* socket_server = CreateSocketServer(endpoints);
-  std::unique_ptr<rtc::Thread> network_thread =
-      absl::make_unique<rtc::Thread>(socket_server);
-  network_thread->SetName("network_thread" + std::to_string(threads_.size()),
-                          nullptr);
-  network_thread->Start();
-  rtc::Thread* out = network_thread.get();
-  threads_.push_back(std::move(network_thread));
-  return out;
-}
-
-rtc::NetworkManager* NetworkEmulationManagerImpl::CreateNetworkManager(
-    const std::vector<EmulatedEndpoint*>& endpoints) {
-  auto network_manager = absl::make_unique<rtc::FakeNetworkManager>();
+  auto endpoints_controller = absl::make_unique<EndpointsContainer>(endpoints);
+  auto network_manager = absl::make_unique<EmulatedNetworkManager>(
+      clock_, endpoints_controller.get());
   for (auto* endpoint : endpoints) {
-    network_manager->AddInterface(
-        rtc::SocketAddress(endpoint->GetPeerLocalAddress(), /*port=*/0));
+    // Associate endpoint with network manager.
+    bool insertion_result =
+        endpoint_to_network_manager_.insert({endpoint, network_manager.get()})
+            .second;
+    RTC_CHECK(insertion_result)
+        << "Endpoint ip=" << endpoint->GetPeerLocalAddress().ToString()
+        << " is already used for another network";
   }
-  rtc::NetworkManager* out = network_manager.get();
-  managers_.push_back(std::move(network_manager));
-  return out;
-}
 
-FakeNetworkSocketServer* NetworkEmulationManagerImpl::CreateSocketServer(
-    const std::vector<EmulatedEndpoint*>& endpoints) {
-  auto socket_server =
-      absl::make_unique<FakeNetworkSocketServer>(clock_, endpoints);
-  FakeNetworkSocketServer* out = socket_server.get();
-  socket_servers_.push_back(std::move(socket_server));
+  EmulatedNetworkManagerInterface* out = network_manager.get();
+
+  endpoints_controllers_.push_back(std::move(endpoints_controller));
+  network_managers_.push_back(std::move(network_manager));
   return out;
 }
 
diff --git a/test/scenario/network/network_emulation_manager.h b/test/scenario/network/network_emulation_manager.h
index 37f52f3..6fe24f7 100644
--- a/test/scenario/network/network_emulation_manager.h
+++ b/test/scenario/network/network_emulation_manager.h
@@ -26,6 +26,7 @@
 #include "rtc_base/thread.h"
 #include "system_wrappers/include/clock.h"
 #include "test/scenario/network/cross_traffic.h"
+#include "test/scenario/network/emulated_network_manager.h"
 #include "test/scenario/network/fake_network_socket_server.h"
 #include "test/scenario/network/network_emulation.h"
 #include "test/scenario/network/traffic_route.h"
@@ -42,6 +43,8 @@
       std::unique_ptr<NetworkBehaviorInterface> network_behavior) override;
 
   EmulatedEndpoint* CreateEndpoint(EmulatedEndpointConfig config) override;
+  void EnableEndpoint(EmulatedEndpoint* endpoint) override;
+  void DisableEndpoint(EmulatedEndpoint* endpoint) override;
 
   EmulatedRoute* CreateRoute(EmulatedEndpoint* from,
                              const std::vector<EmulatedNetworkNode*>& via_nodes,
@@ -57,9 +60,7 @@
       TrafficRoute* traffic_route,
       PulsedPeaksConfig config);
 
-  rtc::Thread* CreateNetworkThread(
-      const std::vector<EmulatedEndpoint*>& endpoints) override;
-  rtc::NetworkManager* CreateNetworkManager(
+  EmulatedNetworkManagerInterface* CreateEmulatedNetworkManagerInterface(
       const std::vector<EmulatedEndpoint*>& endpoints) override;
 
  private:
@@ -84,9 +85,11 @@
   std::vector<std::unique_ptr<TrafficRoute>> traffic_routes_;
   std::vector<std::unique_ptr<RandomWalkCrossTraffic>> random_cross_traffics_;
   std::vector<std::unique_ptr<PulsedPeaksCrossTraffic>> pulsed_cross_traffics_;
-  std::vector<std::unique_ptr<FakeNetworkSocketServer>> socket_servers_;
-  std::vector<std::unique_ptr<rtc::Thread>> threads_;
-  std::vector<std::unique_ptr<rtc::NetworkManager>> managers_;
+  std::vector<std::unique_ptr<EndpointsContainer>> endpoints_controllers_;
+  std::vector<std::unique_ptr<EmulatedNetworkManager>> network_managers_;
+
+  std::map<EmulatedEndpoint*, EmulatedNetworkManager*>
+      endpoint_to_network_manager_;
 
   // Must be the last field, so it will be deleted first, because tasks
   // in the TaskQueue can access other fields of the instance of this class.
diff --git a/test/scenario/network/network_emulation_pc_unittest.cc b/test/scenario/network/network_emulation_pc_unittest.cc
index d197fc5..9799b89 100644
--- a/test/scenario/network/network_emulation_pc_unittest.cc
+++ b/test/scenario/network/network_emulation_pc_unittest.cc
@@ -113,36 +113,32 @@
   emulation.CreateRoute(alice_endpoint, {alice_node}, bob_endpoint);
   emulation.CreateRoute(bob_endpoint, {bob_node}, alice_endpoint);
 
-  rtc::Thread* alice_network_thread =
-      emulation.CreateNetworkThread({alice_endpoint});
-  rtc::Thread* bob_network_thread =
-      emulation.CreateNetworkThread({bob_endpoint});
+  EmulatedNetworkManagerInterface* alice_network =
+      emulation.CreateEmulatedNetworkManagerInterface({alice_endpoint});
+  EmulatedNetworkManagerInterface* bob_network =
+      emulation.CreateEmulatedNetworkManagerInterface({bob_endpoint});
 
   // Setup peer connections.
   rtc::scoped_refptr<PeerConnectionFactoryInterface> alice_pcf;
   rtc::scoped_refptr<PeerConnectionInterface> alice_pc;
   std::unique_ptr<MockPeerConnectionObserver> alice_observer =
       absl::make_unique<MockPeerConnectionObserver>();
-  rtc::NetworkManager* alice_network_manager =
-      emulation.CreateNetworkManager({alice_endpoint});
 
   rtc::scoped_refptr<PeerConnectionFactoryInterface> bob_pcf;
   rtc::scoped_refptr<PeerConnectionInterface> bob_pc;
   std::unique_ptr<MockPeerConnectionObserver> bob_observer =
       absl::make_unique<MockPeerConnectionObserver>();
-  rtc::NetworkManager* bob_network_manager =
-      emulation.CreateNetworkManager({bob_endpoint});
 
   signaling_thread->Invoke<void>(RTC_FROM_HERE, [&]() {
     alice_pcf = CreatePeerConnectionFactory(signaling_thread.get(),
-                                            alice_network_thread);
+                                            alice_network->network_thread());
     alice_pc = CreatePeerConnection(alice_pcf, alice_observer.get(),
-                                    alice_network_manager);
+                                    alice_network->network_manager());
 
-    bob_pcf =
-        CreatePeerConnectionFactory(signaling_thread.get(), bob_network_thread);
-    bob_pc =
-        CreatePeerConnection(bob_pcf, bob_observer.get(), bob_network_manager);
+    bob_pcf = CreatePeerConnectionFactory(signaling_thread.get(),
+                                          bob_network->network_thread());
+    bob_pc = CreatePeerConnection(bob_pcf, bob_observer.get(),
+                                  bob_network->network_manager());
   });
 
   std::unique_ptr<PeerConnectionWrapper> alice =
diff --git a/test/scenario/network/network_emulation_unittest.cc b/test/scenario/network/network_emulation_unittest.cc
index 13c388c..2e7b1d7 100644
--- a/test/scenario/network/network_emulation_unittest.cc
+++ b/test/scenario/network/network_emulation_unittest.cc
@@ -97,12 +97,16 @@
   network_manager.CreateRoute(alice_endpoint, {alice_node}, bob_endpoint);
   network_manager.CreateRoute(bob_endpoint, {bob_node}, alice_endpoint);
 
-  auto* nt1 = network_manager.CreateNetworkThread({alice_endpoint});
-  auto* nt2 = network_manager.CreateNetworkThread({bob_endpoint});
+  EmulatedNetworkManagerInterface* nt1 =
+      network_manager.CreateEmulatedNetworkManagerInterface({alice_endpoint});
+  EmulatedNetworkManagerInterface* nt2 =
+      network_manager.CreateEmulatedNetworkManagerInterface({bob_endpoint});
 
   for (uint64_t j = 0; j < 2; j++) {
-    auto* s1 = nt1->socketserver()->CreateAsyncSocket(AF_INET, SOCK_DGRAM);
-    auto* s2 = nt2->socketserver()->CreateAsyncSocket(AF_INET, SOCK_DGRAM);
+    auto* s1 = nt1->network_thread()->socketserver()->CreateAsyncSocket(
+        AF_INET, SOCK_DGRAM);
+    auto* s2 = nt2->network_thread()->socketserver()->CreateAsyncSocket(
+        AF_INET, SOCK_DGRAM);
 
     SocketReader r1(s1);
     SocketReader r2(s2);
@@ -113,8 +117,8 @@
     s1->Bind(a1);
     s2->Bind(a2);
 
-    s1->Connect(s1->GetLocalAddress());
-    s2->Connect(s2->GetLocalAddress());
+    s1->Connect(s2->GetLocalAddress());
+    s2->Connect(s1->GetLocalAddress());
 
     rtc::CopyOnWriteBuffer data("Hello");
     for (uint64_t i = 0; i < 1000; i++) {