diff --git a/test/network/BUILD.gn b/test/network/BUILD.gn index 852d4b8607..c1560018f3 100644 --- a/test/network/BUILD.gn +++ b/test/network/BUILD.gn @@ -25,8 +25,6 @@ rtc_library("emulated_network") { "cross_traffic.h", "emulated_network_manager.cc", "emulated_network_manager.h", - "fake_network_socket.cc", - "fake_network_socket.h", "fake_network_socket_server.cc", "fake_network_socket_server.h", "network_emulation.cc", @@ -56,6 +54,7 @@ rtc_library("emulated_network") { "../../system_wrappers", "../scenario:column_printer", "../time_controller", + "//third_party/abseil-cpp/absl/algorithm:container", "//third_party/abseil-cpp/absl/memory", "//third_party/abseil-cpp/absl/types:optional", ] diff --git a/test/network/fake_network_socket.cc b/test/network/fake_network_socket.cc deleted file mode 100644 index d514afe206..0000000000 --- a/test/network/fake_network_socket.cc +++ /dev/null @@ -1,227 +0,0 @@ -/* - * 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/network/fake_network_socket.h" - -#include -#include -#include -#include - -#include "rtc_base/logging.h" -#include "rtc_base/thread.h" - -namespace webrtc { -namespace test { -namespace { - -std::string ToString(const rtc::SocketAddress& addr) { - return addr.HostAsURIString() + ":" + std::to_string(addr.port()); -} - -} // namespace - -FakeNetworkSocket::FakeNetworkSocket(SocketManager* socket_manager) - : socket_manager_(socket_manager), - state_(CS_CLOSED), - error_(0), - pending_read_events_count_(0) {} -FakeNetworkSocket::~FakeNetworkSocket() { - Close(); - socket_manager_->Unregister(this); -} - -void FakeNetworkSocket::OnPacketReceived(EmulatedIpPacket packet) { - { - rtc::CritScope crit(&lock_); - packet_queue_.push_back(std::move(packet)); - pending_read_events_count_++; - } - socket_manager_->WakeUp(); -} - -bool FakeNetworkSocket::ProcessIo() { - { - rtc::CritScope crit(&lock_); - if (pending_read_events_count_ == 0) { - return false; - } - pending_read_events_count_--; - RTC_DCHECK_GE(pending_read_events_count_, 0); - } - if (!endpoint_->Enabled()) { - // If endpoint disabled then just pop and discard packet. - PopFrontPacket(); - return true; - } - SignalReadEvent(this); - return true; -} - -rtc::SocketAddress FakeNetworkSocket::GetLocalAddress() const { - return local_addr_; -} - -rtc::SocketAddress FakeNetworkSocket::GetRemoteAddress() const { - return remote_addr_; -} - -int FakeNetworkSocket::Bind(const rtc::SocketAddress& addr) { - RTC_CHECK(local_addr_.IsNil()) - << "Socket already bound to address: " << ToString(local_addr_); - local_addr_ = addr; - endpoint_ = socket_manager_->GetEndpointNode(local_addr_.ipaddr()); - if (!endpoint_) { - local_addr_.Clear(); - RTC_LOG(INFO) << "No endpoint for address: " << ToString(addr); - error_ = EADDRNOTAVAIL; - return 2; - } - absl::optional port = - endpoint_->BindReceiver(local_addr_.port(), this); - if (!port) { - local_addr_.Clear(); - RTC_LOG(INFO) << "Cannot bind to in-use address: " << ToString(addr); - error_ = EADDRINUSE; - return 1; - } - local_addr_.SetPort(port.value()); - return 0; -} - -int FakeNetworkSocket::Connect(const rtc::SocketAddress& addr) { - RTC_CHECK(remote_addr_.IsNil()) - << "Socket already connected to address: " << ToString(remote_addr_); - RTC_CHECK(!local_addr_.IsNil()) - << "Socket have to be bind to some local address"; - remote_addr_ = addr; - state_ = CS_CONNECTED; - return 0; -} - -int FakeNetworkSocket::Send(const void* pv, size_t cb) { - RTC_CHECK(state_ == CS_CONNECTED) << "Socket cannot send: not connected"; - return SendTo(pv, cb, remote_addr_); -} - -int FakeNetworkSocket::SendTo(const void* pv, - size_t cb, - const rtc::SocketAddress& addr) { - RTC_CHECK(!local_addr_.IsNil()) - << "Socket have to be bind to some local address"; - if (!endpoint_->Enabled()) { - error_ = ENETDOWN; - return -1; - } - rtc::CopyOnWriteBuffer packet(static_cast(pv), cb); - endpoint_->SendPacket(local_addr_, addr, packet); - return cb; -} - -int FakeNetworkSocket::Recv(void* pv, size_t cb, int64_t* timestamp) { - rtc::SocketAddress paddr; - return RecvFrom(pv, cb, &paddr, timestamp); -} - -// Reads 1 packet from internal queue. Reads up to |cb| bytes into |pv| -// and returns the length of received packet. -int FakeNetworkSocket::RecvFrom(void* pv, - size_t cb, - rtc::SocketAddress* paddr, - int64_t* timestamp) { - if (timestamp) { - *timestamp = -1; - } - absl::optional packetOpt = PopFrontPacket(); - - if (!packetOpt) { - error_ = EAGAIN; - return -1; - } - - EmulatedIpPacket packet = std::move(packetOpt.value()); - *paddr = packet.from; - size_t data_read = std::min(cb, packet.size()); - memcpy(pv, packet.cdata(), data_read); - *timestamp = packet.arrival_time.us(); - - // According to RECV(2) Linux Man page - // real socket will discard data, that won't fit into provided buffer, - // but we won't to skip such error, so we will assert here. - RTC_CHECK(data_read == packet.size()) - << "Too small buffer is provided for socket read. " - << "Received data size: " << packet.size() - << "; Provided buffer size: " << cb; - - // According to RECV(2) Linux Man page - // real socket will return message length, not data read. In our case it is - // actually the same value. - return static_cast(packet.size()); -} - -int FakeNetworkSocket::Listen(int backlog) { - RTC_CHECK(false) << "Listen() isn't valid for SOCK_DGRAM"; -} - -rtc::AsyncSocket* FakeNetworkSocket::Accept(rtc::SocketAddress* /*paddr*/) { - RTC_CHECK(false) << "Accept() isn't valid for SOCK_DGRAM"; -} - -int FakeNetworkSocket::Close() { - state_ = CS_CLOSED; - if (!local_addr_.IsNil()) { - endpoint_->UnbindReceiver(local_addr_.port()); - } - local_addr_.Clear(); - remote_addr_.Clear(); - return 0; -} - -int FakeNetworkSocket::GetError() const { - return error_; -} - -void FakeNetworkSocket::SetError(int error) { - RTC_CHECK(error == 0); - error_ = error; -} - -rtc::AsyncSocket::ConnState FakeNetworkSocket::GetState() const { - return state_; -} - -int FakeNetworkSocket::GetOption(Option opt, int* value) { - auto it = options_map_.find(opt); - if (it == options_map_.end()) { - return -1; - } - *value = it->second; - return 0; -} - -int FakeNetworkSocket::SetOption(Option opt, int value) { - options_map_[opt] = value; - return 0; -} - -absl::optional FakeNetworkSocket::PopFrontPacket() { - rtc::CritScope crit(&lock_); - if (packet_queue_.empty()) { - return absl::nullopt; - } - - absl::optional packet = - absl::make_optional(std::move(packet_queue_.front())); - packet_queue_.pop_front(); - return packet; -} - -} // namespace test -} // namespace webrtc diff --git a/test/network/fake_network_socket.h b/test/network/fake_network_socket.h deleted file mode 100644 index 8ac91a013f..0000000000 --- a/test/network/fake_network_socket.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * 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_NETWORK_FAKE_NETWORK_SOCKET_H_ -#define TEST_NETWORK_FAKE_NETWORK_SOCKET_H_ - -#include -#include -#include - -#include "rtc_base/async_socket.h" -#include "rtc_base/copy_on_write_buffer.h" -#include "rtc_base/critical_section.h" -#include "rtc_base/socket_address.h" -#include "test/network/network_emulation.h" - -namespace webrtc { -namespace test { - -class SocketIoProcessor { - public: - virtual ~SocketIoProcessor() = default; - - // Process single IO operation. - virtual bool ProcessIo() = 0; -}; - -class SocketManager { - public: - virtual ~SocketManager() = default; - - virtual void WakeUp() = 0; - virtual void Unregister(SocketIoProcessor* io_processor) = 0; - // Provides endpoints by IP address. - virtual EmulatedEndpointImpl* GetEndpointNode(const rtc::IPAddress& ip) = 0; -}; - -// Represents a socket, which will operate with emulated network. -class FakeNetworkSocket : public rtc::AsyncSocket, - public EmulatedNetworkReceiverInterface, - public SocketIoProcessor { - public: - explicit FakeNetworkSocket(SocketManager* scoket_manager); - ~FakeNetworkSocket() override; - - // Will be invoked by EmulatedEndpoint to deliver packets into this socket. - void OnPacketReceived(EmulatedIpPacket packet) override; - // Will fire read event for incoming packets. - bool ProcessIo() override; - - // rtc::Socket methods: - rtc::SocketAddress GetLocalAddress() const override; - rtc::SocketAddress GetRemoteAddress() const override; - int Bind(const rtc::SocketAddress& addr) override; - int Connect(const rtc::SocketAddress& addr) override; - int Close() override; - int Send(const void* pv, size_t cb) override; - int SendTo(const void* pv, - size_t cb, - const rtc::SocketAddress& addr) override; - int Recv(void* pv, size_t cb, int64_t* timestamp) override; - int RecvFrom(void* pv, - size_t cb, - rtc::SocketAddress* paddr, - int64_t* timestamp) override; - int Listen(int backlog) override; - rtc::AsyncSocket* Accept(rtc::SocketAddress* paddr) override; - int GetError() const override; - void SetError(int error) override; - ConnState GetState() const override; - int GetOption(Option opt, int* value) override; - int SetOption(Option opt, int value) override; - - private: - absl::optional PopFrontPacket(); - - SocketManager* const socket_manager_; - EmulatedEndpointImpl* endpoint_; - - rtc::SocketAddress local_addr_; - rtc::SocketAddress remote_addr_; - ConnState state_; - int error_; - std::map options_map_; - - rtc::CriticalSection lock_; - // Count of packets in the queue for which we didn't fire read event. - // |pending_read_events_count_| can be different from |packet_queue_.size()| - // because read events will be fired by one thread and packets in the queue - // can be processed by another thread. - int pending_read_events_count_; - std::deque packet_queue_ RTC_GUARDED_BY(lock_); -}; - -} // namespace test -} // namespace webrtc - -#endif // TEST_NETWORK_FAKE_NETWORK_SOCKET_H_ diff --git a/test/network/fake_network_socket_server.cc b/test/network/fake_network_socket_server.cc index a8e3eac6ba..6c1b8d7776 100644 --- a/test/network/fake_network_socket_server.cc +++ b/test/network/fake_network_socket_server.cc @@ -10,12 +10,274 @@ #include "test/network/fake_network_socket_server.h" +#include +#include #include +#include +#include "absl/algorithm/container.h" +#include "rtc_base/logging.h" #include "rtc_base/thread.h" namespace webrtc { namespace test { +namespace { +std::string ToString(const rtc::SocketAddress& addr) { + return addr.HostAsURIString() + ":" + std::to_string(addr.port()); +} + +} // namespace + +// Represents a socket, which will operate with emulated network. +class FakeNetworkSocket : public rtc::AsyncSocket, + public EmulatedNetworkReceiverInterface { + public: + explicit FakeNetworkSocket(FakeNetworkSocketServer* scoket_manager); + ~FakeNetworkSocket() override; + + // Will be invoked by EmulatedEndpoint to deliver packets into this socket. + void OnPacketReceived(EmulatedIpPacket packet) override; + // Will fire read event for incoming packets. + bool ProcessIo(); + + // rtc::Socket methods: + rtc::SocketAddress GetLocalAddress() const override; + rtc::SocketAddress GetRemoteAddress() const override; + int Bind(const rtc::SocketAddress& addr) override; + int Connect(const rtc::SocketAddress& addr) override; + int Close() override; + int Send(const void* pv, size_t cb) override; + int SendTo(const void* pv, + size_t cb, + const rtc::SocketAddress& addr) override; + int Recv(void* pv, size_t cb, int64_t* timestamp) override; + int RecvFrom(void* pv, + size_t cb, + rtc::SocketAddress* paddr, + int64_t* timestamp) override; + int Listen(int backlog) override; + rtc::AsyncSocket* Accept(rtc::SocketAddress* paddr) override; + int GetError() const override; + void SetError(int error) override; + ConnState GetState() const override; + int GetOption(Option opt, int* value) override; + int SetOption(Option opt, int value) override; + + private: + absl::optional PopFrontPacket(); + + FakeNetworkSocketServer* const socket_server_; + EmulatedEndpointImpl* endpoint_; + + rtc::SocketAddress local_addr_; + rtc::SocketAddress remote_addr_; + ConnState state_; + int error_; + std::map options_map_; + + rtc::CriticalSection lock_; + // Count of packets in the queue for which we didn't fire read event. + // |pending_read_events_count_| can be different from |packet_queue_.size()| + // because read events will be fired by one thread and packets in the queue + // can be processed by another thread. + int pending_read_events_count_; + std::deque packet_queue_ RTC_GUARDED_BY(lock_); +}; + +FakeNetworkSocket::FakeNetworkSocket(FakeNetworkSocketServer* socket_server) + : socket_server_(socket_server), + state_(CS_CLOSED), + error_(0), + pending_read_events_count_(0) {} +FakeNetworkSocket::~FakeNetworkSocket() { + Close(); + socket_server_->Unregister(this); +} + +void FakeNetworkSocket::OnPacketReceived(EmulatedIpPacket packet) { + { + rtc::CritScope crit(&lock_); + packet_queue_.push_back(std::move(packet)); + pending_read_events_count_++; + } + socket_server_->WakeUp(); +} + +bool FakeNetworkSocket::ProcessIo() { + { + rtc::CritScope crit(&lock_); + if (pending_read_events_count_ == 0) { + return false; + } + pending_read_events_count_--; + RTC_DCHECK_GE(pending_read_events_count_, 0); + } + if (!endpoint_->Enabled()) { + // If endpoint disabled then just pop and discard packet. + PopFrontPacket(); + return true; + } + SignalReadEvent(this); + return true; +} + +rtc::SocketAddress FakeNetworkSocket::GetLocalAddress() const { + return local_addr_; +} + +rtc::SocketAddress FakeNetworkSocket::GetRemoteAddress() const { + return remote_addr_; +} + +int FakeNetworkSocket::Bind(const rtc::SocketAddress& addr) { + RTC_CHECK(local_addr_.IsNil()) + << "Socket already bound to address: " << ToString(local_addr_); + local_addr_ = addr; + endpoint_ = socket_server_->GetEndpointNode(local_addr_.ipaddr()); + if (!endpoint_) { + local_addr_.Clear(); + RTC_LOG(INFO) << "No endpoint for address: " << ToString(addr); + error_ = EADDRNOTAVAIL; + return 2; + } + absl::optional port = + endpoint_->BindReceiver(local_addr_.port(), this); + if (!port) { + local_addr_.Clear(); + RTC_LOG(INFO) << "Cannot bind to in-use address: " << ToString(addr); + error_ = EADDRINUSE; + return 1; + } + local_addr_.SetPort(port.value()); + return 0; +} + +int FakeNetworkSocket::Connect(const rtc::SocketAddress& addr) { + RTC_CHECK(remote_addr_.IsNil()) + << "Socket already connected to address: " << ToString(remote_addr_); + RTC_CHECK(!local_addr_.IsNil()) + << "Socket have to be bind to some local address"; + remote_addr_ = addr; + state_ = CS_CONNECTED; + return 0; +} + +int FakeNetworkSocket::Send(const void* pv, size_t cb) { + RTC_CHECK(state_ == CS_CONNECTED) << "Socket cannot send: not connected"; + return SendTo(pv, cb, remote_addr_); +} + +int FakeNetworkSocket::SendTo(const void* pv, + size_t cb, + const rtc::SocketAddress& addr) { + RTC_CHECK(!local_addr_.IsNil()) + << "Socket have to be bind to some local address"; + if (!endpoint_->Enabled()) { + error_ = ENETDOWN; + return -1; + } + rtc::CopyOnWriteBuffer packet(static_cast(pv), cb); + endpoint_->SendPacket(local_addr_, addr, packet); + return cb; +} + +int FakeNetworkSocket::Recv(void* pv, size_t cb, int64_t* timestamp) { + rtc::SocketAddress paddr; + return RecvFrom(pv, cb, &paddr, timestamp); +} + +// Reads 1 packet from internal queue. Reads up to |cb| bytes into |pv| +// and returns the length of received packet. +int FakeNetworkSocket::RecvFrom(void* pv, + size_t cb, + rtc::SocketAddress* paddr, + int64_t* timestamp) { + if (timestamp) { + *timestamp = -1; + } + absl::optional packetOpt = PopFrontPacket(); + + if (!packetOpt) { + error_ = EAGAIN; + return -1; + } + + EmulatedIpPacket packet = std::move(packetOpt.value()); + *paddr = packet.from; + size_t data_read = std::min(cb, packet.size()); + memcpy(pv, packet.cdata(), data_read); + *timestamp = packet.arrival_time.us(); + + // According to RECV(2) Linux Man page + // real socket will discard data, that won't fit into provided buffer, + // but we won't to skip such error, so we will assert here. + RTC_CHECK(data_read == packet.size()) + << "Too small buffer is provided for socket read. " + << "Received data size: " << packet.size() + << "; Provided buffer size: " << cb; + + // According to RECV(2) Linux Man page + // real socket will return message length, not data read. In our case it is + // actually the same value. + return static_cast(packet.size()); +} + +int FakeNetworkSocket::Listen(int backlog) { + RTC_CHECK(false) << "Listen() isn't valid for SOCK_DGRAM"; +} + +rtc::AsyncSocket* FakeNetworkSocket::Accept(rtc::SocketAddress* /*paddr*/) { + RTC_CHECK(false) << "Accept() isn't valid for SOCK_DGRAM"; +} + +int FakeNetworkSocket::Close() { + state_ = CS_CLOSED; + if (!local_addr_.IsNil()) { + endpoint_->UnbindReceiver(local_addr_.port()); + } + local_addr_.Clear(); + remote_addr_.Clear(); + return 0; +} + +int FakeNetworkSocket::GetError() const { + return error_; +} + +void FakeNetworkSocket::SetError(int error) { + RTC_CHECK(error == 0); + error_ = error; +} + +rtc::AsyncSocket::ConnState FakeNetworkSocket::GetState() const { + return state_; +} + +int FakeNetworkSocket::GetOption(Option opt, int* value) { + auto it = options_map_.find(opt); + if (it == options_map_.end()) { + return -1; + } + *value = it->second; + return 0; +} + +int FakeNetworkSocket::SetOption(Option opt, int value) { + options_map_[opt] = value; + return 0; +} + +absl::optional FakeNetworkSocket::PopFrontPacket() { + rtc::CritScope crit(&lock_); + if (packet_queue_.empty()) { + return absl::nullopt; + } + + absl::optional packet = + absl::make_optional(std::move(packet_queue_.front())); + packet_queue_.pop_front(); + return packet; +} FakeNetworkSocketServer::FakeNetworkSocketServer( Clock* clock, @@ -34,9 +296,9 @@ EmulatedEndpointImpl* FakeNetworkSocketServer::GetEndpointNode( return endpoints_container_->LookupByLocalAddress(ip); } -void FakeNetworkSocketServer::Unregister(SocketIoProcessor* io_processor) { +void FakeNetworkSocketServer::Unregister(FakeNetworkSocket* socket) { rtc::CritScope crit(&lock_); - io_processors_.erase(io_processor); + sockets_.erase(absl::c_find(sockets_, socket)); } rtc::Socket* FakeNetworkSocketServer::CreateSocket(int /*family*/, @@ -52,7 +314,7 @@ rtc::AsyncSocket* FakeNetworkSocketServer::CreateAsyncSocket(int family, FakeNetworkSocket* out = new FakeNetworkSocket(this); { rtc::CritScope crit(&lock_); - io_processors_.insert(out); + sockets_.push_back(out); } return out; } @@ -75,8 +337,8 @@ bool FakeNetworkSocketServer::Wait(int cms, bool process_io) { wakeup_.Wait(cms); rtc::CritScope crit(&lock_); - for (auto* io_processor : io_processors_) { - while (io_processor->ProcessIo()) { + for (auto* socket : sockets_) { + while (socket->ProcessIo()) { } } return true; diff --git a/test/network/fake_network_socket_server.h b/test/network/fake_network_socket_server.h index 2421469c16..ac026ca4fe 100644 --- a/test/network/fake_network_socket_server.h +++ b/test/network/fake_network_socket_server.h @@ -19,27 +19,25 @@ #include "rtc_base/critical_section.h" #include "rtc_base/event.h" #include "rtc_base/message_queue.h" -#include "rtc_base/socket.h" -#include "rtc_base/socket_address.h" #include "rtc_base/socket_server.h" #include "rtc_base/third_party/sigslot/sigslot.h" #include "system_wrappers/include/clock.h" -#include "test/network/fake_network_socket.h" +#include "test/network/network_emulation.h" namespace webrtc { namespace test { +class FakeNetworkSocket; // FakeNetworkSocketServer must outlive any sockets it creates. class FakeNetworkSocketServer : public rtc::SocketServer, - public sigslot::has_slots<>, - public SocketManager { + public sigslot::has_slots<> { public: FakeNetworkSocketServer(Clock* clock, EndpointsContainer* endpoints_controller); ~FakeNetworkSocketServer() override; - EmulatedEndpointImpl* GetEndpointNode(const rtc::IPAddress& ip) override; - void Unregister(SocketIoProcessor* io_processor) override; + EmulatedEndpointImpl* GetEndpointNode(const rtc::IPAddress& ip); + void Unregister(FakeNetworkSocket* socket); void OnMessageQueueDestroyed(); // rtc::SocketFactory methods: @@ -62,7 +60,7 @@ class FakeNetworkSocketServer : public rtc::SocketServer, rtc::MessageQueue* msg_queue_; rtc::CriticalSection lock_; - std::set io_processors_ RTC_GUARDED_BY(lock_); + std::vector sockets_ RTC_GUARDED_BY(lock_); }; } // namespace test