From fb1db47d6a02fd0443dfeae92cc37b02c9294b28 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 27 Aug 2020 05:14:14 +0000 Subject: [PATCH 001/100] core: add envoy internal address Signed-off-by: Yuchen Dai --- api/envoy/config/core/v3/address.proto | 14 +++++++++ api/envoy/config/core/v4alpha/address.proto | 17 ++++++++++ .../envoy/config/core/v3/address.proto | 14 +++++++++ .../envoy/config/core/v4alpha/address.proto | 17 ++++++++++ include/envoy/network/address.h | 19 +++++++++++- source/common/network/address_impl.cc | 11 +++++++ source/common/network/address_impl.h | 31 +++++++++++++++++++ source/common/network/resolver_impl.cc | 18 +++++++++-- source/common/upstream/upstream_impl.cc | 1 + test/common/network/dns_impl_test.cc | 3 ++ test/common/network/resolver_impl_test.cc | 2 +- test/mocks/network/mocks.h | 1 + 12 files changed, 144 insertions(+), 4 deletions(-) diff --git a/api/envoy/config/core/v3/address.proto b/api/envoy/config/core/v3/address.proto index 5102c2d57591..21297db2bc9b 100644 --- a/api/envoy/config/core/v3/address.proto +++ b/api/envoy/config/core/v3/address.proto @@ -30,6 +30,18 @@ message Pipe { uint32 mode = 2 [(validate.rules).uint32 = {lte: 511}]; } +// [#not-implemented-hide:] The address representing an envoy internal listener, or a client connecting to that listener. +message EnvoyInternalAddress { + oneof address_name_specifier { + option (validate.required) = true; + + // The address is the name of a internal listener. + string server_listener_name = 1; + + string client_address_id = 2; + } +} + // [#next-free-field: 7] message SocketAddress { option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.core.SocketAddress"; @@ -129,6 +141,8 @@ message Address { SocketAddress socket_address = 1; Pipe pipe = 2; + + EnvoyInternalAddress envoy_internal_address = 3; } } diff --git a/api/envoy/config/core/v4alpha/address.proto b/api/envoy/config/core/v4alpha/address.proto index ffade4bed75b..18761ebb6637 100644 --- a/api/envoy/config/core/v4alpha/address.proto +++ b/api/envoy/config/core/v4alpha/address.proto @@ -30,6 +30,21 @@ message Pipe { uint32 mode = 2 [(validate.rules).uint32 = {lte: 511}]; } +// [#not-implemented-hide:] The address representing an envoy internal listener, or a client connecting to that listener. +message EnvoyInternalAddress { + option (udpa.annotations.versioning).previous_message_type = + "envoy.config.core.v3.EnvoyInternalAddress"; + + oneof address_name_specifier { + option (validate.required) = true; + + // The address is the name of a internal listener. + string server_listener_name = 1; + + string client_address_id = 2; + } +} + // [#next-free-field: 7] message SocketAddress { option (udpa.annotations.versioning).previous_message_type = "envoy.config.core.v3.SocketAddress"; @@ -129,6 +144,8 @@ message Address { SocketAddress socket_address = 1; Pipe pipe = 2; + + EnvoyInternalAddress envoy_internal_address = 3; } } diff --git a/generated_api_shadow/envoy/config/core/v3/address.proto b/generated_api_shadow/envoy/config/core/v3/address.proto index 5102c2d57591..21297db2bc9b 100644 --- a/generated_api_shadow/envoy/config/core/v3/address.proto +++ b/generated_api_shadow/envoy/config/core/v3/address.proto @@ -30,6 +30,18 @@ message Pipe { uint32 mode = 2 [(validate.rules).uint32 = {lte: 511}]; } +// [#not-implemented-hide:] The address representing an envoy internal listener, or a client connecting to that listener. +message EnvoyInternalAddress { + oneof address_name_specifier { + option (validate.required) = true; + + // The address is the name of a internal listener. + string server_listener_name = 1; + + string client_address_id = 2; + } +} + // [#next-free-field: 7] message SocketAddress { option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.core.SocketAddress"; @@ -129,6 +141,8 @@ message Address { SocketAddress socket_address = 1; Pipe pipe = 2; + + EnvoyInternalAddress envoy_internal_address = 3; } } diff --git a/generated_api_shadow/envoy/config/core/v4alpha/address.proto b/generated_api_shadow/envoy/config/core/v4alpha/address.proto index ffade4bed75b..18761ebb6637 100644 --- a/generated_api_shadow/envoy/config/core/v4alpha/address.proto +++ b/generated_api_shadow/envoy/config/core/v4alpha/address.proto @@ -30,6 +30,21 @@ message Pipe { uint32 mode = 2 [(validate.rules).uint32 = {lte: 511}]; } +// [#not-implemented-hide:] The address representing an envoy internal listener, or a client connecting to that listener. +message EnvoyInternalAddress { + option (udpa.annotations.versioning).previous_message_type = + "envoy.config.core.v3.EnvoyInternalAddress"; + + oneof address_name_specifier { + option (validate.required) = true; + + // The address is the name of a internal listener. + string server_listener_name = 1; + + string client_address_id = 2; + } +} + // [#next-free-field: 7] message SocketAddress { option (udpa.annotations.versioning).previous_message_type = "envoy.config.core.v3.SocketAddress"; @@ -129,6 +144,8 @@ message Address { SocketAddress socket_address = 1; Pipe pipe = 2; + + EnvoyInternalAddress envoy_internal_address = 3; } } diff --git a/include/envoy/network/address.h b/include/envoy/network/address.h index edea7108a7b9..62552c13455a 100644 --- a/include/envoy/network/address.h +++ b/include/envoy/network/address.h @@ -118,7 +118,18 @@ class Pipe { virtual mode_t mode() const PURE; }; -enum class Type { Ip, Pipe }; +class EnvoyInternalAddress { +public: + virtual ~EnvoyInternalAddress() = default; + + /** + * @return The unique id of the internal address. If the address represents the destination + * internal listener, the address id is that listener name. + */ + virtual const std::string& addressId() const PURE; +}; + +enum class Type { Ip, Pipe, EnvoyInternal }; /** * Interface for all network addresses. @@ -166,6 +177,12 @@ class Instance { */ virtual const Pipe* pipe() const PURE; + /** + * @return the envoy internal address information IFF type() == + * Type::EnvoyInternal, otherwise nullptr. + */ + virtual const EnvoyInternalAddress* envoyInternalAddress() const PURE; + /** * @return the underlying structure wherein the address is stored */ diff --git a/source/common/network/address_impl.cc b/source/common/network/address_impl.cc index 2fb068d94674..38308a491f5b 100644 --- a/source/common/network/address_impl.cc +++ b/source/common/network/address_impl.cc @@ -300,6 +300,17 @@ PipeInstance::PipeInstance(const std::string& pipe_path, mode_t mode, bool PipeInstance::operator==(const Instance& rhs) const { return asString() == rhs.asString(); } +EnvoyInternalInstance::EnvoyInternalInstance(const std::string& address_id, + const SocketInterface* sock_interface) + : InstanceBase(Type::EnvoyInternal, sockInterfaceOrDefault(sock_interface)), + internal_address_(address_id) { + friendly_name_ = absl::StrCat("envoy://", address_id); +} + +bool EnvoyInternalInstance::operator==(const Instance& rhs) const { + return rhs.type() == Type::EnvoyInternal && asString() == rhs.asString(); +} + } // namespace Address } // namespace Network } // namespace Envoy diff --git a/source/common/network/address_impl.h b/source/common/network/address_impl.h index 3b3ffd52783f..ca1e1cc84eaa 100644 --- a/source/common/network/address_impl.h +++ b/source/common/network/address_impl.h @@ -10,6 +10,8 @@ #include "envoy/network/address.h" #include "envoy/network/socket.h" +#include "common/common/assert.h" + namespace Envoy { namespace Network { namespace Address { @@ -84,6 +86,7 @@ class Ipv4Instance : public InstanceBase { bool operator==(const Instance& rhs) const override; const Ip* ip() const override { return &ip_; } const Pipe* pipe() const override { return nullptr; } + const EnvoyInternalAddress* envoyInternalAddress() const override { return nullptr; } const sockaddr* sockAddr() const override { return reinterpret_cast(&ip_.ipv4_.address_); } @@ -157,6 +160,7 @@ class Ipv6Instance : public InstanceBase { bool operator==(const Instance& rhs) const override; const Ip* ip() const override { return &ip_; } const Pipe* pipe() const override { return nullptr; } + const EnvoyInternalAddress* envoyInternalAddress() const override { return nullptr; } const sockaddr* sockAddr() const override { return reinterpret_cast(&ip_.ipv6_.address_); } @@ -219,6 +223,7 @@ class PipeInstance : public InstanceBase { bool operator==(const Instance& rhs) const override; const Ip* ip() const override { return nullptr; } const Pipe* pipe() const override { return &pipe_; } + const EnvoyInternalAddress* envoyInternalAddress() const override { return nullptr; } const sockaddr* sockAddr() const override { return reinterpret_cast(&pipe_.address_); } @@ -245,6 +250,32 @@ class PipeInstance : public InstanceBase { PipeHelper pipe_; }; +class EnvoyInternalInstance : public InstanceBase { +public: + /** + * Construct from a string name. + */ + explicit EnvoyInternalInstance(const std::string& envoy_listener_name, + const SocketInterface* sock_interface = nullptr); + + // Network::Address::Instance + bool operator==(const Instance& rhs) const override; + const Ip* ip() const override { return nullptr; } + const Pipe* pipe() const override { return nullptr; } + const EnvoyInternalAddress* envoyInternalAddress() const override { return &internal_address_; } + const sockaddr* sockAddr() const override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } + socklen_t sockAddrLen() const override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } + +private: + struct EnvoyInternalAddressImpl : public EnvoyInternalAddress { + explicit EnvoyInternalAddressImpl(const std::string& address_id) : address_id_(address_id) {} + ~EnvoyInternalAddressImpl() = default; + const std::string& addressId() const override { return address_id_; } + std::string address_id_; + }; + EnvoyInternalAddressImpl internal_address_; +}; + } // namespace Address } // namespace Network } // namespace Envoy diff --git a/source/common/network/resolver_impl.cc b/source/common/network/resolver_impl.cc index a037f2dc69de..bdc4fc9588a2 100644 --- a/source/common/network/resolver_impl.cc +++ b/source/common/network/resolver_impl.cc @@ -48,9 +48,23 @@ InstanceConstSharedPtr resolveProtoAddress(const envoy::config::core::v3::Addres case envoy::config::core::v3::Address::AddressCase::kSocketAddress: return resolveProtoSocketAddress(address.socket_address()); case envoy::config::core::v3::Address::AddressCase::kPipe: - return InstanceConstSharedPtr{new PipeInstance(address.pipe().path())}; + return std::make_shared(address.pipe().path()); + case envoy::config::core::v3::Address::AddressCase::kEnvoyInternalAddress: + switch (address.envoy_internal_address().address_name_specifier_case()) { + case envoy::config::core::v3::EnvoyInternalAddress::AddressNameSpecifierCase:: + kServerListenerName: + return std::make_shared( + address.envoy_internal_address().server_listener_name()); + case envoy::config::core::v3::EnvoyInternalAddress::AddressNameSpecifierCase::kClientAddressId: + return std::make_shared( + address.envoy_internal_address().client_address_id()); + default: + throw EnvoyException("Internal address must be a server listener name or client address id" + + address.DebugString()); + } default: - throw EnvoyException("Address must be a socket or pipe: " + address.DebugString()); + throw EnvoyException("Address must be a socket, pipe or envoy internal: " + + address.DebugString()); } } diff --git a/source/common/upstream/upstream_impl.cc b/source/common/upstream/upstream_impl.cc index d98d672ffd8f..7cbee9a065c7 100644 --- a/source/common/upstream/upstream_impl.cc +++ b/source/common/upstream/upstream_impl.cc @@ -346,6 +346,7 @@ HostImpl::createConnection(Event::Dispatcher& dispatcher, const ClusterInfo& clu } else { connection_options = options; } + ASSERT(!address->envoyInternalAddress()); Network::ClientConnectionPtr connection = dispatcher.createClientConnection( address, cluster.sourceAddress(), socket_factory.createTransportSocket(std::move(transport_socket_options)), diff --git a/test/common/network/dns_impl_test.cc b/test/common/network/dns_impl_test.cc index 678e97852e49..d69622fb09b0 100644 --- a/test/common/network/dns_impl_test.cc +++ b/test/common/network/dns_impl_test.cc @@ -390,6 +390,9 @@ class CustomInstance : public Address::Instance { const std::string& logicalName() const override { return antagonistic_name_; } const Address::Ip* ip() const override { return instance_.ip(); } const Address::Pipe* pipe() const override { return instance_.pipe(); } + const Address::EnvoyInternalAddress* envoyInternalAddress() const override { + return instance_.envoyInternalAddress(); + } const sockaddr* sockAddr() const override { return instance_.sockAddr(); } socklen_t sockAddrLen() const override { return instance_.sockAddrLen(); } Address::Type type() const override { return instance_.type(); } diff --git a/test/common/network/resolver_impl_test.cc b/test/common/network/resolver_impl_test.cc index 6e7c0a5e8b9e..92ed2ee966e5 100644 --- a/test/common/network/resolver_impl_test.cc +++ b/test/common/network/resolver_impl_test.cc @@ -157,7 +157,7 @@ TEST(ResolverTest, NonStandardResolver) { TEST(ResolverTest, UninitializedAddress) { envoy::config::core::v3::Address address; EXPECT_THROW_WITH_MESSAGE(resolveProtoAddress(address), EnvoyException, - "Address must be a socket or pipe: "); + "Address must be a socket, pipe or envoy internal: "); } TEST(ResolverTest, NoSuchResolver) { diff --git a/test/mocks/network/mocks.h b/test/mocks/network/mocks.h index 0097df388d7a..9be29e87c4b0 100644 --- a/test/mocks/network/mocks.h +++ b/test/mocks/network/mocks.h @@ -436,6 +436,7 @@ class MockResolvedAddress : public Address::Instance { MOCK_METHOD(Api::SysCallIntResult, connect, (os_fd_t), (const)); MOCK_METHOD(const Address::Ip*, ip, (), (const)); MOCK_METHOD(const Address::Pipe*, pipe, (), (const)); + MOCK_METHOD(Address::EnvoyInternalAddress*, envoyInternalAddress, (), (const)); MOCK_METHOD(IoHandlePtr, socket, (Socket::Type), (const)); MOCK_METHOD(Address::Type, type, (), (const)); MOCK_METHOD(const sockaddr*, sockAddr, (), (const)); From 6fceaf2df66909d92bfea7e582ead440af32a04e Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 27 Aug 2020 08:40:05 +0000 Subject: [PATCH 002/100] listener: add internal listener api Signed-off-by: Yuchen Dai --- .../listener/v3/internal_listener.proto | 20 +++++++++++++++++++ api/envoy/config/listener/v3/listener.proto | 9 ++++++++- .../listener/v4alpha/internal_listener.proto | 20 +++++++++++++++++++ .../config/listener/v4alpha/listener.proto | 9 ++++++++- .../listener/v3/internal_listener.proto | 20 +++++++++++++++++++ .../envoy/config/listener/v3/listener.proto | 9 ++++++++- .../listener/v4alpha/internal_listener.proto | 20 +++++++++++++++++++ .../config/listener/v4alpha/listener.proto | 9 ++++++++- 8 files changed, 112 insertions(+), 4 deletions(-) create mode 100644 api/envoy/config/listener/v3/internal_listener.proto create mode 100644 api/envoy/config/listener/v4alpha/internal_listener.proto create mode 100644 generated_api_shadow/envoy/config/listener/v3/internal_listener.proto create mode 100644 generated_api_shadow/envoy/config/listener/v4alpha/internal_listener.proto diff --git a/api/envoy/config/listener/v3/internal_listener.proto b/api/envoy/config/listener/v3/internal_listener.proto new file mode 100644 index 000000000000..8fb5bb8c7857 --- /dev/null +++ b/api/envoy/config/listener/v3/internal_listener.proto @@ -0,0 +1,20 @@ +syntax = "proto3"; + +package envoy.config.listener.v3; + +import "udpa/annotations/status.proto"; +import "udpa/annotations/versioning.proto"; + +option java_package = "io.envoyproxy.envoy.config.listener.v3"; +option java_outer_classname = "InternalListenerProto"; +option java_multiple_files = true; +option (udpa.annotations.file_status).package_version_status = ACTIVE; + +// [#not-implemented-hide:] +// [#protodoc-title: internal listener] +// Describes a type of internal listener which expects to serve the cluster in +// the same envoy process. +message InternalListener { + option (udpa.annotations.versioning).previous_message_type = + "envoy.config.listener.v2.InternalListener"; +} diff --git a/api/envoy/config/listener/v3/listener.proto b/api/envoy/config/listener/v3/listener.proto index 88e8ae4ad5b1..2533b25ac083 100644 --- a/api/envoy/config/listener/v3/listener.proto +++ b/api/envoy/config/listener/v3/listener.proto @@ -8,6 +8,7 @@ import "envoy/config/core/v3/base.proto"; import "envoy/config/core/v3/extension.proto"; import "envoy/config/core/v3/socket_option.proto"; import "envoy/config/listener/v3/api_listener.proto"; +import "envoy/config/listener/v3/internal_listener.proto"; import "envoy/config/listener/v3/listener_components.proto"; import "envoy/config/listener/v3/udp_listener_config.proto"; @@ -36,7 +37,7 @@ message ListenerCollection { udpa.core.v1.CollectionEntry entries = 1; } -// [#next-free-field: 25] +// [#next-free-field: 26] message Listener { option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.Listener"; @@ -263,4 +264,10 @@ message Listener { // The maximum length a tcp listener's pending connections queue can grow to. If no value is // provided net.core.somaxconn will be used on Linux and 128 otherwise. google.protobuf.UInt32Value tcp_backlog_size = 24; + + // Used to represent an internal listener, which accepts connection from the cluster in the same envoy process. + // When this field is set, the address field must be :ref:`envoy internal address + // `. + // [#not-implemented-hide:] + InternalListener internal_listener = 25; } diff --git a/api/envoy/config/listener/v4alpha/internal_listener.proto b/api/envoy/config/listener/v4alpha/internal_listener.proto new file mode 100644 index 000000000000..0bffb7e6626d --- /dev/null +++ b/api/envoy/config/listener/v4alpha/internal_listener.proto @@ -0,0 +1,20 @@ +syntax = "proto3"; + +package envoy.config.listener.v4alpha; + +import "udpa/annotations/status.proto"; +import "udpa/annotations/versioning.proto"; + +option java_package = "io.envoyproxy.envoy.config.listener.v4alpha"; +option java_outer_classname = "InternalListenerProto"; +option java_multiple_files = true; +option (udpa.annotations.file_status).package_version_status = NEXT_MAJOR_VERSION_CANDIDATE; + +// [#not-implemented-hide:] +// [#protodoc-title: internal listener] +// Describes a type of internal listener which expects to serve the cluster in +// the same envoy process. +message InternalListener { + option (udpa.annotations.versioning).previous_message_type = + "envoy.config.listener.v3.InternalListener"; +} diff --git a/api/envoy/config/listener/v4alpha/listener.proto b/api/envoy/config/listener/v4alpha/listener.proto index 753f6d733cc0..c09a7ecc6da1 100644 --- a/api/envoy/config/listener/v4alpha/listener.proto +++ b/api/envoy/config/listener/v4alpha/listener.proto @@ -8,6 +8,7 @@ import "envoy/config/core/v4alpha/base.proto"; import "envoy/config/core/v4alpha/extension.proto"; import "envoy/config/core/v4alpha/socket_option.proto"; import "envoy/config/listener/v4alpha/api_listener.proto"; +import "envoy/config/listener/v4alpha/internal_listener.proto"; import "envoy/config/listener/v4alpha/listener_components.proto"; import "envoy/config/listener/v4alpha/udp_listener_config.proto"; @@ -39,7 +40,7 @@ message ListenerCollection { udpa.core.v1.CollectionEntry entries = 1; } -// [#next-free-field: 25] +// [#next-free-field: 26] message Listener { option (udpa.annotations.versioning).previous_message_type = "envoy.config.listener.v3.Listener"; @@ -266,4 +267,10 @@ message Listener { // The maximum length a tcp listener's pending connections queue can grow to. If no value is // provided net.core.somaxconn will be used on Linux and 128 otherwise. google.protobuf.UInt32Value tcp_backlog_size = 24; + + // Used to represent an internal listener, which accepts connection from the cluster in the same envoy process. + // When this field is set, the address field must be :ref:`envoy internal address + // `. + // [#not-implemented-hide:] + InternalListener internal_listener = 25; } diff --git a/generated_api_shadow/envoy/config/listener/v3/internal_listener.proto b/generated_api_shadow/envoy/config/listener/v3/internal_listener.proto new file mode 100644 index 000000000000..8fb5bb8c7857 --- /dev/null +++ b/generated_api_shadow/envoy/config/listener/v3/internal_listener.proto @@ -0,0 +1,20 @@ +syntax = "proto3"; + +package envoy.config.listener.v3; + +import "udpa/annotations/status.proto"; +import "udpa/annotations/versioning.proto"; + +option java_package = "io.envoyproxy.envoy.config.listener.v3"; +option java_outer_classname = "InternalListenerProto"; +option java_multiple_files = true; +option (udpa.annotations.file_status).package_version_status = ACTIVE; + +// [#not-implemented-hide:] +// [#protodoc-title: internal listener] +// Describes a type of internal listener which expects to serve the cluster in +// the same envoy process. +message InternalListener { + option (udpa.annotations.versioning).previous_message_type = + "envoy.config.listener.v2.InternalListener"; +} diff --git a/generated_api_shadow/envoy/config/listener/v3/listener.proto b/generated_api_shadow/envoy/config/listener/v3/listener.proto index d57b12950535..e86db539fa85 100644 --- a/generated_api_shadow/envoy/config/listener/v3/listener.proto +++ b/generated_api_shadow/envoy/config/listener/v3/listener.proto @@ -8,6 +8,7 @@ import "envoy/config/core/v3/base.proto"; import "envoy/config/core/v3/extension.proto"; import "envoy/config/core/v3/socket_option.proto"; import "envoy/config/listener/v3/api_listener.proto"; +import "envoy/config/listener/v3/internal_listener.proto"; import "envoy/config/listener/v3/listener_components.proto"; import "envoy/config/listener/v3/udp_listener_config.proto"; @@ -36,7 +37,7 @@ message ListenerCollection { udpa.core.v1.CollectionEntry entries = 1; } -// [#next-free-field: 25] +// [#next-free-field: 26] message Listener { option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.Listener"; @@ -262,5 +263,11 @@ message Listener { // provided net.core.somaxconn will be used on Linux and 128 otherwise. google.protobuf.UInt32Value tcp_backlog_size = 24; + // Used to represent an internal listener, which accepts connection from the cluster in the same envoy process. + // When this field is set, the address field must be :ref:`envoy internal address + // `. + // [#not-implemented-hide:] + InternalListener internal_listener = 25; + google.protobuf.BoolValue hidden_envoy_deprecated_use_original_dst = 4 [deprecated = true]; } diff --git a/generated_api_shadow/envoy/config/listener/v4alpha/internal_listener.proto b/generated_api_shadow/envoy/config/listener/v4alpha/internal_listener.proto new file mode 100644 index 000000000000..0bffb7e6626d --- /dev/null +++ b/generated_api_shadow/envoy/config/listener/v4alpha/internal_listener.proto @@ -0,0 +1,20 @@ +syntax = "proto3"; + +package envoy.config.listener.v4alpha; + +import "udpa/annotations/status.proto"; +import "udpa/annotations/versioning.proto"; + +option java_package = "io.envoyproxy.envoy.config.listener.v4alpha"; +option java_outer_classname = "InternalListenerProto"; +option java_multiple_files = true; +option (udpa.annotations.file_status).package_version_status = NEXT_MAJOR_VERSION_CANDIDATE; + +// [#not-implemented-hide:] +// [#protodoc-title: internal listener] +// Describes a type of internal listener which expects to serve the cluster in +// the same envoy process. +message InternalListener { + option (udpa.annotations.versioning).previous_message_type = + "envoy.config.listener.v3.InternalListener"; +} diff --git a/generated_api_shadow/envoy/config/listener/v4alpha/listener.proto b/generated_api_shadow/envoy/config/listener/v4alpha/listener.proto index 753f6d733cc0..c09a7ecc6da1 100644 --- a/generated_api_shadow/envoy/config/listener/v4alpha/listener.proto +++ b/generated_api_shadow/envoy/config/listener/v4alpha/listener.proto @@ -8,6 +8,7 @@ import "envoy/config/core/v4alpha/base.proto"; import "envoy/config/core/v4alpha/extension.proto"; import "envoy/config/core/v4alpha/socket_option.proto"; import "envoy/config/listener/v4alpha/api_listener.proto"; +import "envoy/config/listener/v4alpha/internal_listener.proto"; import "envoy/config/listener/v4alpha/listener_components.proto"; import "envoy/config/listener/v4alpha/udp_listener_config.proto"; @@ -39,7 +40,7 @@ message ListenerCollection { udpa.core.v1.CollectionEntry entries = 1; } -// [#next-free-field: 25] +// [#next-free-field: 26] message Listener { option (udpa.annotations.versioning).previous_message_type = "envoy.config.listener.v3.Listener"; @@ -266,4 +267,10 @@ message Listener { // The maximum length a tcp listener's pending connections queue can grow to. If no value is // provided net.core.somaxconn will be used on Linux and 128 otherwise. google.protobuf.UInt32Value tcp_backlog_size = 24; + + // Used to represent an internal listener, which accepts connection from the cluster in the same envoy process. + // When this field is set, the address field must be :ref:`envoy internal address + // `. + // [#not-implemented-hide:] + InternalListener internal_listener = 25; } From df05bbaca192b936994fcf78bed2943b285a9ae1 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 27 Aug 2020 09:36:00 +0000 Subject: [PATCH 003/100] rename Network::ListenerImpl and Network::ListenerCallbacks Signed-off-by: Yuchen Dai --- include/envoy/event/dispatcher.h | 2 +- include/envoy/network/listener.h | 4 +- source/common/event/dispatcher_impl.cc | 6 +- source/common/event/dispatcher_impl.h | 2 +- source/common/network/listener_impl.cc | 16 ++--- source/common/network/listener_impl.h | 9 ++- source/server/config_validation/dispatcher.cc | 2 +- source/server/config_validation/dispatcher.h | 2 +- source/server/connection_handler_impl.h | 4 +- source/server/server.cc | 4 +- test/common/http/codec_client_test.cc | 2 +- test/common/network/connection_impl_test.cc | 2 +- test/common/network/dns_impl_test.cc | 2 +- test/common/network/listener_impl_test.cc | 59 ++++++++++--------- .../transport_sockets/tls/ssl_socket_test.cc | 22 +++---- test/mocks/event/mocks.h | 4 +- test/mocks/network/mocks.cc | 4 +- test/mocks/network/mocks.h | 6 +- test/server/connection_handler_test.cc | 58 +++++++++--------- 19 files changed, 105 insertions(+), 105 deletions(-) diff --git a/include/envoy/event/dispatcher.h b/include/envoy/event/dispatcher.h index 98bb16ea7c38..9fcf55707c99 100644 --- a/include/envoy/event/dispatcher.h +++ b/include/envoy/event/dispatcher.h @@ -152,7 +152,7 @@ class Dispatcher { * @return Network::ListenerPtr a new listener that is owned by the caller. */ virtual Network::ListenerPtr createListener(Network::SocketSharedPtr&& socket, - Network::ListenerCallbacks& cb, bool bind_to_port, + Network::TcpListenerCallbacks& cb, bool bind_to_port, uint32_t backlog_size) PURE; /** diff --git a/include/envoy/network/listener.h b/include/envoy/network/listener.h index d07e9d01d0b4..4a1ff1d01060 100644 --- a/include/envoy/network/listener.h +++ b/include/envoy/network/listener.h @@ -171,9 +171,9 @@ class ListenerConfig { /** * Callbacks invoked by a listener. */ -class ListenerCallbacks { +class TcpListenerCallbacks { public: - virtual ~ListenerCallbacks() = default; + virtual ~TcpListenerCallbacks() = default; /** * Called when a new connection is accepted. diff --git a/source/common/event/dispatcher_impl.cc b/source/common/event/dispatcher_impl.cc index 09827d0ed891..c0cfb93653d1 100644 --- a/source/common/event/dispatcher_impl.cc +++ b/source/common/event/dispatcher_impl.cc @@ -137,11 +137,11 @@ Filesystem::WatcherPtr DispatcherImpl::createFilesystemWatcher() { } Network::ListenerPtr DispatcherImpl::createListener(Network::SocketSharedPtr&& socket, - Network::ListenerCallbacks& cb, + Network::TcpListenerCallbacks& cb, bool bind_to_port, uint32_t backlog_size) { ASSERT(isThreadSafe()); - return std::make_unique(*this, std::move(socket), cb, bind_to_port, - backlog_size); + return std::make_unique(*this, std::move(socket), cb, bind_to_port, + backlog_size); } Network::UdpListenerPtr DispatcherImpl::createUdpListener(Network::SocketSharedPtr&& socket, diff --git a/source/common/event/dispatcher_impl.h b/source/common/event/dispatcher_impl.h index f16abc2c420d..c81498c89f79 100644 --- a/source/common/event/dispatcher_impl.h +++ b/source/common/event/dispatcher_impl.h @@ -60,7 +60,7 @@ class DispatcherImpl : Logger::Loggable, uint32_t events) override; Filesystem::WatcherPtr createFilesystemWatcher() override; Network::ListenerPtr createListener(Network::SocketSharedPtr&& socket, - Network::ListenerCallbacks& cb, bool bind_to_port, + Network::TcpListenerCallbacks& cb, bool bind_to_port, uint32_t backlog_size) override; Network::UdpListenerPtr createUdpListener(Network::SocketSharedPtr&& socket, Network::UdpListenerCallbacks& cb) override; diff --git a/source/common/network/listener_impl.cc b/source/common/network/listener_impl.cc index 5a733c9c4dfa..160989db8e65 100644 --- a/source/common/network/listener_impl.cc +++ b/source/common/network/listener_impl.cc @@ -17,10 +17,10 @@ namespace Envoy { namespace Network { -const absl::string_view ListenerImpl::GlobalMaxCxRuntimeKey = +const absl::string_view TcpListenerImpl::GlobalMaxCxRuntimeKey = "overload.global_downstream_max_connections"; -bool ListenerImpl::rejectCxOverGlobalLimit() { +bool TcpListenerImpl::rejectCxOverGlobalLimit() { // Enforce the global connection limit if necessary, immediately closing the accepted connection. Runtime::Loader* runtime = Runtime::LoaderSingleton::getExisting(); @@ -41,7 +41,7 @@ bool ListenerImpl::rejectCxOverGlobalLimit() { return AcceptedSocketImpl::acceptedSocketCount() >= global_cx_limit; } -void ListenerImpl::onSocketEvent(short flags) { +void TcpListenerImpl::onSocketEvent(short flags) { ASSERT(flags & (Event::FileReadyType::Read)); // TODO(fcoras): Add limit on number of accepted calls per wakeup @@ -90,7 +90,7 @@ void ListenerImpl::onSocketEvent(short flags) { } } -void ListenerImpl::setupServerSocket(Event::DispatcherImpl& dispatcher, Socket& socket) { +void TcpListenerImpl::setupServerSocket(Event::DispatcherImpl& dispatcher, Socket& socket) { socket.ioHandle().listen(backlog_size_); // Although onSocketEvent drains to completion, use level triggered mode to avoid potential @@ -106,17 +106,17 @@ void ListenerImpl::setupServerSocket(Event::DispatcherImpl& dispatcher, Socket& } } -ListenerImpl::ListenerImpl(Event::DispatcherImpl& dispatcher, SocketSharedPtr socket, - ListenerCallbacks& cb, bool bind_to_port, uint32_t backlog_size) +TcpListenerImpl::TcpListenerImpl(Event::DispatcherImpl& dispatcher, SocketSharedPtr socket, + TcpListenerCallbacks& cb, bool bind_to_port, uint32_t backlog_size) : BaseListenerImpl(dispatcher, std::move(socket)), cb_(cb), backlog_size_(backlog_size) { if (bind_to_port) { setupServerSocket(dispatcher, *socket_); } } -void ListenerImpl::enable() { file_event_->setEnabled(Event::FileReadyType::Read); } +void TcpListenerImpl::enable() { file_event_->setEnabled(Event::FileReadyType::Read); } -void ListenerImpl::disable() { file_event_->setEnabled(0); } +void TcpListenerImpl::disable() { file_event_->setEnabled(0); } } // namespace Network } // namespace Envoy diff --git a/source/common/network/listener_impl.h b/source/common/network/listener_impl.h index 61ca54d9d14e..56b6725b36c9 100644 --- a/source/common/network/listener_impl.h +++ b/source/common/network/listener_impl.h @@ -10,12 +10,11 @@ namespace Network { /** * libevent implementation of Network::Listener for TCP. - * TODO(conqerAtapple): Consider renaming the class to `TcpListenerImpl`. */ -class ListenerImpl : public BaseListenerImpl { +class TcpListenerImpl : public BaseListenerImpl { public: - ListenerImpl(Event::DispatcherImpl& dispatcher, SocketSharedPtr socket, ListenerCallbacks& cb, - bool bind_to_port, uint32_t backlog_size); + TcpListenerImpl(Event::DispatcherImpl& dispatcher, SocketSharedPtr socket, + TcpListenerCallbacks& cb, bool bind_to_port, uint32_t backlog_size); void disable() override; void enable() override; @@ -24,7 +23,7 @@ class ListenerImpl : public BaseListenerImpl { protected: void setupServerSocket(Event::DispatcherImpl& dispatcher, Socket& socket); - ListenerCallbacks& cb_; + TcpListenerCallbacks& cb_; const uint32_t backlog_size_; private: diff --git a/source/server/config_validation/dispatcher.cc b/source/server/config_validation/dispatcher.cc index 91bb1dc66d62..3316f58065c2 100644 --- a/source/server/config_validation/dispatcher.cc +++ b/source/server/config_validation/dispatcher.cc @@ -22,7 +22,7 @@ Network::DnsResolverSharedPtr ValidationDispatcher::createDnsResolver( } Network::ListenerPtr ValidationDispatcher::createListener(Network::SocketSharedPtr&&, - Network::ListenerCallbacks&, bool, + Network::TcpListenerCallbacks&, bool, uint32_t) { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } diff --git a/source/server/config_validation/dispatcher.h b/source/server/config_validation/dispatcher.h index d61d3bcc0b43..b5deea61f58d 100644 --- a/source/server/config_validation/dispatcher.h +++ b/source/server/config_validation/dispatcher.h @@ -26,7 +26,7 @@ class ValidationDispatcher : public DispatcherImpl { Network::DnsResolverSharedPtr createDnsResolver(const std::vector& resolvers, const bool use_tcp_for_dns_lookups) override; - Network::ListenerPtr createListener(Network::SocketSharedPtr&&, Network::ListenerCallbacks&, + Network::ListenerPtr createListener(Network::SocketSharedPtr&&, Network::TcpListenerCallbacks&, bool bind_to_port, uint32_t backlog_size) override; protected: diff --git a/source/server/connection_handler_impl.h b/source/server/connection_handler_impl.h index 63a8c97575f3..c481ac8cccb3 100644 --- a/source/server/connection_handler_impl.h +++ b/source/server/connection_handler_impl.h @@ -107,7 +107,7 @@ class ConnectionHandlerImpl : public Network::ConnectionHandler, /** * Wrapper for an active tcp listener owned by this handler. */ - class ActiveTcpListener : public Network::ListenerCallbacks, + class ActiveTcpListener : public Network::TcpListenerCallbacks, public ActiveListenerImplBase, public Network::BalancedConnectionHandler { public: @@ -128,7 +128,7 @@ class ConnectionHandlerImpl : public Network::ConnectionHandler, config_->openConnections().dec(); } - // Network::ListenerCallbacks + // Network::TcpListenerCallbacks void onAccept(Network::ConnectionSocketPtr&& socket) override; void onReject() override { stats_.downstream_global_cx_overflow_.inc(); } diff --git a/source/server/server.cc b/source/server/server.cc index 912665143c98..751971cb7ca1 100644 --- a/source/server/server.cc +++ b/source/server/server.cc @@ -542,11 +542,11 @@ void InstanceImpl::onRuntimeReady() { // If there is no global limit to the number of active connections, warn on startup. // TODO (tonya11en): Move this functionality into the overload manager. - if (!runtime().snapshot().get(Network::ListenerImpl::GlobalMaxCxRuntimeKey)) { + if (!runtime().snapshot().get(Network::TcpListenerImpl::GlobalMaxCxRuntimeKey)) { ENVOY_LOG(warn, "there is no configured limit to the number of allowed active connections. Set a " "limit via the runtime key {}", - Network::ListenerImpl::GlobalMaxCxRuntimeKey); + Network::TcpListenerImpl::GlobalMaxCxRuntimeKey); } } diff --git a/test/common/http/codec_client_test.cc b/test/common/http/codec_client_test.cc index cdd74b8b26bf..48a1dad0da8e 100644 --- a/test/common/http/codec_client_test.cc +++ b/test/common/http/codec_client_test.cc @@ -348,7 +348,7 @@ class CodecNetworkTest : public testing::TestWithParam { Api::ApiPtr api_; Event::DispatcherPtr dispatcher_; std::shared_ptr socket_{nullptr}; - Network::MockListenerCallbacks listener_callbacks_; + Network::MockTcpListenerCallbacks listener_callbacks_; Network::MockConnectionHandler connection_handler_; Network::ListenerPtr listener_; Network::ClientConnectionPtr client_connection_; diff --git a/test/common/network/dns_impl_test.cc b/test/common/network/dns_impl_test.cc index d69622fb09b0..ea83c16c21e7 100644 --- a/test/common/network/dns_impl_test.cc +++ b/test/common/network/dns_impl_test.cc @@ -268,7 +268,7 @@ class TestDnsServerQuery { bool refused_{}; }; -class TestDnsServer : public ListenerCallbacks { +class TestDnsServer : public TcpListenerCallbacks { public: TestDnsServer(Event::Dispatcher& dispatcher) : dispatcher_(dispatcher), record_ttl_(0), stream_info_(dispatcher.timeSource()) {} diff --git a/test/common/network/listener_impl_test.cc b/test/common/network/listener_impl_test.cc index d3a80fea73c0..c12a404f9e49 100644 --- a/test/common/network/listener_impl_test.cc +++ b/test/common/network/listener_impl_test.cc @@ -32,7 +32,7 @@ static void errorCallbackTest(Address::IpVersion version) { auto socket = std::make_shared( Network::Test::getCanonicalLoopbackAddress(version), nullptr, true); - Network::MockListenerCallbacks listener_callbacks; + Network::MockTcpListenerCallbacks listener_callbacks; Network::MockConnectionHandler connection_handler; Network::ListenerPtr listener = dispatcher->createListener(socket, listener_callbacks, true, ENVOY_TCP_BACKLOG_SIZE); @@ -63,23 +63,24 @@ TEST_P(ListenerImplDeathTest, ErrorCallback) { EXPECT_DEATH(errorCallbackTest(GetParam()), ".*listener accept failure.*"); } -class TestListenerImpl : public ListenerImpl { +class TestTcpListenerImpl : public TcpListenerImpl { public: - TestListenerImpl(Event::DispatcherImpl& dispatcher, SocketSharedPtr socket, ListenerCallbacks& cb, - bool bind_to_port, uint32_t tcp_backlog = ENVOY_TCP_BACKLOG_SIZE) - : ListenerImpl(dispatcher, std::move(socket), cb, bind_to_port, tcp_backlog) {} + TestTcpListenerImpl(Event::DispatcherImpl& dispatcher, SocketSharedPtr socket, + TcpListenerCallbacks& cb, bool bind_to_port, + uint32_t tcp_backlog = ENVOY_TCP_BACKLOG_SIZE) + : TcpListenerImpl(dispatcher, std::move(socket), cb, bind_to_port, tcp_backlog) {} MOCK_METHOD(Address::InstanceConstSharedPtr, getLocalAddress, (os_fd_t fd)); }; -using ListenerImplTest = ListenerImplTestBase; -INSTANTIATE_TEST_SUITE_P(IpVersions, ListenerImplTest, +using TcpListenerImplTest = ListenerImplTestBase; +INSTANTIATE_TEST_SUITE_P(IpVersions, TcpListenerImplTest, testing::ValuesIn(TestEnvironment::getIpVersionsForTest()), TestUtility::ipTestParamsToString); // Test that socket options are set after the listener is setup. -TEST_P(ListenerImplTest, SetListeningSocketOptionsSuccess) { - Network::MockListenerCallbacks listener_callbacks; +TEST_P(TcpListenerImplTest, SetListeningSocketOptionsSuccess) { + Network::MockTcpListenerCallbacks listener_callbacks; Network::MockConnectionHandler connection_handler; auto socket = std::make_shared( @@ -88,12 +89,12 @@ TEST_P(ListenerImplTest, SetListeningSocketOptionsSuccess) { socket->addOption(option); EXPECT_CALL(*option, setOption(_, envoy::config::core::v3::SocketOption::STATE_LISTENING)) .WillOnce(Return(true)); - TestListenerImpl listener(dispatcherImpl(), socket, listener_callbacks, true); + TestTcpListenerImpl listener(dispatcherImpl(), socket, listener_callbacks, true); } // Test that an exception is thrown if there is an error setting socket options. -TEST_P(ListenerImplTest, SetListeningSocketOptionsError) { - Network::MockListenerCallbacks listener_callbacks; +TEST_P(TcpListenerImplTest, SetListeningSocketOptionsError) { + Network::MockTcpListenerCallbacks listener_callbacks; Network::MockConnectionHandler connection_handler; auto socket = std::make_shared( @@ -102,22 +103,22 @@ TEST_P(ListenerImplTest, SetListeningSocketOptionsError) { socket->addOption(option); EXPECT_CALL(*option, setOption(_, envoy::config::core::v3::SocketOption::STATE_LISTENING)) .WillOnce(Return(false)); - EXPECT_THROW_WITH_MESSAGE(TestListenerImpl(dispatcherImpl(), socket, listener_callbacks, true), + EXPECT_THROW_WITH_MESSAGE(TestTcpListenerImpl(dispatcherImpl(), socket, listener_callbacks, true), CreateListenerException, fmt::format("cannot set post-listen socket option on socket: {}", socket->localAddress()->asString())); } -TEST_P(ListenerImplTest, UseActualDst) { +TEST_P(TcpListenerImplTest, UseActualDst) { auto socket = std::make_shared( Network::Test::getCanonicalLoopbackAddress(version_), nullptr, true); auto socketDst = std::make_shared(alt_address_, nullptr, false); - Network::MockListenerCallbacks listener_callbacks1; + Network::MockTcpListenerCallbacks listener_callbacks1; Network::MockConnectionHandler connection_handler; // Do not redirect since use_original_dst is false. - Network::TestListenerImpl listener(dispatcherImpl(), socket, listener_callbacks1, true); - Network::MockListenerCallbacks listener_callbacks2; - Network::TestListenerImpl listenerDst(dispatcherImpl(), socketDst, listener_callbacks2, false); + Network::TestTcpListenerImpl listener(dispatcherImpl(), socket, listener_callbacks1, true); + Network::MockTcpListenerCallbacks listener_callbacks2; + Network::TestTcpListenerImpl listenerDst(dispatcherImpl(), socketDst, listener_callbacks2, false); Network::ClientConnectionPtr client_connection = dispatcher_->createClientConnection( socket->localAddress(), Network::Address::InstanceConstSharedPtr(), @@ -141,7 +142,7 @@ TEST_P(ListenerImplTest, UseActualDst) { dispatcher_->run(Event::Dispatcher::RunType::Block); } -TEST_P(ListenerImplTest, GlobalConnectionLimitEnforcement) { +TEST_P(TcpListenerImplTest, GlobalConnectionLimitEnforcement) { // Required to manipulate runtime values when there is no test server. TestScopedRuntime scoped_runtime; @@ -149,7 +150,7 @@ TEST_P(ListenerImplTest, GlobalConnectionLimitEnforcement) { {{"overload.global_downstream_max_connections", "2"}}); auto socket = std::make_shared( Network::Test::getCanonicalLoopbackAddress(version_), nullptr, true); - Network::MockListenerCallbacks listener_callbacks; + Network::MockTcpListenerCallbacks listener_callbacks; Network::MockConnectionHandler connection_handler; Network::ListenerPtr listener = dispatcher_->createListener(socket, listener_callbacks, true, ENVOY_TCP_BACKLOG_SIZE); @@ -208,13 +209,13 @@ TEST_P(ListenerImplTest, GlobalConnectionLimitEnforcement) { {{"overload.global_downstream_max_connections", ""}}); } -TEST_P(ListenerImplTest, WildcardListenerUseActualDst) { +TEST_P(TcpListenerImplTest, WildcardListenerUseActualDst) { auto socket = std::make_shared( Network::Test::getCanonicalLoopbackAddress(version_), nullptr, true); - Network::MockListenerCallbacks listener_callbacks; + Network::MockTcpListenerCallbacks listener_callbacks; Network::MockConnectionHandler connection_handler; // Do not redirect since use_original_dst is false. - Network::TestListenerImpl listener(dispatcherImpl(), socket, listener_callbacks, true); + Network::TestTcpListenerImpl listener(dispatcherImpl(), socket, listener_callbacks, true); auto local_dst_address = Network::Utility::getAddressWithPort( *Network::Test::getCanonicalLoopbackAddress(version_), socket->localAddress()->ip()->port()); @@ -241,7 +242,7 @@ TEST_P(ListenerImplTest, WildcardListenerUseActualDst) { // receiving IPv4 connections on an IPv6 socket. In this case the address instances of both // local and remote addresses of the connection should be IPv4 instances, as the connection really // is an IPv4 connection. -TEST_P(ListenerImplTest, WildcardListenerIpv4Compat) { +TEST_P(TcpListenerImplTest, WildcardListenerIpv4Compat) { auto option = std::make_unique(); auto options = std::make_shared>(); EXPECT_CALL(*option, setOption(_, envoy::config::core::v3::SocketOption::STATE_PREBIND)) @@ -250,13 +251,13 @@ TEST_P(ListenerImplTest, WildcardListenerIpv4Compat) { auto socket = std::make_shared(Network::Test::getAnyAddress(version_, true), options, true); - Network::MockListenerCallbacks listener_callbacks; + Network::MockTcpListenerCallbacks listener_callbacks; Network::MockConnectionHandler connection_handler; ASSERT_TRUE(socket->localAddress()->ip()->isAnyAddress()); // Do not redirect since use_original_dst is false. - Network::TestListenerImpl listener(dispatcherImpl(), socket, listener_callbacks, true); + Network::TestTcpListenerImpl listener(dispatcherImpl(), socket, listener_callbacks, true); auto listener_address = Network::Utility::getAddressWithPort( *Network::Test::getCanonicalLoopbackAddress(version_), socket->localAddress()->ip()->port()); @@ -283,14 +284,14 @@ TEST_P(ListenerImplTest, WildcardListenerIpv4Compat) { dispatcher_->run(Event::Dispatcher::RunType::Block); } -TEST_P(ListenerImplTest, DisableAndEnableListener) { +TEST_P(TcpListenerImplTest, DisableAndEnableListener) { testing::InSequence s1; auto socket = std::make_shared( Network::Test::getCanonicalLoopbackAddress(version_), nullptr, true); - MockListenerCallbacks listener_callbacks; + MockTcpListenerCallbacks listener_callbacks; MockConnectionCallbacks connection_callbacks; - TestListenerImpl listener(dispatcherImpl(), socket, listener_callbacks, true); + TestTcpListenerImpl listener(dispatcherImpl(), socket, listener_callbacks, true); // When listener is disabled, the timer should fire before any connection is accepted. listener.disable(); diff --git a/test/extensions/transport_sockets/tls/ssl_socket_test.cc b/test/extensions/transport_sockets/tls/ssl_socket_test.cc index 69a721d3ec3f..4752f40e8912 100644 --- a/test/extensions/transport_sockets/tls/ssl_socket_test.cc +++ b/test/extensions/transport_sockets/tls/ssl_socket_test.cc @@ -310,7 +310,7 @@ void testUtil(const TestUtilOptions& options) { Event::DispatcherPtr dispatcher = server_api->allocateDispatcher("test_thread"); auto socket = std::make_shared( Network::Test::getCanonicalLoopbackAddress(options.version()), nullptr, true); - Network::MockListenerCallbacks callbacks; + Network::MockTcpListenerCallbacks callbacks; Network::MockConnectionHandler connection_handler; Network::ListenerPtr listener = dispatcher->createListener(socket, callbacks, true, ENVOY_TCP_BACKLOG_SIZE); @@ -612,7 +612,7 @@ const std::string testUtilV2(const TestUtilOptionsV2& options) { Event::DispatcherPtr dispatcher(server_api->allocateDispatcher("test_thread")); auto socket = std::make_shared( Network::Test::getCanonicalLoopbackAddress(options.version()), nullptr, true); - NiceMock callbacks; + NiceMock callbacks; Network::MockConnectionHandler connection_handler; Network::ListenerPtr listener = dispatcher->createListener(socket, callbacks, true, ENVOY_TCP_BACKLOG_SIZE); @@ -2404,7 +2404,7 @@ TEST_P(SslSocketTest, FlushCloseDuringHandshake) { auto socket = std::make_shared( Network::Test::getCanonicalLoopbackAddress(GetParam()), nullptr, true); - Network::MockListenerCallbacks callbacks; + Network::MockTcpListenerCallbacks callbacks; Network::MockConnectionHandler connection_handler; Network::ListenerPtr listener = dispatcher_->createListener(socket, callbacks, true, ENVOY_TCP_BACKLOG_SIZE); @@ -2461,7 +2461,7 @@ TEST_P(SslSocketTest, HalfClose) { auto socket = std::make_shared( Network::Test::getCanonicalLoopbackAddress(GetParam()), nullptr, true); - Network::MockListenerCallbacks listener_callbacks; + Network::MockTcpListenerCallbacks listener_callbacks; Network::MockConnectionHandler connection_handler; Network::ListenerPtr listener = dispatcher_->createListener(socket, listener_callbacks, true, ENVOY_TCP_BACKLOG_SIZE); @@ -2544,7 +2544,7 @@ TEST_P(SslSocketTest, ClientAuthMultipleCAs) { auto socket = std::make_shared( Network::Test::getCanonicalLoopbackAddress(GetParam()), nullptr, true); - Network::MockListenerCallbacks callbacks; + Network::MockTcpListenerCallbacks callbacks; Network::MockConnectionHandler connection_handler; Network::ListenerPtr listener = dispatcher_->createListener(socket, callbacks, true, ENVOY_TCP_BACKLOG_SIZE); @@ -2642,7 +2642,7 @@ void testTicketSessionResumption(const std::string& server_ctx_yaml1, Network::Test::getCanonicalLoopbackAddress(ip_version), nullptr, true); auto socket2 = std::make_shared( Network::Test::getCanonicalLoopbackAddress(ip_version), nullptr, true); - NiceMock callbacks; + NiceMock callbacks; Network::MockConnectionHandler connection_handler; Event::DispatcherPtr dispatcher(server_api->allocateDispatcher("test_thread")); Network::ListenerPtr listener1 = @@ -2780,7 +2780,7 @@ void testSupportForStatelessSessionResumption(const std::string& server_ctx_yaml server_stats_store, {}); auto tcp_socket = std::make_shared( Network::Test::getCanonicalLoopbackAddress(ip_version), nullptr, true); - NiceMock callbacks; + NiceMock callbacks; Network::MockConnectionHandler connection_handler; Event::DispatcherPtr dispatcher(server_api->allocateDispatcher("test_thread")); Network::ListenerPtr listener = @@ -3224,7 +3224,7 @@ TEST_P(SslSocketTest, ClientAuthCrossListenerSessionResumption) { Network::Test::getCanonicalLoopbackAddress(GetParam()), nullptr, true); auto socket2 = std::make_shared( Network::Test::getCanonicalLoopbackAddress(GetParam()), nullptr, true); - Network::MockListenerCallbacks callbacks; + Network::MockTcpListenerCallbacks callbacks; Network::MockConnectionHandler connection_handler; Network::ListenerPtr listener = dispatcher_->createListener(socket, callbacks, true, ENVOY_TCP_BACKLOG_SIZE); @@ -3339,7 +3339,7 @@ void SslSocketTest::testClientSessionResumption(const std::string& server_ctx_ya auto socket = std::make_shared( Network::Test::getCanonicalLoopbackAddress(version), nullptr, true); - NiceMock callbacks; + NiceMock callbacks; Network::MockConnectionHandler connection_handler; Api::ApiPtr api = Api::createApiForTest(server_stats_store, time_system_); Event::DispatcherPtr dispatcher(server_api->allocateDispatcher("test_thread")); @@ -3602,7 +3602,7 @@ TEST_P(SslSocketTest, SslError) { auto socket = std::make_shared( Network::Test::getCanonicalLoopbackAddress(GetParam()), nullptr, true); - Network::MockListenerCallbacks callbacks; + Network::MockTcpListenerCallbacks callbacks; Network::MockConnectionHandler connection_handler; Network::ListenerPtr listener = dispatcher_->createListener(socket, callbacks, true, ENVOY_TCP_BACKLOG_SIZE); @@ -4684,7 +4684,7 @@ class SslReadBufferLimitTest : public SslSocketTest { Stats::TestUtil::TestStore server_stats_store_; Stats::TestUtil::TestStore client_stats_store_; std::shared_ptr socket_; - Network::MockListenerCallbacks listener_callbacks_; + Network::MockTcpListenerCallbacks listener_callbacks_; Network::MockConnectionHandler connection_handler_; const std::string server_ctx_yaml_ = R"EOF( common_tls_context: diff --git a/test/mocks/event/mocks.h b/test/mocks/event/mocks.h index 187df9f15e8d..605005fe471a 100644 --- a/test/mocks/event/mocks.h +++ b/test/mocks/event/mocks.h @@ -64,7 +64,7 @@ class MockDispatcher : public Dispatcher { } Network::ListenerPtr createListener(Network::SocketSharedPtr&& socket, - Network::ListenerCallbacks& cb, bool bind_to_port, + Network::TcpListenerCallbacks& cb, bool bind_to_port, uint32_t backlog_size) override { return Network::ListenerPtr{createListener_(std::move(socket), cb, bind_to_port, backlog_size)}; } @@ -115,7 +115,7 @@ class MockDispatcher : public Dispatcher { (os_fd_t fd, FileReadyCb cb, FileTriggerType trigger, uint32_t events)); MOCK_METHOD(Filesystem::Watcher*, createFilesystemWatcher_, ()); MOCK_METHOD(Network::Listener*, createListener_, - (Network::SocketSharedPtr && socket, Network::ListenerCallbacks& cb, + (Network::SocketSharedPtr && socket, Network::TcpListenerCallbacks& cb, bool bind_to_port, uint32_t backlog_size)); MOCK_METHOD(Network::UdpListener*, createUdpListener_, (Network::SocketSharedPtr && socket, Network::UdpListenerCallbacks& cb)); diff --git a/test/mocks/network/mocks.cc b/test/mocks/network/mocks.cc index 61369918ef9e..3f203fe7e343 100644 --- a/test/mocks/network/mocks.cc +++ b/test/mocks/network/mocks.cc @@ -93,8 +93,8 @@ MockFilter::MockFilter() { MockFilter::~MockFilter() = default; -MockListenerCallbacks::MockListenerCallbacks() = default; -MockListenerCallbacks::~MockListenerCallbacks() = default; +MockTcpListenerCallbacks::MockTcpListenerCallbacks() = default; +MockTcpListenerCallbacks::~MockTcpListenerCallbacks() = default; MockUdpListenerCallbacks::MockUdpListenerCallbacks() = default; MockUdpListenerCallbacks::~MockUdpListenerCallbacks() = default; diff --git a/test/mocks/network/mocks.h b/test/mocks/network/mocks.h index 9be29e87c4b0..541a4cb09758 100644 --- a/test/mocks/network/mocks.h +++ b/test/mocks/network/mocks.h @@ -123,10 +123,10 @@ class MockFilter : public Filter { WriteFilterCallbacks* write_callbacks_{}; }; -class MockListenerCallbacks : public ListenerCallbacks { +class MockTcpListenerCallbacks : public TcpListenerCallbacks { public: - MockListenerCallbacks(); - ~MockListenerCallbacks() override; + MockTcpListenerCallbacks(); + ~MockTcpListenerCallbacks() override; void onAccept(ConnectionSocketPtr&& socket) override { onAccept_(socket); } diff --git a/test/server/connection_handler_test.cc b/test/server/connection_handler_test.cc index 7ee24468032b..ce005c707ce0 100644 --- a/test/server/connection_handler_test.cc +++ b/test/server/connection_handler_test.cc @@ -175,7 +175,7 @@ class ConnectionHandlerTest : public testing::Test, protected Logger::Loggable Network::Listener* { if (listener_callbacks != nullptr) { *listener_callbacks = &cb; @@ -248,7 +248,7 @@ TEST_F(ConnectionHandlerTest, RemoveListenerDuringRebalance) { // So we just leak the FDs for this test. ON_CALL(os_sys_calls_, close(_)).WillByDefault(Return(Api::SysCallIntResult{0, 0})); - Network::ListenerCallbacks* listener_callbacks; + Network::TcpListenerCallbacks* listener_callbacks; auto listener = new NiceMock(); Network::MockConnectionBalancer* connection_balancer = new Network::MockConnectionBalancer(); Network::BalancedConnectionHandler* current_handler; @@ -286,7 +286,7 @@ TEST_F(ConnectionHandlerTest, RemoveListenerDuringRebalance) { } TEST_F(ConnectionHandlerTest, ListenerConnectionLimitEnforced) { - Network::ListenerCallbacks* listener_callbacks1; + Network::TcpListenerCallbacks* listener_callbacks1; auto listener1 = new NiceMock(); TestListener* test_listener1 = addListener(1, false, false, "test_listener1", listener1, &listener_callbacks1); @@ -298,7 +298,7 @@ TEST_F(ConnectionHandlerTest, ListenerConnectionLimitEnforced) { handler_->addListener(absl::nullopt, *test_listener1); auto listener2 = new NiceMock(); - Network::ListenerCallbacks* listener_callbacks2; + Network::TcpListenerCallbacks* listener_callbacks2; TestListener* test_listener2 = addListener(2, false, false, "test_listener2", listener2, &listener_callbacks2); Network::Address::InstanceConstSharedPtr alt_address( @@ -370,7 +370,7 @@ TEST_F(ConnectionHandlerTest, ListenerConnectionLimitEnforced) { TEST_F(ConnectionHandlerTest, RemoveListener) { InSequence s; - Network::ListenerCallbacks* listener_callbacks; + Network::TcpListenerCallbacks* listener_callbacks; auto listener = new NiceMock(); TestListener* test_listener = addListener(1, true, false, "test_listener", listener, &listener_callbacks); @@ -400,7 +400,7 @@ TEST_F(ConnectionHandlerTest, RemoveListener) { TEST_F(ConnectionHandlerTest, DisableListener) { InSequence s; - Network::ListenerCallbacks* listener_callbacks; + Network::TcpListenerCallbacks* listener_callbacks; auto listener = new NiceMock(); TestListener* test_listener = addListener(1, false, false, "test_listener", listener, &listener_callbacks); @@ -416,7 +416,7 @@ TEST_F(ConnectionHandlerTest, DisableListener) { TEST_F(ConnectionHandlerTest, AddDisabledListener) { InSequence s; - Network::ListenerCallbacks* listener_callbacks; + Network::TcpListenerCallbacks* listener_callbacks; auto listener = new NiceMock(); TestListener* test_listener = addListener(1, false, false, "test_listener", listener, &listener_callbacks); @@ -431,7 +431,7 @@ TEST_F(ConnectionHandlerTest, AddDisabledListener) { TEST_F(ConnectionHandlerTest, DestroyCloseConnections) { InSequence s; - Network::ListenerCallbacks* listener_callbacks; + Network::TcpListenerCallbacks* listener_callbacks; auto listener = new NiceMock(); TestListener* test_listener = addListener(1, true, false, "test_listener", listener, &listener_callbacks); @@ -450,7 +450,7 @@ TEST_F(ConnectionHandlerTest, DestroyCloseConnections) { TEST_F(ConnectionHandlerTest, CloseDuringFilterChainCreate) { InSequence s; - Network::ListenerCallbacks* listener_callbacks; + Network::TcpListenerCallbacks* listener_callbacks; auto listener = new NiceMock(); TestListener* test_listener = addListener(1, true, false, "test_listener", listener, &listener_callbacks); @@ -473,7 +473,7 @@ TEST_F(ConnectionHandlerTest, CloseDuringFilterChainCreate) { TEST_F(ConnectionHandlerTest, CloseConnectionOnEmptyFilterChain) { InSequence s; - Network::ListenerCallbacks* listener_callbacks; + Network::TcpListenerCallbacks* listener_callbacks; auto listener = new NiceMock(); TestListener* test_listener = addListener(1, true, false, "test_listener", listener, &listener_callbacks); @@ -494,7 +494,7 @@ TEST_F(ConnectionHandlerTest, CloseConnectionOnEmptyFilterChain) { } TEST_F(ConnectionHandlerTest, NormalRedirect) { - Network::ListenerCallbacks* listener_callbacks1; + Network::TcpListenerCallbacks* listener_callbacks1; auto listener1 = new NiceMock(); TestListener* test_listener1 = addListener(1, true, true, "test_listener1", listener1, &listener_callbacks1); @@ -503,7 +503,7 @@ TEST_F(ConnectionHandlerTest, NormalRedirect) { EXPECT_CALL(*socket_factory_, localAddress()).WillRepeatedly(ReturnRef(normal_address)); handler_->addListener(absl::nullopt, *test_listener1); - Network::ListenerCallbacks* listener_callbacks2; + Network::TcpListenerCallbacks* listener_callbacks2; auto listener2 = new NiceMock(); TestListener* test_listener2 = addListener(1, false, false, "test_listener2", listener2, &listener_callbacks2); @@ -556,7 +556,7 @@ TEST_F(ConnectionHandlerTest, NormalRedirect) { } TEST_F(ConnectionHandlerTest, FallbackToWildcardListener) { - Network::ListenerCallbacks* listener_callbacks1; + Network::TcpListenerCallbacks* listener_callbacks1; auto listener1 = new NiceMock(); TestListener* test_listener1 = addListener(1, true, true, "test_listener1", listener1, &listener_callbacks1); @@ -565,7 +565,7 @@ TEST_F(ConnectionHandlerTest, FallbackToWildcardListener) { EXPECT_CALL(*socket_factory_, localAddress()).WillRepeatedly(ReturnRef(normal_address)); handler_->addListener(absl::nullopt, *test_listener1); - Network::ListenerCallbacks* listener_callbacks2; + Network::TcpListenerCallbacks* listener_callbacks2; auto listener2 = new NiceMock(); TestListener* test_listener2 = addListener(1, false, false, "test_listener2", listener2, &listener_callbacks2); @@ -610,7 +610,7 @@ TEST_F(ConnectionHandlerTest, FallbackToWildcardListener) { } TEST_F(ConnectionHandlerTest, WildcardListenerWithOriginalDst) { - Network::ListenerCallbacks* listener_callbacks1; + Network::TcpListenerCallbacks* listener_callbacks1; auto listener1 = new NiceMock(); TestListener* test_listener1 = addListener(1, true, true, "test_listener1", listener1, &listener_callbacks1); @@ -652,7 +652,7 @@ TEST_F(ConnectionHandlerTest, WildcardListenerWithOriginalDst) { } TEST_F(ConnectionHandlerTest, WildcardListenerWithNoOriginalDst) { - Network::ListenerCallbacks* listener_callbacks1; + Network::TcpListenerCallbacks* listener_callbacks1; auto listener1 = new NiceMock(); TestListener* test_listener1 = addListener(1, true, true, "test_listener1", listener1, &listener_callbacks1); @@ -687,7 +687,7 @@ TEST_F(ConnectionHandlerTest, WildcardListenerWithNoOriginalDst) { } TEST_F(ConnectionHandlerTest, TransportProtocolDefault) { - Network::ListenerCallbacks* listener_callbacks; + Network::TcpListenerCallbacks* listener_callbacks; auto listener = new NiceMock(); TestListener* test_listener = addListener(1, true, false, "test_listener", listener, &listener_callbacks); @@ -705,7 +705,7 @@ TEST_F(ConnectionHandlerTest, TransportProtocolDefault) { } TEST_F(ConnectionHandlerTest, TransportProtocolCustom) { - Network::ListenerCallbacks* listener_callbacks; + Network::TcpListenerCallbacks* listener_callbacks; auto listener = new NiceMock(); TestListener* test_listener = addListener(1, true, false, "test_listener", listener, &listener_callbacks); @@ -738,7 +738,7 @@ TEST_F(ConnectionHandlerTest, TransportProtocolCustom) { TEST_F(ConnectionHandlerTest, ListenerFilterTimeout) { InSequence s; - Network::ListenerCallbacks* listener_callbacks; + Network::TcpListenerCallbacks* listener_callbacks; auto listener = new NiceMock(); TestListener* test_listener = addListener(1, true, false, "test_listener", listener, &listener_callbacks); @@ -782,7 +782,7 @@ TEST_F(ConnectionHandlerTest, ListenerFilterTimeout) { TEST_F(ConnectionHandlerTest, ContinueOnListenerFilterTimeout) { InSequence s; - Network::ListenerCallbacks* listener_callbacks; + Network::TcpListenerCallbacks* listener_callbacks; auto listener = new NiceMock(); TestListener* test_listener = addListener(1, true, false, "test_listener", listener, &listener_callbacks, nullptr, nullptr, @@ -828,7 +828,7 @@ TEST_F(ConnectionHandlerTest, ContinueOnListenerFilterTimeout) { TEST_F(ConnectionHandlerTest, ListenerFilterTimeoutResetOnSuccess) { InSequence s; - Network::ListenerCallbacks* listener_callbacks; + Network::TcpListenerCallbacks* listener_callbacks; auto listener = new NiceMock(); TestListener* test_listener = addListener(1, true, false, "test_listener", listener, &listener_callbacks); @@ -866,7 +866,7 @@ TEST_F(ConnectionHandlerTest, ListenerFilterTimeoutResetOnSuccess) { TEST_F(ConnectionHandlerTest, ListenerFilterDisabledTimeout) { InSequence s; - Network::ListenerCallbacks* listener_callbacks; + Network::TcpListenerCallbacks* listener_callbacks; auto listener = new NiceMock(); TestListener* test_listener = addListener(1, true, false, "test_listener", listener, &listener_callbacks, nullptr, nullptr, @@ -896,7 +896,7 @@ TEST_F(ConnectionHandlerTest, ListenerFilterDisabledTimeout) { TEST_F(ConnectionHandlerTest, ListenerFilterReportError) { InSequence s; - Network::ListenerCallbacks* listener_callbacks; + Network::TcpListenerCallbacks* listener_callbacks; auto listener = new NiceMock(); TestListener* test_listener = addListener(1, true, false, "test_listener", listener, &listener_callbacks); @@ -961,7 +961,7 @@ TEST_F(ConnectionHandlerTest, TcpListenerInplaceUpdate) { InSequence s; uint64_t old_listener_tag = 1; uint64_t new_listener_tag = 2; - Network::ListenerCallbacks* old_listener_callbacks; + Network::TcpListenerCallbacks* old_listener_callbacks; auto old_listener = new NiceMock(); TestListener* old_test_listener = addListener(old_listener_tag, true, false, "test_listener", old_listener, &old_listener_callbacks); @@ -969,7 +969,7 @@ TEST_F(ConnectionHandlerTest, TcpListenerInplaceUpdate) { handler_->addListener(absl::nullopt, *old_test_listener); ASSERT_NE(old_test_listener, nullptr); - Network::ListenerCallbacks* new_listener_callbacks = nullptr; + Network::TcpListenerCallbacks* new_listener_callbacks = nullptr; auto overridden_filter_chain_manager = std::make_shared>(); @@ -991,7 +991,7 @@ TEST_F(ConnectionHandlerTest, TcpListenerInplaceUpdate) { TEST_F(ConnectionHandlerTest, TcpListenerRemoveFilterChain) { InSequence s; uint64_t listener_tag = 1; - Network::ListenerCallbacks* listener_callbacks; + Network::TcpListenerCallbacks* listener_callbacks; auto listener = new NiceMock(); TestListener* test_listener = addListener(listener_tag, true, false, "test_listener", listener, &listener_callbacks); @@ -1032,7 +1032,7 @@ TEST_F(ConnectionHandlerTest, TcpListenerRemoveFilterChain) { // Listener Filter matchers works. TEST_F(ConnectionHandlerTest, ListenerFilterWorks) { - Network::ListenerCallbacks* listener_callbacks; + Network::TcpListenerCallbacks* listener_callbacks; auto listener = new NiceMock(); TestListener* test_listener = addListener(1, true, false, "test_listener", listener, &listener_callbacks); @@ -1098,7 +1098,7 @@ TEST_F(ConnectionHandlerTest, TcpBacklogCustom) { EXPECT_CALL(*socket_factory_, getListenSocket()).WillOnce(Return(listeners_.back()->socket_)); EXPECT_CALL(*socket_factory_, localAddress()).WillOnce(ReturnRef(local_address_)); EXPECT_CALL(dispatcher_, createListener_(_, _, _, _)) - .WillOnce(Invoke([custom_backlog](Network::SocketSharedPtr&&, Network::ListenerCallbacks&, + .WillOnce(Invoke([custom_backlog](Network::SocketSharedPtr&&, Network::TcpListenerCallbacks&, bool, uint32_t backlog) -> Network::Listener* { EXPECT_EQ(custom_backlog, backlog); return nullptr; From d7cac74a9950bf38ca406f7b0654e878fe7e0a57 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 27 Aug 2020 09:45:46 +0000 Subject: [PATCH 004/100] rename file Signed-off-by: Yuchen Dai --- source/common/event/dispatcher_impl.cc | 2 +- source/common/network/BUILD | 4 ++-- .../common/network/{listener_impl.cc => tcp_listener_impl.cc} | 2 +- .../common/network/{listener_impl.h => tcp_listener_impl.h} | 0 source/server/server.cc | 2 +- test/common/network/listener_impl_test.cc | 2 +- .../filters/listener/proxy_protocol/proxy_protocol_test.cc | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) rename source/common/network/{listener_impl.cc => tcp_listener_impl.cc} (99%) rename source/common/network/{listener_impl.h => tcp_listener_impl.h} (100%) diff --git a/source/common/event/dispatcher_impl.cc b/source/common/event/dispatcher_impl.cc index c0cfb93653d1..0c19bddf2db6 100644 --- a/source/common/event/dispatcher_impl.cc +++ b/source/common/event/dispatcher_impl.cc @@ -20,7 +20,7 @@ #include "common/filesystem/watcher_impl.h" #include "common/network/connection_impl.h" #include "common/network/dns_impl.h" -#include "common/network/listener_impl.h" +#include "common/network/tcp_listener_impl.h" #include "common/network/udp_listener_impl.h" #include "event2/event.h" diff --git a/source/common/network/BUILD b/source/common/network/BUILD index 11b6e565bd89..88a6151774d2 100644 --- a/source/common/network/BUILD +++ b/source/common/network/BUILD @@ -229,12 +229,12 @@ envoy_cc_library( name = "listener_lib", srcs = [ "base_listener_impl.cc", - "listener_impl.cc", + "tcp_listener_impl.cc", "udp_listener_impl.cc", ], hdrs = [ "base_listener_impl.h", - "listener_impl.h", + "tcp_listener_impl.h", "udp_listener_impl.h", ], deps = [ diff --git a/source/common/network/listener_impl.cc b/source/common/network/tcp_listener_impl.cc similarity index 99% rename from source/common/network/listener_impl.cc rename to source/common/network/tcp_listener_impl.cc index 160989db8e65..5c39ec692f89 100644 --- a/source/common/network/listener_impl.cc +++ b/source/common/network/tcp_listener_impl.cc @@ -1,4 +1,4 @@ -#include "common/network/listener_impl.h" +#include "common/network/tcp_listener_impl.h" #include "envoy/common/exception.h" #include "envoy/common/platform.h" diff --git a/source/common/network/listener_impl.h b/source/common/network/tcp_listener_impl.h similarity index 100% rename from source/common/network/listener_impl.h rename to source/common/network/tcp_listener_impl.h diff --git a/source/server/server.cc b/source/server/server.cc index 751971cb7ca1..5745de888e68 100644 --- a/source/server/server.cc +++ b/source/server/server.cc @@ -32,9 +32,9 @@ #include "common/local_info/local_info_impl.h" #include "common/memory/stats.h" #include "common/network/address_impl.h" -#include "common/network/listener_impl.h" #include "common/network/socket_interface.h" #include "common/network/socket_interface_impl.h" +#include "common/network/tcp_listener_impl.h" #include "common/protobuf/utility.h" #include "common/router/rds_impl.h" #include "common/runtime/runtime_impl.h" diff --git a/test/common/network/listener_impl_test.cc b/test/common/network/listener_impl_test.cc index c12a404f9e49..8056826de91a 100644 --- a/test/common/network/listener_impl_test.cc +++ b/test/common/network/listener_impl_test.cc @@ -2,7 +2,7 @@ #include "envoy/network/exception.h" #include "common/network/address_impl.h" -#include "common/network/listener_impl.h" +#include "common/network/tcp_listener_impl.h" #include "common/network/utility.h" #include "common/stream_info/stream_info_impl.h" diff --git a/test/extensions/filters/listener/proxy_protocol/proxy_protocol_test.cc b/test/extensions/filters/listener/proxy_protocol/proxy_protocol_test.cc index d74b77b2ad50..03093cdd50c1 100644 --- a/test/extensions/filters/listener/proxy_protocol/proxy_protocol_test.cc +++ b/test/extensions/filters/listener/proxy_protocol/proxy_protocol_test.cc @@ -11,8 +11,8 @@ #include "common/event/dispatcher_impl.h" #include "common/network/connection_balancer_impl.h" #include "common/network/listen_socket_impl.h" -#include "common/network/listener_impl.h" #include "common/network/raw_buffer_socket.h" +#include "common/network/tcp_listener_impl.h" #include "common/network/utility.h" #include "server/connection_handler_impl.h" From be6f09d10157463795a0e3b33ce080a83cbe6404 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 27 Aug 2020 10:42:23 +0000 Subject: [PATCH 005/100] scaffold of internal listener impl Signed-off-by: Yuchen Dai --- include/envoy/network/listener.h | 11 ++ source/common/network/BUILD | 1 + source/server/connection_handler_impl.cc | 177 +++++++++++++++++++++++ source/server/connection_handler_impl.h | 67 +++++++++ 4 files changed, 256 insertions(+) diff --git a/include/envoy/network/listener.h b/include/envoy/network/listener.h index 4a1ff1d01060..13173a3bc845 100644 --- a/include/envoy/network/listener.h +++ b/include/envoy/network/listener.h @@ -187,6 +187,17 @@ class TcpListenerCallbacks { virtual void onReject() PURE; }; +/** + * Callbacks invoked by a internal listener. + */ +class InternalListenerCallbacks { +public: + virtual ~InternalListenerCallbacks() = default; + + virtual void setupNewConnection(Network::ConnectionPtr server_conn, + Network::ConnectionSocketPtr socket) PURE; +}; + /** * Utility struct that encapsulates the information from a udp socket's recvmmsg call. */ diff --git a/source/common/network/BUILD b/source/common/network/BUILD index 88a6151774d2..a7b2c3084a42 100644 --- a/source/common/network/BUILD +++ b/source/common/network/BUILD @@ -234,6 +234,7 @@ envoy_cc_library( ], hdrs = [ "base_listener_impl.h", + "internal_listener_impl.h", "tcp_listener_impl.h", "udp_listener_impl.h", ], diff --git a/source/server/connection_handler_impl.cc b/source/server/connection_handler_impl.cc index c06545703508..a8f2f5afd6f2 100644 --- a/source/server/connection_handler_impl.cc +++ b/source/server/connection_handler_impl.cc @@ -7,6 +7,7 @@ #include "envoy/stats/scope.h" #include "envoy/stats/timespan.h" +#include "common/common/assert.h" #include "common/event/deferred_task.h" #include "common/network/connection_impl.h" #include "common/network/utility.h" @@ -608,5 +609,181 @@ void ActiveRawUdpListener::addReadFilter(Network::UdpListenerReadFilterPtr&& fil Network::UdpListener& ActiveRawUdpListener::udpListener() { return *udp_listener_; } +ConnectionHandlerImpl::ActiveInternalListener::ActiveInternalListener( + ConnectionHandlerImpl& parent, Network::ListenerConfig& config) + : ConnectionHandlerImpl::ActiveListenerImplBase(parent, &config), parent_(parent) {} + +void ConnectionHandlerImpl::ActiveInternalListener::updateListenerConfig( + Network::ListenerConfig& config) { + ENVOY_LOG(trace, "replacing listener ", config_->listenerTag(), " by ", config.listenerTag()); + config_ = &config; +} + +ConnectionHandlerImpl::ActiveInternalListener::~ActiveInternalListener() { + is_deleting_ = true; + + // Purge sockets that have not progressed to connections. This should only happen when + // a listener filter stops iteration and never resumes. + while (!sockets_.empty()) { + ActiveTcpSocketPtr removed = sockets_.front()->removeFromList(sockets_); + parent_.dispatcher_.deferredDelete(std::move(removed)); + } + + for (auto& chain_and_connections : connections_by_context_) { + ASSERT(chain_and_connections.second != nullptr); + auto& connections = chain_and_connections.second->connections_; + while (!connections.empty()) { + connections.front()->connection_->close(Network::ConnectionCloseType::NoFlush); + } + } + parent_.dispatcher_.clearDeferredDeleteList(); + + // By the time a listener is destroyed, in the common case, there should be no connections. + // However, this is not always true if there is an in flight rebalanced connection that is + // being posted. This assert is extremely useful for debugging the common path so we will leave it + // for now. If it becomes a problem (developers hitting this assert when using debug builds) we + // can revisit. This case, if it happens, should be benign on production builds. This case is + // covered in ConnectionHandlerTest::RemoveListenerDuringRebalance. + ASSERT(num_listener_connections_ == 0); +} + +// Copied from newConnection(). Invoked by SetupPipeListener. +void ConnectionHandlerImpl::ActiveInternalListener::setupNewConnection( + Network::ConnectionPtr server_conn, Network::ConnectionSocketPtr socket) { + + auto stream_info = std::make_unique(parent_.dispatcher_.timeSource()); + stream_info->setDownstreamLocalAddress(socket->localAddress()); + stream_info->setDownstreamRemoteAddress(socket->remoteAddress()); + stream_info->setDownstreamDirectRemoteAddress(socket->directRemoteAddress()); + + // TODO(lambdai): refactor + // auto p = dynamic_cast(server_conn.get()); + // ASSERT(p); + // p->setStreamInfo(stream_info.get()); + + // Find matching filter chain. + const auto filter_chain = config_->filterChainManager().findFilterChain(*socket); + if (filter_chain == nullptr) { + ENVOY_LOG(debug, "closing connection: no matching filter chain found"); + stats_.no_filter_chain_match_.inc(); + stream_info->setResponseFlag(StreamInfo::ResponseFlag::NoRouteFound); + stream_info->setResponseCodeDetails(StreamInfo::ResponseCodeDetails::get().FilterChainNotFound); + emitLogs(*config_, *stream_info); + socket->close(); + return; + } + + auto transport_socket = filter_chain->transportSocketFactory().createTransportSocket(nullptr); + stream_info->setDownstreamSslConnection(transport_socket->ssl()); + auto& active_connections = getOrCreateActiveConnections(*filter_chain); + // TODO(lambdai): set stream_info + ActiveTcpConnectionPtr active_connection( + new ActiveTcpConnection(active_connections, std::move(server_conn), + parent_.dispatcher_.timeSource(), std::move(stream_info))); + active_connection->connection_->setBufferLimits(config_->perConnectionBufferLimitBytes()); + + const bool empty_filter_chain = !config_->filterChainFactory().createNetworkFilterChain( + *active_connection->connection_, filter_chain->networkFilterFactories()); + if (empty_filter_chain) { + ENVOY_CONN_LOG(debug, "closing connection: no filters", *active_connection->connection_); + active_connection->connection_->close(Network::ConnectionCloseType::NoFlush); + } + + // If the connection is already closed, we can just let this connection immediately die. + if (active_connection->connection_->state() != Network::Connection::State::Closed) { + ENVOY_CONN_LOG(debug, "new connection", *active_connection->connection_); + active_connection->connection_->addConnectionCallbacks(*active_connection); + LinkedList::moveIntoList(std::move(active_connection), active_connections.connections_); + } +} + +void ConnectionHandlerImpl::ActiveInternalListener::newConnection( + Network::ConnectionSocketPtr&& socket, + const envoy::config::core::v3::Metadata& dynamic_metadata) { + auto stream_info = std::make_unique( + parent_.dispatcher_.timeSource(), StreamInfo::FilterState::LifeSpan::Connection); + stream_info->setDownstreamLocalAddress(socket->localAddress()); + stream_info->setDownstreamRemoteAddress(socket->remoteAddress()); + stream_info->setDownstreamDirectRemoteAddress(socket->directRemoteAddress()); + + // merge from the given dynamic metadata if it's not empty + if (dynamic_metadata.filter_metadata_size() > 0) { + stream_info->dynamicMetadata().MergeFrom(dynamic_metadata); + } + + // Find matching filter chain. + const auto filter_chain = config_->filterChainManager().findFilterChain(*socket); + if (filter_chain == nullptr) { + ENVOY_LOG(debug, "closing connection: no matching filter chain found"); + stats_.no_filter_chain_match_.inc(); + stream_info->setResponseFlag(StreamInfo::ResponseFlag::NoRouteFound); + stream_info->setResponseCodeDetails(StreamInfo::ResponseCodeDetails::get().FilterChainNotFound); + emitLogs(*config_, *stream_info); + socket->close(); + return; + } + + auto transport_socket = filter_chain->transportSocketFactory().createTransportSocket(nullptr); + stream_info->setDownstreamSslConnection(transport_socket->ssl()); + auto& active_connections = getOrCreateActiveConnections(*filter_chain); + Network::ConnectionPtr server_conn_ptr; + server_conn_ptr = parent_.dispatcher_.createServerConnection( + std::move(socket), std::move(transport_socket), *stream_info); + + ActiveTcpConnectionPtr active_connection( + new ActiveTcpConnection(active_connections, std::move(server_conn_ptr), + parent_.dispatcher_.timeSource(), std::move(stream_info))); + active_connection->connection_->setBufferLimits(config_->perConnectionBufferLimitBytes()); + + const bool empty_filter_chain = !config_->filterChainFactory().createNetworkFilterChain( + *active_connection->connection_, filter_chain->networkFilterFactories()); + if (empty_filter_chain) { + ENVOY_CONN_LOG(debug, "closing connection: no filters", *active_connection->connection_); + active_connection->connection_->close(Network::ConnectionCloseType::NoFlush); + } + + // If the connection is already closed, we can just let this connection immediately die. + if (active_connection->connection_->state() != Network::Connection::State::Closed) { + ENVOY_CONN_LOG(debug, "new connection", *active_connection->connection_); + active_connection->connection_->addConnectionCallbacks(*active_connection); + LinkedList::moveIntoList(std::move(active_connection), active_connections.connections_); + } +} + +ConnectionHandlerImpl::ActiveConnections& +ConnectionHandlerImpl::ActiveInternalListener::getOrCreateActiveConnections( + const Network::FilterChain& filter_chain) { + NOT_IMPLEMENTED_GCOVR_EXCL_LINE; + ActiveConnectionsPtr& connections = connections_by_context_[&filter_chain]; + // if (connections == nullptr) { + // connections = std::make_unique(*this, + // filter_chain); + // } + return *connections; +} + +void ConnectionHandlerImpl::ActiveInternalListener::deferredRemoveFilterChains( + const std::list& draining_filter_chains) { + // Need to recover the original deleting state. + const bool was_deleting = is_deleting_; + is_deleting_ = true; + for (const auto* filter_chain : draining_filter_chains) { + auto iter = connections_by_context_.find(filter_chain); + if (iter == connections_by_context_.end()) { + // It is possible when listener is stopping. + } else { + auto& connections = iter->second->connections_; + while (!connections.empty()) { + connections.front()->connection_->close(Network::ConnectionCloseType::NoFlush); + } + // Since is_deleting_ is on, we need to manually remove the map value and drive the iterator. + // Defer delete connection container to avoid race condition in destroying connection. + parent_.dispatcher_.deferredDelete(std::move(iter->second)); + connections_by_context_.erase(iter); + } + } + is_deleting_ = was_deleting; +} + } // namespace Server } // namespace Envoy diff --git a/source/server/connection_handler_impl.h b/source/server/connection_handler_impl.h index c481ac8cccb3..4de5577c28c6 100644 --- a/source/server/connection_handler_impl.h +++ b/source/server/connection_handler_impl.h @@ -189,6 +189,73 @@ class ConnectionHandlerImpl : public Network::ConnectionHandler, bool is_deleting_{false}; }; + /** + * Wrapper for an active internal listener owned by this handler. + */ + class ActiveInternalListener : public Network::InternalListenerCallbacks, + public ActiveListenerImplBase { + public: + ActiveInternalListener(ConnectionHandlerImpl& parent, Network::ListenerConfig& config); + + ~ActiveInternalListener() override; + + void decNumConnections() { + ASSERT(num_listener_connections_ > 0); + --num_listener_connections_; + config_->openConnections().dec(); + } + + // Network::InternalListenerCallbacks + void setupNewConnection(Network::ConnectionPtr server_conn, + Network::ConnectionSocketPtr socket) override; + + // ActiveListenerImplBase + Network::Listener* listener() override { return listener_.get(); } + void pauseListening() override { listener_->disable(); } + void resumeListening() override { listener_->enable(); } + void shutdownListener() override { listener_.reset(); } + + /** + * Remove and destroy an active connection. + * @param connection supplies the connection to remove. + */ + void removeConnection(ActiveTcpConnection& connection); + + /** + * Create a new connection from a socket accepted by the listener. + */ + void newConnection(Network::ConnectionSocketPtr&& socket, + const envoy::config::core::v3::Metadata& dynamic_metadata); + + /** + * Return the active connections container attached with the given filter chain. + */ + ActiveConnections& getOrCreateActiveConnections(const Network::FilterChain& filter_chain); + + /** + * Schedule to remove and destroy the active connections which are not tracked by listener + * config. Caution: The connection are not destroyed yet when function returns. + */ + void deferredRemoveFilterChains( + const std::list& draining_filter_chains); + + /** + * Update the listener config. The follow up connections will see the new config. The existing + * connections are not impacted. + */ + void updateListenerConfig(Network::ListenerConfig& config); + + ConnectionHandlerImpl& parent_; + Network::ListenerPtr listener_; + std::list sockets_; + absl::node_hash_map connections_by_context_; + + // The number of connections currently active on this listener. This is typically used for + // connection balancing across per-handler listeners. + std::atomic num_listener_connections_{}; + bool is_deleting_{false}; + }; + /** * Wrapper for a group of active connections which are attached to the same filter chain context. */ From d305855d91044ddbfca2e20e6592e72da3484323 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 27 Aug 2020 10:57:49 +0000 Subject: [PATCH 006/100] add missing file Signed-off-by: Yuchen Dai --- .../common/network/internal_listener_impl.cc | 45 +++++++++++++++++++ .../common/network/internal_listener_impl.h | 30 +++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 source/common/network/internal_listener_impl.cc create mode 100644 source/common/network/internal_listener_impl.h diff --git a/source/common/network/internal_listener_impl.cc b/source/common/network/internal_listener_impl.cc new file mode 100644 index 000000000000..81a762de9f37 --- /dev/null +++ b/source/common/network/internal_listener_impl.cc @@ -0,0 +1,45 @@ +#include "common/network/internal_listener_impl.h" + +#include "envoy/common/exception.h" +#include "envoy/common/platform.h" +#include "envoy/config/core/v3/base.pb.h" +#include "envoy/network/exception.h" + +#include "common/common/assert.h" +#include "common/common/empty_string.h" +#include "common/common/fmt.h" +#include "common/common/utility.h" +#include "common/event/dispatcher_impl.h" +#include "common/network/address_impl.h" +#include "common/network/io_socket_handle_impl.h" + +namespace Envoy { +namespace Network { + +void InternalListenerImpl::setupInternalListener(Event::DispatcherImpl& dispatcher, + const std::string& listener_id) { + dispatcher.registerPipeFactory( + absl::StrCat("envoy://", pipe_listener_id), + [this](const Address::InstanceConstSharedPtr& address, Network::ConnectionPtr server_conn) { + Network::ConnectionSocketPtr socket = std::make_unique( + nullptr, + // Local + address, + // Remote + std::make_shared("127.0.0.1")); + cb_.setupNewConnection(std::move(server_conn), std::move(socket)); + }); +} + +InternalListenerImpl::InternalListenerImpl(Event::DispatcherImpl& dispatcher, + const std::string& listener_id, + InternalListenerCallbacks& cb); + : BaseListenerImpl(dispatcher, nullptr), cb_(cb) { +} + + void InternalListenerImpl::enable() { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } + + void InternalListenerImpl::disable() { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } + + } // namespace Network + } // namespace Envoy \ No newline at end of file diff --git a/source/common/network/internal_listener_impl.h b/source/common/network/internal_listener_impl.h new file mode 100644 index 000000000000..b0f6517bee6e --- /dev/null +++ b/source/common/network/internal_listener_impl.h @@ -0,0 +1,30 @@ +#pragma once + +#include "envoy/runtime/runtime.h" + +#include "absl/strings/string_view.h" +#include "base_listener_impl.h" + +namespace Envoy { +namespace Network { + +/** + * Listener accepting connection from thread local cluster. + */ +class InternalListenerImpl : public BaseListenerImpl { +public: + InternalListenerImpl(Event::DispatcherImpl& dispatcher, const std::string& listener_id, + InternalListenerCallbacks& cb); + void disable() override; + void enable() override; + +protected: + void setupInternalListener(Event::DispatcherImpl& dispatcher, + const std::string& pipe_listener_id); + +private: + InteranalListenerCallbacks& cb_; +}; + +} // namespace Network +} // namespace Envoy From b6d9da5e24e12ae829387153e9daaaff199015b7 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 27 Aug 2020 22:39:48 +0000 Subject: [PATCH 007/100] remove client address and add tests Signed-off-by: Yuchen Dai --- api/envoy/config/core/v3/address.proto | 7 +++--- api/envoy/config/core/v4alpha/address.proto | 7 +++--- .../envoy/config/core/v3/address.proto | 7 +++--- .../envoy/config/core/v4alpha/address.proto | 7 +++--- source/common/network/address_impl.h | 4 ++-- source/common/network/resolver_impl.cc | 5 +--- test/common/network/address_impl_test.cc | 23 +++++++++++++++---- test/common/network/resolver_impl_test.cc | 8 +++++++ 8 files changed, 41 insertions(+), 27 deletions(-) diff --git a/api/envoy/config/core/v3/address.proto b/api/envoy/config/core/v3/address.proto index 21297db2bc9b..4e8049104e16 100644 --- a/api/envoy/config/core/v3/address.proto +++ b/api/envoy/config/core/v3/address.proto @@ -30,15 +30,14 @@ message Pipe { uint32 mode = 2 [(validate.rules).uint32 = {lte: 511}]; } -// [#not-implemented-hide:] The address representing an envoy internal listener, or a client connecting to that listener. +// The address represents an envoy internal listener. +// [#not-implemented-hide:] message EnvoyInternalAddress { oneof address_name_specifier { option (validate.required) = true; - // The address is the name of a internal listener. + // The :ref:`listener name ` of the destination internal listener. string server_listener_name = 1; - - string client_address_id = 2; } } diff --git a/api/envoy/config/core/v4alpha/address.proto b/api/envoy/config/core/v4alpha/address.proto index 18761ebb6637..e9f5e4868a06 100644 --- a/api/envoy/config/core/v4alpha/address.proto +++ b/api/envoy/config/core/v4alpha/address.proto @@ -30,7 +30,8 @@ message Pipe { uint32 mode = 2 [(validate.rules).uint32 = {lte: 511}]; } -// [#not-implemented-hide:] The address representing an envoy internal listener, or a client connecting to that listener. +// The address represents an envoy internal listener. +// [#not-implemented-hide:] message EnvoyInternalAddress { option (udpa.annotations.versioning).previous_message_type = "envoy.config.core.v3.EnvoyInternalAddress"; @@ -38,10 +39,8 @@ message EnvoyInternalAddress { oneof address_name_specifier { option (validate.required) = true; - // The address is the name of a internal listener. + // The :ref:`listener name ` of the destination internal listener. string server_listener_name = 1; - - string client_address_id = 2; } } diff --git a/generated_api_shadow/envoy/config/core/v3/address.proto b/generated_api_shadow/envoy/config/core/v3/address.proto index 21297db2bc9b..4e8049104e16 100644 --- a/generated_api_shadow/envoy/config/core/v3/address.proto +++ b/generated_api_shadow/envoy/config/core/v3/address.proto @@ -30,15 +30,14 @@ message Pipe { uint32 mode = 2 [(validate.rules).uint32 = {lte: 511}]; } -// [#not-implemented-hide:] The address representing an envoy internal listener, or a client connecting to that listener. +// The address represents an envoy internal listener. +// [#not-implemented-hide:] message EnvoyInternalAddress { oneof address_name_specifier { option (validate.required) = true; - // The address is the name of a internal listener. + // The :ref:`listener name ` of the destination internal listener. string server_listener_name = 1; - - string client_address_id = 2; } } diff --git a/generated_api_shadow/envoy/config/core/v4alpha/address.proto b/generated_api_shadow/envoy/config/core/v4alpha/address.proto index 18761ebb6637..e9f5e4868a06 100644 --- a/generated_api_shadow/envoy/config/core/v4alpha/address.proto +++ b/generated_api_shadow/envoy/config/core/v4alpha/address.proto @@ -30,7 +30,8 @@ message Pipe { uint32 mode = 2 [(validate.rules).uint32 = {lte: 511}]; } -// [#not-implemented-hide:] The address representing an envoy internal listener, or a client connecting to that listener. +// The address represents an envoy internal listener. +// [#not-implemented-hide:] message EnvoyInternalAddress { option (udpa.annotations.versioning).previous_message_type = "envoy.config.core.v3.EnvoyInternalAddress"; @@ -38,10 +39,8 @@ message EnvoyInternalAddress { oneof address_name_specifier { option (validate.required) = true; - // The address is the name of a internal listener. + // The :ref:`listener name ` of the destination internal listener. string server_listener_name = 1; - - string client_address_id = 2; } } diff --git a/source/common/network/address_impl.h b/source/common/network/address_impl.h index ca1e1cc84eaa..a09129804b10 100644 --- a/source/common/network/address_impl.h +++ b/source/common/network/address_impl.h @@ -269,9 +269,9 @@ class EnvoyInternalInstance : public InstanceBase { private: struct EnvoyInternalAddressImpl : public EnvoyInternalAddress { explicit EnvoyInternalAddressImpl(const std::string& address_id) : address_id_(address_id) {} - ~EnvoyInternalAddressImpl() = default; + ~EnvoyInternalAddressImpl() override = default; const std::string& addressId() const override { return address_id_; } - std::string address_id_; + const std::string address_id_; }; EnvoyInternalAddressImpl internal_address_; }; diff --git a/source/common/network/resolver_impl.cc b/source/common/network/resolver_impl.cc index bdc4fc9588a2..1d25077f8f15 100644 --- a/source/common/network/resolver_impl.cc +++ b/source/common/network/resolver_impl.cc @@ -55,11 +55,8 @@ InstanceConstSharedPtr resolveProtoAddress(const envoy::config::core::v3::Addres kServerListenerName: return std::make_shared( address.envoy_internal_address().server_listener_name()); - case envoy::config::core::v3::EnvoyInternalAddress::AddressNameSpecifierCase::kClientAddressId: - return std::make_shared( - address.envoy_internal_address().client_address_id()); default: - throw EnvoyException("Internal address must be a server listener name or client address id" + + throw EnvoyException("Internal address must be a server listener name: " + address.DebugString()); } default: diff --git a/test/common/network/address_impl_test.cc b/test/common/network/address_impl_test.cc index fa9436142c14..e221ba5dfb80 100644 --- a/test/common/network/address_impl_test.cc +++ b/test/common/network/address_impl_test.cc @@ -319,6 +319,15 @@ TEST(PipeInstanceTest, Basic) { EXPECT_EQ(nullptr, address.ip()); } +TEST(InteralInstanceTest, Basic) { + EnvoyInternalInstance address("listener_foo"); + EXPECT_EQ("envoy://listener_foo", address.asString()); + EXPECT_EQ(Type::EnvoyInternal, address.type()); + EXPECT_EQ(nullptr, address.ip()); + EXPECT_EQ(nullptr, address.pipe()); + EXPECT_NE(nullptr, address.envoyInternalAddress()); +} + #ifndef WIN32 TEST(PipeInstanceTest, BasicPermission) { std::string path = TestEnvironment::unixDomainSocketPath("foo.sock"); @@ -509,7 +518,7 @@ TEST(AddressFromSockAddrDeathTest, Pipe) { // Test comparisons between all the different (known) test classes. struct TestCase { - enum InstanceType { Ipv4, Ipv6, Pipe }; + enum InstanceType { Ipv4, Ipv6, Pipe, Internal }; TestCase() = default; TestCase(enum InstanceType type, const std::string& address, uint32_t port) @@ -543,6 +552,9 @@ class MixedAddressTest : public testing::TestWithParam<::testing::tuple(test_case.address_); break; + case TestCase::Internal: + return std::make_shared(test_case.address_); + break; } return nullptr; } @@ -561,10 +573,11 @@ TEST_P(MixedAddressTest, Equality) { } struct TestCase test_cases[] = { - {TestCase::Ipv4, "1.2.3.4", 1}, {TestCase::Ipv4, "1.2.3.4", 2}, - {TestCase::Ipv4, "1.2.3.5", 1}, {TestCase::Ipv6, "01:023::00ef", 1}, - {TestCase::Ipv6, "01:023::00ef", 2}, {TestCase::Ipv6, "01:023::00ed", 1}, - {TestCase::Pipe, "/path/to/pipe/1", 0}, {TestCase::Pipe, "/path/to/pipe/2", 0}}; + {TestCase::Ipv4, "1.2.3.4", 1}, {TestCase::Ipv4, "1.2.3.4", 2}, + {TestCase::Ipv4, "1.2.3.5", 1}, {TestCase::Ipv6, "01:023::00ef", 1}, + {TestCase::Ipv6, "01:023::00ef", 2}, {TestCase::Ipv6, "01:023::00ed", 1}, + {TestCase::Pipe, "/path/to/pipe/1", 0}, {TestCase::Pipe, "/path/to/pipe/2", 0}, + {TestCase::Internal, "listener_foo", 0}, {TestCase::Internal, "listener_bar", 0}}; INSTANTIATE_TEST_SUITE_P(AddressCrossProduct, MixedAddressTest, ::testing::Combine(::testing::ValuesIn(test_cases), diff --git a/test/common/network/resolver_impl_test.cc b/test/common/network/resolver_impl_test.cc index 92ed2ee966e5..f9cf9a12fe6c 100644 --- a/test/common/network/resolver_impl_test.cc +++ b/test/common/network/resolver_impl_test.cc @@ -63,6 +63,14 @@ TEST(ResolverTest, FromProtoAddress) { EXPECT_EQ("/foo/bar", resolveProtoAddress(pipe_address)->asString()); } +TEST(ResolverTest, InternalListenerNameFromProtoAddress) { + envoy::config::core::v3::Address internal_listener_address; + internal_listener_address.mutable_envoy_internal_address()->set_server_listener_name( + "internal_listener_foo"); + EXPECT_EQ("envoy://internal_listener_foo", + resolveProtoAddress(internal_listener_address)->asString()); +} + // Validate correct handling of ipv4_compat field. TEST(ResolverTest, FromProtoAddressV4Compat) { { From 48e064076b1b096ddad1831f50f5d638c3c72cdf Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Fri, 28 Aug 2020 08:28:42 +0000 Subject: [PATCH 008/100] remove unimplement to fix docs Signed-off-by: Yuchen Dai --- api/envoy/config/core/v3/address.proto | 1 - api/envoy/config/core/v4alpha/address.proto | 1 - generated_api_shadow/envoy/config/core/v3/address.proto | 1 - generated_api_shadow/envoy/config/core/v4alpha/address.proto | 1 - 4 files changed, 4 deletions(-) diff --git a/api/envoy/config/core/v3/address.proto b/api/envoy/config/core/v3/address.proto index 4e8049104e16..7826c8c5b5fa 100644 --- a/api/envoy/config/core/v3/address.proto +++ b/api/envoy/config/core/v3/address.proto @@ -31,7 +31,6 @@ message Pipe { } // The address represents an envoy internal listener. -// [#not-implemented-hide:] message EnvoyInternalAddress { oneof address_name_specifier { option (validate.required) = true; diff --git a/api/envoy/config/core/v4alpha/address.proto b/api/envoy/config/core/v4alpha/address.proto index e9f5e4868a06..f6d31f1fcb88 100644 --- a/api/envoy/config/core/v4alpha/address.proto +++ b/api/envoy/config/core/v4alpha/address.proto @@ -31,7 +31,6 @@ message Pipe { } // The address represents an envoy internal listener. -// [#not-implemented-hide:] message EnvoyInternalAddress { option (udpa.annotations.versioning).previous_message_type = "envoy.config.core.v3.EnvoyInternalAddress"; diff --git a/generated_api_shadow/envoy/config/core/v3/address.proto b/generated_api_shadow/envoy/config/core/v3/address.proto index 4e8049104e16..7826c8c5b5fa 100644 --- a/generated_api_shadow/envoy/config/core/v3/address.proto +++ b/generated_api_shadow/envoy/config/core/v3/address.proto @@ -31,7 +31,6 @@ message Pipe { } // The address represents an envoy internal listener. -// [#not-implemented-hide:] message EnvoyInternalAddress { oneof address_name_specifier { option (validate.required) = true; diff --git a/generated_api_shadow/envoy/config/core/v4alpha/address.proto b/generated_api_shadow/envoy/config/core/v4alpha/address.proto index e9f5e4868a06..f6d31f1fcb88 100644 --- a/generated_api_shadow/envoy/config/core/v4alpha/address.proto +++ b/generated_api_shadow/envoy/config/core/v4alpha/address.proto @@ -31,7 +31,6 @@ message Pipe { } // The address represents an envoy internal listener. -// [#not-implemented-hide:] message EnvoyInternalAddress { option (udpa.annotations.versioning).previous_message_type = "envoy.config.core.v3.EnvoyInternalAddress"; From e81a41e9f41e9cf8ce5b196019045784e52303b6 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 3 Sep 2020 09:59:32 +0000 Subject: [PATCH 009/100] guard internal address Signed-off-by: Yuchen Dai --- include/envoy/network/socket_interface.h | 6 +- source/common/event/file_event_impl.h | 18 ++++ source/common/network/BUILD | 1 + source/common/network/io_socket_error_impl.cc | 10 ++ source/common/network/io_socket_error_impl.h | 5 + .../common/network/io_socket_handle_impl.cc | 91 +++++++++++++++++++ source/common/network/io_socket_handle_impl.h | 49 ++++++++++ .../common/network/socket_interface_impl.cc | 6 +- source/server/listener_manager_impl.cc | 9 ++ test/common/network/address_impl_test.cc | 5 + test/common/network/resolver_impl_test.cc | 8 ++ test/server/listener_manager_impl_test.cc | 13 +++ 12 files changed, 218 insertions(+), 3 deletions(-) diff --git a/include/envoy/network/socket_interface.h b/include/envoy/network/socket_interface.h index 702819ce3b4a..c558c32e3470 100644 --- a/include/envoy/network/socket_interface.h +++ b/include/envoy/network/socket_interface.h @@ -49,13 +49,17 @@ class SocketInterface { using SocketInterfacePtr = std::unique_ptr; /** - * Create IoHandle for given address + * Create IoHandle for given address. * @param type type of socket to be requested * @param addr address that is gleaned for address type, version and socket interface name * @return @ref Network::IoHandlePtr that wraps the underlying socket file descriptor */ static inline IoHandlePtr ioHandleForAddr(Socket::Type type, const Address::InstanceConstSharedPtr addr) { + // Cannot create IoHandle for internal address yet. + if (addr->envoyInternalAddress()) { + return nullptr; + } return addr->socketInterface().socket(type, addr); } diff --git a/source/common/event/file_event_impl.h b/source/common/event/file_event_impl.h index e4044fd25194..c2d72aa62469 100644 --- a/source/common/event/file_event_impl.h +++ b/source/common/event/file_event_impl.h @@ -42,5 +42,23 @@ class FileEventImpl : public FileEvent, ImplBase { const bool activate_fd_events_next_event_loop_; }; +class TimerWrappedFileEventImpl : public FileEvent { +public: + TimerWrappedFileEventImpl(SchedulableCallbackPtr schedulable) + : schedulable_(std::move(schedulable)) {} + + ~TimerWrappedFileEventImpl() { + if (schedulable_->enabled()) { + schedulable_->cancel(); + } + } + // Event::FileEvent + void activate(uint32_t) override {} + void setEnabled(uint32_t) override {} + +private: + SchedulableCallbackPtr schedulable_; +}; + } // namespace Event } // namespace Envoy diff --git a/source/common/network/BUILD b/source/common/network/BUILD index 11b6e565bd89..15fa16a06329 100644 --- a/source/common/network/BUILD +++ b/source/common/network/BUILD @@ -194,6 +194,7 @@ envoy_cc_library( "//include/envoy/event:dispatcher_interface", "//include/envoy/network:io_handle_interface", "//source/common/api:os_sys_calls_lib", + "//source/common/event:dispatcher_includes", "@envoy_api//envoy/extensions/network/socket_interface/v3:pkg_cc_proto", ], ) diff --git a/source/common/network/io_socket_error_impl.cc b/source/common/network/io_socket_error_impl.cc index c1d3c13d78a0..fcf1f1efcf42 100644 --- a/source/common/network/io_socket_error_impl.cc +++ b/source/common/network/io_socket_error_impl.cc @@ -46,5 +46,15 @@ void IoSocketError::deleteIoError(Api::IoError* err) { } } +inline IoSocketError* getIoSocketInvalidAddressInstance() { + static auto* instance = new IoSocketError(SOCKET_ERROR_NOT_SUP); + return instance; +} + +Api::IoCallUint64Result IoSocketError::ioResultSocketInvalidAddress() { + return Api::IoCallUint64Result( + 0, Api::IoErrorPtr(getIoSocketInvalidAddressInstance(), [](IoError*) {})); +} + } // namespace Network } // namespace Envoy diff --git a/source/common/network/io_socket_error_impl.h b/source/common/network/io_socket_error_impl.h index aa8f362dc8ca..50d08b55f26a 100644 --- a/source/common/network/io_socket_error_impl.h +++ b/source/common/network/io_socket_error_impl.h @@ -21,6 +21,11 @@ class IoSocketError : public Api::IoError { // deleter deleteIoError() below to avoid deallocating memory for this error. static IoSocketError* getIoSocketEagainInstance(); + // This error is introduced when Envoy create socket for unsupported address. It is either a bug, + // or this Envoy instance received config which is not yet supported. This should not be fatal + // error. + static Api::IoCallUint64Result ioResultSocketInvalidAddress(); + // Deallocate memory only if the error is not Again. static void deleteIoError(Api::IoError* err); diff --git a/source/common/network/io_socket_handle_impl.cc b/source/common/network/io_socket_handle_impl.cc index f18c73f1af89..30390856d6a4 100644 --- a/source/common/network/io_socket_handle_impl.cc +++ b/source/common/network/io_socket_handle_impl.cc @@ -4,6 +4,7 @@ #include "common/api/os_sys_calls_impl.h" #include "common/common/utility.h" +#include "common/event/file_event_impl.h" #include "common/network/address_impl.h" #include "absl/container/fixed_array.h" @@ -489,5 +490,95 @@ Api::SysCallIntResult IoSocketHandleImpl::shutdown(int how) { return Api::OsSysCallsSingleton::get().shutdown(fd_, how); } +NullIoSocketHandleImpl::~NullIoSocketHandleImpl() = default; + +Api::IoCallUint64Result NullIoSocketHandleImpl::close() { + return IoSocketError::ioResultSocketInvalidAddress(); +} + +bool NullIoSocketHandleImpl::isOpen() const { return false; } + +Api::IoCallUint64Result NullIoSocketHandleImpl::readv(uint64_t, Buffer::RawSlice*, uint64_t) { + return IoSocketError::ioResultSocketInvalidAddress(); +} + +Api::IoCallUint64Result NullIoSocketHandleImpl::writev(const Buffer::RawSlice*, uint64_t) { + return IoSocketError::ioResultSocketInvalidAddress(); +} + +Api::IoCallUint64Result NullIoSocketHandleImpl::sendmsg(const Buffer::RawSlice*, uint64_t, int, + const Address::Ip*, + const Address::Instance&) { + return IoSocketError::ioResultSocketInvalidAddress(); +} + +Api::IoCallUint64Result NullIoSocketHandleImpl::recvmsg(Buffer::RawSlice*, const uint64_t, uint32_t, + RecvMsgOutput&) { + return IoSocketError::ioResultSocketInvalidAddress(); +} + +Api::IoCallUint64Result NullIoSocketHandleImpl::recvmmsg(RawSliceArrays&, uint32_t, + RecvMsgOutput&) { + return IoSocketError::ioResultSocketInvalidAddress(); +} + +Api::IoCallUint64Result NullIoSocketHandleImpl::recv(void*, size_t, int) { + return IoSocketError::ioResultSocketInvalidAddress(); +} + +bool NullIoSocketHandleImpl::supportsMmsg() const { return false; } + +bool NullIoSocketHandleImpl::supportsUdpGro() const { return false; } + +Api::SysCallIntResult makeInvalidSyscall() { + return Api::SysCallIntResult{-1, SOCKET_ERROR_NOT_SUP /*SOCKET_ERROR_NOT_SUP*/}; +} + +Api::SysCallIntResult NullIoSocketHandleImpl::bind(Address::InstanceConstSharedPtr) { + return makeInvalidSyscall(); +} + +Api::SysCallIntResult NullIoSocketHandleImpl::listen(int) { return makeInvalidSyscall(); } + +IoHandlePtr NullIoSocketHandleImpl::accept(struct sockaddr*, socklen_t*) { + + return std::make_unique(); +} + +Api::SysCallIntResult NullIoSocketHandleImpl::connect(Address::InstanceConstSharedPtr) { + return makeInvalidSyscall(); +} + +Api::SysCallIntResult NullIoSocketHandleImpl::setOption(int, int, const void*, socklen_t) { + return makeInvalidSyscall(); +} + +Api::SysCallIntResult NullIoSocketHandleImpl::getOption(int, int, void*, socklen_t*) { + return makeInvalidSyscall(); +} + +Api::SysCallIntResult NullIoSocketHandleImpl::setBlocking(bool) { return makeInvalidSyscall(); } + +absl::optional NullIoSocketHandleImpl::domain() { return absl::nullopt; } + +Address::InstanceConstSharedPtr NullIoSocketHandleImpl::localAddress() { + throw EnvoyException(fmt::format("getsockname failed for NullIoSocketHandleImpl")); +} + +Address::InstanceConstSharedPtr NullIoSocketHandleImpl::peerAddress() { + + throw EnvoyException(fmt::format("getsockname failed for NullIoSocketHandleImpl")); +} + +Event::FileEventPtr NullIoSocketHandleImpl::createFileEvent(Event::Dispatcher& dispatcher, + Event::FileReadyCb cb, + Event::FileTriggerType, + uint32_t events) { + return std::make_unique( + dispatcher.createSchedulableCallback([cb, events]() -> void { cb(events); })); +} + +Api::SysCallIntResult NullIoSocketHandleImpl::shutdown(int) { return makeInvalidSyscall(); } + } // namespace Network } // namespace Envoy diff --git a/source/common/network/io_socket_handle_impl.h b/source/common/network/io_socket_handle_impl.h index e1cacec47d8b..62144f16bac9 100644 --- a/source/common/network/io_socket_handle_impl.h +++ b/source/common/network/io_socket_handle_impl.h @@ -93,5 +93,54 @@ class IoSocketHandleImpl : public IoHandle, protected Logger::Loggable { +public: + NullIoSocketHandleImpl() { + ENVOY_LOG(debug, + "creating socket to invalid address. Please update envoy to support this address."); + } + ~NullIoSocketHandleImpl() override; + + os_fd_t fdDoNotUse() const override { return INVALID_SOCKET; } + + Api::IoCallUint64Result close() override; + + bool isOpen() const override; + + Api::IoCallUint64Result readv(uint64_t max_length, Buffer::RawSlice* slices, + uint64_t num_slice) override; + + Api::IoCallUint64Result writev(const Buffer::RawSlice* slices, uint64_t num_slice) override; + + Api::IoCallUint64Result sendmsg(const Buffer::RawSlice* slices, uint64_t num_slice, int flags, + const Address::Ip* self_ip, + const Address::Instance& peer_address) override; + + Api::IoCallUint64Result recvmsg(Buffer::RawSlice* slices, const uint64_t num_slice, + uint32_t self_port, RecvMsgOutput& output) override; + + Api::IoCallUint64Result recvmmsg(RawSliceArrays& slices, uint32_t self_port, + RecvMsgOutput& output) override; + Api::IoCallUint64Result recv(void* buffer, size_t length, int flags) override; + + bool supportsMmsg() const override; + bool supportsUdpGro() const override; + + Api::SysCallIntResult bind(Address::InstanceConstSharedPtr address) override; + Api::SysCallIntResult listen(int backlog) override; + IoHandlePtr accept(struct sockaddr* addr, socklen_t* addrlen) override; + Api::SysCallIntResult connect(Address::InstanceConstSharedPtr address) override; + Api::SysCallIntResult setOption(int level, int optname, const void* optval, + socklen_t optlen) override; + Api::SysCallIntResult getOption(int level, int optname, void* optval, socklen_t* optlen) override; + Api::SysCallIntResult setBlocking(bool blocking) override; + absl::optional domain() override; + Address::InstanceConstSharedPtr localAddress() override; + Address::InstanceConstSharedPtr peerAddress() override; + Event::FileEventPtr createFileEvent(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, + Event::FileTriggerType trigger, uint32_t events) override; + Api::SysCallIntResult shutdown(int how) override; +}; + } // namespace Network } // namespace Envoy diff --git a/source/common/network/socket_interface_impl.cc b/source/common/network/socket_interface_impl.cc index 9afbe9d331e7..1d631061f1d8 100644 --- a/source/common/network/socket_interface_impl.cc +++ b/source/common/network/socket_interface_impl.cc @@ -36,9 +36,11 @@ IoHandlePtr SocketInterfaceImpl::socket(Socket::Type socket_type, Address::Type ASSERT(version == Address::IpVersion::v4); domain = AF_INET; } - } else { - ASSERT(addr_type == Address::Type::Pipe); + } else if (addr_type == Address::Type::Pipe) { domain = AF_UNIX; + } else { + ASSERT(addr_type == Address::Type::EnvoyInternal); + return std::make_unique(); } const Api::SysCallSocketResult result = Api::OsSysCallsSingleton::get().socket(domain, flags, 0); diff --git a/source/server/listener_manager_impl.cc b/source/server/listener_manager_impl.cc index ea735ffb41d5..d3354a2ea568 100644 --- a/source/server/listener_manager_impl.cc +++ b/source/server/listener_manager_impl.cc @@ -335,6 +335,15 @@ ListenerManagerStats ListenerManagerImpl::generateStats(Stats::Scope& scope) { bool ListenerManagerImpl::addOrUpdateListener(const envoy::config::listener::v3::Listener& config, const std::string& version_info, bool added_via_api) { + // TODO(lambdai): Implement internal listener. + if (config.address().has_envoy_internal_address()) { + ENVOY_LOG(debug, + "listener {} has envoy internal address {}. Internal address cannot be used by " + "listener yet", + config.name(), config.address().envoy_internal_address().DebugString()); + return false; + } + // TODO(junr03): currently only one ApiListener can be installed via bootstrap to avoid having to // build a collection of listeners, and to have to be able to warm and drain the listeners. In the // future allow multiple ApiListeners, and allow them to be created via LDS as well as bootstrap. diff --git a/test/common/network/address_impl_test.cc b/test/common/network/address_impl_test.cc index e221ba5dfb80..19ce7947b86b 100644 --- a/test/common/network/address_impl_test.cc +++ b/test/common/network/address_impl_test.cc @@ -154,6 +154,8 @@ TEST(Ipv4InstanceTest, SocketAddress) { EXPECT_TRUE(addressesEqual(Network::Utility::parseInternetAddress("1.2.3.4"), address)); EXPECT_EQ(nullptr, address.ip()->ipv6()); EXPECT_TRUE(address.ip()->isUnicastAddress()); + EXPECT_EQ(nullptr, address.pipe()); + EXPECT_EQ(nullptr, address.envoyInternalAddress()); } TEST(Ipv4InstanceTest, AddressOnly) { @@ -241,6 +243,8 @@ TEST(Ipv6InstanceTest, SocketAddress) { EXPECT_TRUE(addressesEqual(Network::Utility::parseInternetAddress("1:0023::0Ef"), address)); EXPECT_EQ(nullptr, address.ip()->ipv4()); EXPECT_TRUE(address.ip()->isUnicastAddress()); + EXPECT_EQ(nullptr, address.pipe()); + EXPECT_EQ(nullptr, address.envoyInternalAddress()); } TEST(Ipv6InstanceTest, AddressOnly) { @@ -317,6 +321,7 @@ TEST(PipeInstanceTest, Basic) { EXPECT_EQ("/foo", address.asString()); EXPECT_EQ(Type::Pipe, address.type()); EXPECT_EQ(nullptr, address.ip()); + EXPECT_EQ(nullptr, address.envoyInternalAddress()); } TEST(InteralInstanceTest, Basic) { diff --git a/test/common/network/resolver_impl_test.cc b/test/common/network/resolver_impl_test.cc index f9cf9a12fe6c..f432ec3464f6 100644 --- a/test/common/network/resolver_impl_test.cc +++ b/test/common/network/resolver_impl_test.cc @@ -71,6 +71,14 @@ TEST(ResolverTest, InternalListenerNameFromProtoAddress) { resolveProtoAddress(internal_listener_address)->asString()); } +TEST(ResolverTest, UnsupportedInternalAddressFromProtoAddress) { + envoy::config::core::v3::Address internal_address; + internal_address.mutable_envoy_internal_address(); + EXPECT_THROW_WITH_MESSAGE( + resolveProtoAddress(internal_address), EnvoyException, + "Internal address must be a server listener name: envoy_internal_address {\n}\n"); +} + // Validate correct handling of ipv4_compat field. TEST(ResolverTest, FromProtoAddressV4Compat) { { diff --git a/test/server/listener_manager_impl_test.cc b/test/server/listener_manager_impl_test.cc index 1f871adffcd2..c7d66354dcfb 100644 --- a/test/server/listener_manager_impl_test.cc +++ b/test/server/listener_manager_impl_test.cc @@ -536,6 +536,19 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, StatsScopeTest) { EXPECT_EQ(1UL, server_.stats_store_.counterFromString("listener.127.0.0.1_1234.foo").value()); } +TEST_F(ListenerManagerImplTest, UnsupportedInternalListener) { + const std::string yaml = R"EOF( +address: + envoy_internal_address: + server_listener_name: a_listener_name +filter_chains: +- filters: [] + )EOF"; + + EXPECT_FALSE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true)); + EXPECT_EQ(0U, manager_->listeners().size()); +} + TEST_F(ListenerManagerImplTest, NotDefaultListenerFiltersTimeout) { const std::string yaml = R"EOF( name: "foo" From a337bde79e1ff57e3af4669dbfcd17d39c305938 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 3 Sep 2020 21:14:03 +0000 Subject: [PATCH 010/100] add integration test for NullIoSocketHandleImpl Signed-off-by: Yuchen Dai --- include/envoy/network/socket_interface.h | 4 ---- source/common/event/file_event_impl.h | 4 ++-- .../common/network/io_socket_handle_impl.cc | 3 ++- source/common/network/io_socket_handle_impl.h | 16 ++++++++++--- .../socket_interface_integration_test.cc | 24 +++++++++++++++++++ 5 files changed, 41 insertions(+), 10 deletions(-) diff --git a/include/envoy/network/socket_interface.h b/include/envoy/network/socket_interface.h index c558c32e3470..a7c817611c67 100644 --- a/include/envoy/network/socket_interface.h +++ b/include/envoy/network/socket_interface.h @@ -56,10 +56,6 @@ using SocketInterfacePtr = std::unique_ptr; */ static inline IoHandlePtr ioHandleForAddr(Socket::Type type, const Address::InstanceConstSharedPtr addr) { - // Cannot create IoHandle for internal address yet. - if (addr->envoyInternalAddress()) { - return nullptr; - } return addr->socketInterface().socket(type, addr); } diff --git a/source/common/event/file_event_impl.h b/source/common/event/file_event_impl.h index c2d72aa62469..d4562538914e 100644 --- a/source/common/event/file_event_impl.h +++ b/source/common/event/file_event_impl.h @@ -53,8 +53,8 @@ class TimerWrappedFileEventImpl : public FileEvent { } } // Event::FileEvent - void activate(uint32_t) override {} - void setEnabled(uint32_t) override {} + void activate(uint32_t) override { schedulable_->scheduleCallbackNextIteration(); } + void setEnabled(uint32_t) override { schedulable_->scheduleCallbackNextIteration(); } private: SchedulableCallbackPtr schedulable_; diff --git a/source/common/network/io_socket_handle_impl.cc b/source/common/network/io_socket_handle_impl.cc index 30390856d6a4..4e0e4273dde7 100644 --- a/source/common/network/io_socket_handle_impl.cc +++ b/source/common/network/io_socket_handle_impl.cc @@ -493,10 +493,11 @@ Api::SysCallIntResult IoSocketHandleImpl::shutdown(int how) { NullIoSocketHandleImpl::~NullIoSocketHandleImpl() = default; Api::IoCallUint64Result NullIoSocketHandleImpl::close() { + closed_ = true; return IoSocketError::ioResultSocketInvalidAddress(); } -bool NullIoSocketHandleImpl::isOpen() const { return false; } +bool NullIoSocketHandleImpl::isOpen() const { return !closed_; } Api::IoCallUint64Result NullIoSocketHandleImpl::readv(uint64_t, Buffer::RawSlice*, uint64_t) { return IoSocketError::ioResultSocketInvalidAddress(); diff --git a/source/common/network/io_socket_handle_impl.h b/source/common/network/io_socket_handle_impl.h index 62144f16bac9..25d704b5b323 100644 --- a/source/common/network/io_socket_handle_impl.h +++ b/source/common/network/io_socket_handle_impl.h @@ -13,7 +13,7 @@ namespace Envoy { namespace Network { /** - * IoHandle derivative for sockets + * IoHandle derivative for sockets. */ class IoSocketHandleImpl : public IoHandle, protected Logger::Loggable { public: @@ -93,13 +93,18 @@ class IoSocketHandleImpl : public IoHandle, protected Logger::Loggable { public: - NullIoSocketHandleImpl() { + NullIoSocketHandleImpl() : closed_{false} { ENVOY_LOG(debug, "creating socket to invalid address. Please update envoy to support this address."); } - ~NullIoSocketHandleImpl() override; + + ~NullIoSocketHandleImpl() override { ASSERT(closed_); } os_fd_t fdDoNotUse() const override { return INVALID_SOCKET; } @@ -140,6 +145,11 @@ class NullIoSocketHandleImpl : public IoHandle, protected Logger::Loggableclose(Network::ConnectionCloseType::FlushWrite); } +// Test that connecting to internal address should always followed by disconnection with no crash. +TEST_P(SocketInterfaceIntegrationTest, InternalAddressWithSocketInterface) { + BaseIntegrationTest::initialize(); + + ConnectionStatusCallbacks connect_callbacks_; + Network::ClientConnectionPtr client_; + const Network::SocketInterface* sock_interface = Network::socketInterface( + "envoy.extensions.network.socket_interface.default_socket_interface"); + Network::Address::InstanceConstSharedPtr address = + std::make_shared("listener_0", sock_interface); + + client_ = dispatcher_->createClientConnection(address, Network::Address::InstanceConstSharedPtr(), + Network::Test::createRawBufferSocket(), nullptr); + + client_->addConnectionCallbacks(connect_callbacks_); + client_->connect(); + + while (!connect_callbacks_.closed()) { + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } + + client_->close(Network::ConnectionCloseType::FlushWrite); +} + } // namespace } // namespace Envoy \ No newline at end of file From dc874553cfc022c3813d587b68f0ba6addab01f8 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 3 Sep 2020 21:14:03 +0000 Subject: [PATCH 011/100] add integration test for NullIoSocketHandleImpl Signed-off-by: Yuchen Dai --- include/envoy/network/socket_interface.h | 4 -- source/common/event/file_event_impl.h | 4 +- .../common/network/io_socket_handle_impl.cc | 5 +- source/common/network/io_socket_handle_impl.h | 16 ++++-- .../socket_interface_integration_test.cc | 50 +++++++++++++++++++ 5 files changed, 67 insertions(+), 12 deletions(-) diff --git a/include/envoy/network/socket_interface.h b/include/envoy/network/socket_interface.h index c558c32e3470..a7c817611c67 100644 --- a/include/envoy/network/socket_interface.h +++ b/include/envoy/network/socket_interface.h @@ -56,10 +56,6 @@ using SocketInterfacePtr = std::unique_ptr; */ static inline IoHandlePtr ioHandleForAddr(Socket::Type type, const Address::InstanceConstSharedPtr addr) { - // Cannot create IoHandle for internal address yet. - if (addr->envoyInternalAddress()) { - return nullptr; - } return addr->socketInterface().socket(type, addr); } diff --git a/source/common/event/file_event_impl.h b/source/common/event/file_event_impl.h index c2d72aa62469..d4562538914e 100644 --- a/source/common/event/file_event_impl.h +++ b/source/common/event/file_event_impl.h @@ -53,8 +53,8 @@ class TimerWrappedFileEventImpl : public FileEvent { } } // Event::FileEvent - void activate(uint32_t) override {} - void setEnabled(uint32_t) override {} + void activate(uint32_t) override { schedulable_->scheduleCallbackNextIteration(); } + void setEnabled(uint32_t) override { schedulable_->scheduleCallbackNextIteration(); } private: SchedulableCallbackPtr schedulable_; diff --git a/source/common/network/io_socket_handle_impl.cc b/source/common/network/io_socket_handle_impl.cc index 30390856d6a4..3e84da7c639e 100644 --- a/source/common/network/io_socket_handle_impl.cc +++ b/source/common/network/io_socket_handle_impl.cc @@ -490,13 +490,12 @@ Api::SysCallIntResult IoSocketHandleImpl::shutdown(int how) { return Api::OsSysCallsSingleton::get().shutdown(fd_, how); } -NullIoSocketHandleImpl::~NullIoSocketHandleImpl() = default; - Api::IoCallUint64Result NullIoSocketHandleImpl::close() { + closed_ = true; return IoSocketError::ioResultSocketInvalidAddress(); } -bool NullIoSocketHandleImpl::isOpen() const { return false; } +bool NullIoSocketHandleImpl::isOpen() const { return !closed_; } Api::IoCallUint64Result NullIoSocketHandleImpl::readv(uint64_t, Buffer::RawSlice*, uint64_t) { return IoSocketError::ioResultSocketInvalidAddress(); diff --git a/source/common/network/io_socket_handle_impl.h b/source/common/network/io_socket_handle_impl.h index 62144f16bac9..25d704b5b323 100644 --- a/source/common/network/io_socket_handle_impl.h +++ b/source/common/network/io_socket_handle_impl.h @@ -13,7 +13,7 @@ namespace Envoy { namespace Network { /** - * IoHandle derivative for sockets + * IoHandle derivative for sockets. */ class IoSocketHandleImpl : public IoHandle, protected Logger::Loggable { public: @@ -93,13 +93,18 @@ class IoSocketHandleImpl : public IoHandle, protected Logger::Loggable { public: - NullIoSocketHandleImpl() { + NullIoSocketHandleImpl() : closed_{false} { ENVOY_LOG(debug, "creating socket to invalid address. Please update envoy to support this address."); } - ~NullIoSocketHandleImpl() override; + + ~NullIoSocketHandleImpl() override { ASSERT(closed_); } os_fd_t fdDoNotUse() const override { return INVALID_SOCKET; } @@ -140,6 +145,11 @@ class NullIoSocketHandleImpl : public IoHandle, protected Logger::Loggableclose(Network::ConnectionCloseType::FlushWrite); } +// Test that connecting to internal address should always followed by disconnection with no crash. +TEST_P(SocketInterfaceIntegrationTest, InternalAddressWithSocketInterface) { + BaseIntegrationTest::initialize(); + + ConnectionStatusCallbacks connect_callbacks_; + Network::ClientConnectionPtr client_; + const Network::SocketInterface* sock_interface = Network::socketInterface( + "envoy.extensions.network.socket_interface.default_socket_interface"); + Network::Address::InstanceConstSharedPtr address = + std::make_shared("listener_0", sock_interface); + + client_ = dispatcher_->createClientConnection(address, Network::Address::InstanceConstSharedPtr(), + Network::Test::createRawBufferSocket(), nullptr); + + client_->addConnectionCallbacks(connect_callbacks_); + client_->connect(); + + while (!connect_callbacks_.closed()) { + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } + + client_->close(Network::ConnectionCloseType::FlushWrite); +} + +// Test that connecting to internal address should always followed by disconnection with no crash. +TEST_P(SocketInterfaceIntegrationTest, UdpOpOntInternalAddressWithSocketInterface) { + BaseIntegrationTest::initialize(); + + const Network::SocketInterface* sock_interface = Network::socketInterface( + "envoy.extensions.network.socket_interface.default_socket_interface"); + Network::Address::InstanceConstSharedPtr address = + std::make_shared("listener_0", sock_interface); + + auto socket = std::make_unique(Network::Socket::Type::Datagram, address); + + Network::IoHandle::RecvMsgOutput output{1, nullptr}; + Buffer::OwnedImpl buffer; + + Buffer::RawSlice iovec; + buffer.reserve(100, &iovec, 1); + + Api::IoCallUint64Result result = socket->ioHandle().recvmsg(&iovec, 1, 12345, output); + EXPECT_FALSE(result.ok()); + EXPECT_EQ(Api::IoError::IoErrorCode::NoSupport, result.err_->getErrorCode()); + EXPECT_TRUE(socket->isOpen()); + socket->close(); + EXPECT_FALSE(socket->isOpen()); +} + } // namespace } // namespace Envoy \ No newline at end of file From 51914a9d8fe7bf1b3e054c30e8d5bca69c1c9ed8 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Fri, 4 Sep 2020 00:22:30 +0000 Subject: [PATCH 012/100] fix spelling Signed-off-by: Yuchen Dai --- source/common/network/io_socket_handle_impl.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/common/network/io_socket_handle_impl.h b/source/common/network/io_socket_handle_impl.h index 25d704b5b323..cf7fd5da9d15 100644 --- a/source/common/network/io_socket_handle_impl.h +++ b/source/common/network/io_socket_handle_impl.h @@ -94,8 +94,8 @@ class IoSocketHandleImpl : public IoHandle, protected Logger::Loggable { public: From f8816b09be0b29bb91776bae1145fd41f1faae8e Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Wed, 9 Sep 2020 10:50:16 +0000 Subject: [PATCH 013/100] incomplete impl of internal listener Signed-off-by: Yuchen Dai --- include/envoy/event/dispatcher.h | 10 ++++++ source/common/event/dispatcher_impl.cc | 31 +++++++++++++++++++ source/common/event/dispatcher_impl.h | 10 +++++- .../common/network/internal_listener_impl.cc | 2 +- source/server/config_validation/dispatcher.cc | 6 ++++ source/server/config_validation/dispatcher.h | 3 ++ test/mocks/event/mocks.h | 7 +++++ 7 files changed, 67 insertions(+), 2 deletions(-) diff --git a/include/envoy/event/dispatcher.h b/include/envoy/event/dispatcher.h index 9fcf55707c99..1cc8e51802bc 100644 --- a/include/envoy/event/dispatcher.h +++ b/include/envoy/event/dispatcher.h @@ -113,6 +113,16 @@ class Dispatcher { Network::TransportSocketPtr&& transport_socket, const Network::ConnectionSocket::OptionsSharedPtr& options) PURE; + /** + * Creates an client internal connection. Does NOT initiate the connection; + * the caller must then call connect() on the returned Network::ClientConnection. + * @param internal_address supplies the internal address to connect to. + * @param local_address supplies an address to bind to or nullptr if no bind is necessary. + * @return Network::ClientConnectionPtr a client connection that is owned by the caller. + */ + virtual Network::ClientConnectionPtr + createInternalConnection(Network::Address::InstanceConstSharedPtr internal_address, + Network::Address::InstanceConstSharedPtr local_address) PURE; /** * Creates an async DNS resolver. The resolver should only be used on the thread that runs this * dispatcher. diff --git a/source/common/event/dispatcher_impl.cc b/source/common/event/dispatcher_impl.cc index 0c19bddf2db6..320998be6438 100644 --- a/source/common/event/dispatcher_impl.cc +++ b/source/common/event/dispatcher_impl.cc @@ -117,6 +117,37 @@ DispatcherImpl::createClientConnection(Network::Address::InstanceConstSharedPtr std::move(transport_socket), options); } +Network::ClientConnectionPtr +DispatcherImpl::createInternalConnection(Network::Address::InstanceConstSharedPtr internal_address, + Network::Address::InstanceConstSharedPtr) { + ASSERT(isThreadSafe()); + if (internal_address == nullptr) { + return nullptr; + } + // Find the internal listener callback. The listener will setup the server connection. + auto iter = internal_listeners_.find(internal_address->asString()); + for (const auto& [name, _] : internal_listeners_) { + ENVOY_LOG_MISC(debug, "lambdai: p listener {}", name); + } + if (iter == internal_listeners_.end()) { + ENVOY_LOG_MISC(debug, "lambdai: no valid listener registered for envoy internal address {}", + internal_address->asString()); + return nullptr; + } + Network::ConnectionPtr server_conn{}; + Network::ClientConnectionPtr client_conn{}; + + (iter->second)(internal_address, std::move(server_conn)); + return client_conn; +} + +void DispatcherImpl::registerInternalListener( + const std::string& internal_listener_id, + DispatcherImpl::InternalConnectionCallback internal_conn_callback) { + ENVOY_LOG_MISC(debug, "lambdai: register pipe factory on address {}", internal_listener_id); + internal_listeners_[internal_listener_id] = internal_conn_callback; +} + Network::DnsResolverSharedPtr DispatcherImpl::createDnsResolver( const std::vector& resolvers, const bool use_tcp_for_dns_lookups) { diff --git a/source/common/event/dispatcher_impl.h b/source/common/event/dispatcher_impl.h index c81498c89f79..d37365f2acc9 100644 --- a/source/common/event/dispatcher_impl.h +++ b/source/common/event/dispatcher_impl.h @@ -34,7 +34,8 @@ class DispatcherImpl : Logger::Loggable, DispatcherImpl(const std::string& name, Buffer::WatermarkFactoryPtr&& factory, Api::Api& api, Event::TimeSystem& time_system); ~DispatcherImpl() override; - + using InternalConnectionCallback = std::function; /** * @return event_base& the libevent base. */ @@ -53,6 +54,12 @@ class DispatcherImpl : Logger::Loggable, Network::Address::InstanceConstSharedPtr source_address, Network::TransportSocketPtr&& transport_socket, const Network::ConnectionSocket::OptionsSharedPtr& options) override; + void registerInternalListener(const std::string& internal_listener_id, + InternalConnectionCallback internal_conn_callback); + + Network::ClientConnectionPtr + createInternalConnection(Network::Address::InstanceConstSharedPtr internal_address, + Network::Address::InstanceConstSharedPtr local_address) override; Network::DnsResolverSharedPtr createDnsResolver(const std::vector& resolvers, const bool use_tcp_for_dns_lookups) override; @@ -121,6 +128,7 @@ class DispatcherImpl : Logger::Loggable, const ScopeTrackedObject* current_object_{}; bool deferred_deleting_{}; MonotonicTime approximate_monotonic_time_; + absl::flat_hash_map internal_listeners_; }; } // namespace Event diff --git a/source/common/network/internal_listener_impl.cc b/source/common/network/internal_listener_impl.cc index 81a762de9f37..c4ae98809c7d 100644 --- a/source/common/network/internal_listener_impl.cc +++ b/source/common/network/internal_listener_impl.cc @@ -18,7 +18,7 @@ namespace Network { void InternalListenerImpl::setupInternalListener(Event::DispatcherImpl& dispatcher, const std::string& listener_id) { - dispatcher.registerPipeFactory( + dispatcher.registerInternalListener( absl::StrCat("envoy://", pipe_listener_id), [this](const Address::InstanceConstSharedPtr& address, Network::ConnectionPtr server_conn) { Network::ConnectionSocketPtr socket = std::make_unique( diff --git a/source/server/config_validation/dispatcher.cc b/source/server/config_validation/dispatcher.cc index 3316f58065c2..c45e28f5bf38 100644 --- a/source/server/config_validation/dispatcher.cc +++ b/source/server/config_validation/dispatcher.cc @@ -16,6 +16,12 @@ Network::ClientConnectionPtr ValidationDispatcher::createClientConnection( std::move(transport_socket), options); } +Network::ClientConnectionPtr +ValidationDispatcher::createInternalConnection(Network::Address::InstanceConstSharedPtr, + Network::Address::InstanceConstSharedPtr) { + NOT_IMPLEMENTED_GCOVR_EXCL_LINE; +} + Network::DnsResolverSharedPtr ValidationDispatcher::createDnsResolver( const std::vector&, const bool) { return dns_resolver_; diff --git a/source/server/config_validation/dispatcher.h b/source/server/config_validation/dispatcher.h index b5deea61f58d..64015eabe4d3 100644 --- a/source/server/config_validation/dispatcher.h +++ b/source/server/config_validation/dispatcher.h @@ -23,6 +23,9 @@ class ValidationDispatcher : public DispatcherImpl { createClientConnection(Network::Address::InstanceConstSharedPtr, Network::Address::InstanceConstSharedPtr, Network::TransportSocketPtr&&, const Network::ConnectionSocket::OptionsSharedPtr& options) override; + Network::ClientConnectionPtr + createInternalConnection(Network::Address::InstanceConstSharedPtr internal_address, + Network::Address::InstanceConstSharedPtr local_address) override; Network::DnsResolverSharedPtr createDnsResolver(const std::vector& resolvers, const bool use_tcp_for_dns_lookups) override; diff --git a/test/mocks/event/mocks.h b/test/mocks/event/mocks.h index 605005fe471a..940cf5711ecb 100644 --- a/test/mocks/event/mocks.h +++ b/test/mocks/event/mocks.h @@ -17,6 +17,7 @@ #include "envoy/network/transport_socket.h" #include "envoy/ssl/context.h" +#include "common/common/assert.h" #include "common/common/scope_tracker.h" #include "test/mocks/buffer/mocks.h" @@ -54,6 +55,12 @@ class MockDispatcher : public Dispatcher { createClientConnection_(address, source_address, transport_socket, options)}; } + Network::ClientConnectionPtr + createInternalConnection(Network::Address::InstanceConstSharedPtr internal_address, + Network::Address::InstanceConstSharedPtr local_address) override { + NOT_IMPLEMENTED_GCOVR_EXCL_LINE; + } + FileEventPtr createFileEvent(os_fd_t fd, FileReadyCb cb, FileTriggerType trigger, uint32_t events) override { return FileEventPtr{createFileEvent_(fd, cb, trigger, events)}; From bc57e788d779c8e7b5e9dec9a4c5692268fe7bd8 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Wed, 9 Sep 2020 21:18:13 +0000 Subject: [PATCH 014/100] adding active internal listener Signed-off-by: Yuchen Dai --- include/envoy/network/listener.h | 4 ++++ source/common/event/dispatcher_impl.cc | 9 +++++++-- source/common/event/dispatcher_impl.h | 1 + source/common/network/internal_listener_impl.cc | 16 ++++++++-------- source/common/network/internal_listener_impl.h | 9 ++++++--- source/server/BUILD | 1 + source/server/connection_handler_impl.cc | 10 +++++++++- source/server/connection_handler_impl.h | 13 ++++++++----- source/server/listener_impl.cc | 8 +++++--- source/server/listener_manager_impl.cc | 17 +++++++++-------- test/server/connection_handler_test.cc | 16 ++++++++++++++++ 11 files changed, 74 insertions(+), 30 deletions(-) diff --git a/include/envoy/network/listener.h b/include/envoy/network/listener.h index 13173a3bc845..9ff169df9bb0 100644 --- a/include/envoy/network/listener.h +++ b/include/envoy/network/listener.h @@ -141,6 +141,10 @@ class ListenerConfig { */ virtual UdpPacketWriterFactoryOptRef udpPacketWriterFactory() PURE; + virtual bool isInternalListener() { + return false; + } + /** * @return traffic direction of the listener. */ diff --git a/source/common/event/dispatcher_impl.cc b/source/common/event/dispatcher_impl.cc index 320998be6438..e9cdbef6f1ba 100644 --- a/source/common/event/dispatcher_impl.cc +++ b/source/common/event/dispatcher_impl.cc @@ -144,8 +144,13 @@ DispatcherImpl::createInternalConnection(Network::Address::InstanceConstSharedPt void DispatcherImpl::registerInternalListener( const std::string& internal_listener_id, DispatcherImpl::InternalConnectionCallback internal_conn_callback) { - ENVOY_LOG_MISC(debug, "lambdai: register pipe factory on address {}", internal_listener_id); - internal_listeners_[internal_listener_id] = internal_conn_callback; + if (internal_conn_callback == nullptr) { + ENVOY_LOG_MISC(debug, "lambdai: unregister pipe factory on address {}", internal_listener_id); + internal_listeners_.erase(internal_listener_id); + } else { + ENVOY_LOG_MISC(debug, "lambdai: register pipe factory on address {}", internal_listener_id); + internal_listeners_[internal_listener_id] = internal_conn_callback; + } } Network::DnsResolverSharedPtr DispatcherImpl::createDnsResolver( diff --git a/source/common/event/dispatcher_impl.h b/source/common/event/dispatcher_impl.h index d37365f2acc9..fed10b749504 100644 --- a/source/common/event/dispatcher_impl.h +++ b/source/common/event/dispatcher_impl.h @@ -54,6 +54,7 @@ class DispatcherImpl : Logger::Loggable, Network::Address::InstanceConstSharedPtr source_address, Network::TransportSocketPtr&& transport_socket, const Network::ConnectionSocket::OptionsSharedPtr& options) override; + // Register the internal listener to setup the internal connection. Pass nullptr callback to unregister. void registerInternalListener(const std::string& internal_listener_id, InternalConnectionCallback internal_conn_callback); diff --git a/source/common/network/internal_listener_impl.cc b/source/common/network/internal_listener_impl.cc index c4ae98809c7d..e864429359f1 100644 --- a/source/common/network/internal_listener_impl.cc +++ b/source/common/network/internal_listener_impl.cc @@ -19,7 +19,7 @@ namespace Network { void InternalListenerImpl::setupInternalListener(Event::DispatcherImpl& dispatcher, const std::string& listener_id) { dispatcher.registerInternalListener( - absl::StrCat("envoy://", pipe_listener_id), + listener_id, [this](const Address::InstanceConstSharedPtr& address, Network::ConnectionPtr server_conn) { Network::ConnectionSocketPtr socket = std::make_unique( nullptr, @@ -33,13 +33,13 @@ void InternalListenerImpl::setupInternalListener(Event::DispatcherImpl& dispatch InternalListenerImpl::InternalListenerImpl(Event::DispatcherImpl& dispatcher, const std::string& listener_id, - InternalListenerCallbacks& cb); - : BaseListenerImpl(dispatcher, nullptr), cb_(cb) { -} + InternalListenerCallbacks& cb) + : BaseListenerImpl(dispatcher, nullptr), internal_listener_id_(listener_id), + dispatcher_(dispatcher), cb_(cb) {} - void InternalListenerImpl::enable() { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } +void InternalListenerImpl::enable() { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } - void InternalListenerImpl::disable() { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } +void InternalListenerImpl::disable() { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } - } // namespace Network - } // namespace Envoy \ No newline at end of file +} // namespace Network +} // namespace Envoy \ No newline at end of file diff --git a/source/common/network/internal_listener_impl.h b/source/common/network/internal_listener_impl.h index b0f6517bee6e..be4c93220782 100644 --- a/source/common/network/internal_listener_impl.h +++ b/source/common/network/internal_listener_impl.h @@ -20,10 +20,13 @@ class InternalListenerImpl : public BaseListenerImpl { protected: void setupInternalListener(Event::DispatcherImpl& dispatcher, - const std::string& pipe_listener_id); + const std::string& internal_listener_id); -private: - InteranalListenerCallbacks& cb_; +// TODO(lambdai): make it private +public: + std::string internal_listener_id_; + Event::DispatcherImpl& dispatcher_; + InternalListenerCallbacks& cb_; }; } // namespace Network diff --git a/source/server/BUILD b/source/server/BUILD index dc82ca7ef502..e98944e1a404 100644 --- a/source/server/BUILD +++ b/source/server/BUILD @@ -81,6 +81,7 @@ envoy_cc_library( "//source/common/event:deferred_task", "//source/common/network:connection_lib", "//source/common/stats:timespan_lib", + "//source/common/network:listener_lib", "//source/common/stream_info:stream_info_lib", "//source/extensions/transport_sockets:well_known_names", ], diff --git a/source/server/connection_handler_impl.cc b/source/server/connection_handler_impl.cc index ae56e39cecb8..33498b52f5d1 100644 --- a/source/server/connection_handler_impl.cc +++ b/source/server/connection_handler_impl.cc @@ -41,7 +41,9 @@ void ConnectionHandlerImpl::decNumConnections() { void ConnectionHandlerImpl::addListener(absl::optional overridden_listener, Network::ListenerConfig& config) { ActiveListenerDetails details; - if (config.listenSocketFactory().socketType() == Network::Socket::Type::Stream) { + if (config.isInternalListener()) { + + } else if (config.listenSocketFactory().socketType() == Network::Socket::Type::Stream) { if (overridden_listener.has_value()) { for (auto& listener : listeners_) { if (listener.second.listener_->listenerTag() == overridden_listener) { @@ -646,6 +648,12 @@ ConnectionHandlerImpl::ActiveInternalListener::~ActiveInternalListener() { ASSERT(num_listener_connections_ == 0); } +void ConnectionHandlerImpl::ActiveInternalListener::shutdownListener() { + internal_listener_->dispatcher_.registerInternalListener( + internal_listener_->internal_listener_id_, + /* connection_callback= */nullptr + ); +} // Copied from newConnection(). Invoked by SetupPipeListener. void ConnectionHandlerImpl::ActiveInternalListener::setupNewConnection( Network::ConnectionPtr server_conn, Network::ConnectionSocketPtr socket) { diff --git a/source/server/connection_handler_impl.h b/source/server/connection_handler_impl.h index 86c1babd5b80..56a227256c49 100644 --- a/source/server/connection_handler_impl.h +++ b/source/server/connection_handler_impl.h @@ -12,6 +12,7 @@ #include "envoy/network/filter.h" #include "envoy/network/listen_socket.h" #include "envoy/network/listener.h" + #include "envoy/server/active_udp_listener_config.h" #include "envoy/server/listener_manager.h" #include "envoy/stats/scope.h" @@ -20,6 +21,7 @@ #include "common/common/linked_object.h" #include "common/common/non_copyable.h" #include "common/stream_info/stream_info_impl.h" +#include "common/network/internal_listener_impl.h" #include "spdlog/spdlog.h" @@ -210,10 +212,10 @@ class ConnectionHandlerImpl : public Network::ConnectionHandler, Network::ConnectionSocketPtr socket) override; // ActiveListenerImplBase - Network::Listener* listener() override { return listener_.get(); } - void pauseListening() override { listener_->disable(); } - void resumeListening() override { listener_->enable(); } - void shutdownListener() override { listener_.reset(); } + Network::Listener* listener() override { return internal_listener_.get(); } + void pauseListening() override { internal_listener_->disable(); } + void resumeListening() override { internal_listener_->enable(); } + void shutdownListener() override; /** * Remove and destroy an active connection. @@ -246,7 +248,8 @@ class ConnectionHandlerImpl : public Network::ConnectionHandler, void updateListenerConfig(Network::ListenerConfig& config); ConnectionHandlerImpl& parent_; - Network::ListenerPtr listener_; + std::unique_ptr internal_listener_; + std::list sockets_; absl::node_hash_map connections_by_context_; diff --git a/source/server/listener_impl.cc b/source/server/listener_impl.cc index 32e3a3efa0c4..d0091f9c9484 100644 --- a/source/server/listener_impl.cc +++ b/source/server/listener_impl.cc @@ -64,7 +64,7 @@ ListenSocketFactoryImpl::ListenSocketFactoryImpl(ListenerComponentFactory& facto const std::string& listener_name, bool reuse_port) : factory_(factory), local_address_(address), socket_type_(socket_type), options_(options), bind_to_port_(bind_to_port), listener_name_(listener_name), reuse_port_(reuse_port) { - + // TODO(lambdai): Dispatch by address type. bool create_socket = false; if (local_address_->type() == Network::Address::Type::Ip) { if (socket_type_ == Network::Socket::Type::Datagram) { @@ -79,10 +79,12 @@ ListenSocketFactoryImpl::ListenSocketFactoryImpl(ListenerComponentFactory& facto // then all worker threads should use same port. create_socket = true; } - } else { - ASSERT(local_address_->type() == Network::Address::Type::Pipe); + } else if (local_address_->type() == Network::Address::Type::Pipe) { // Listeners with Unix domain socket always use shared socket. create_socket = true; + } else { + ASSERT(local_address_->type() == Network::Address::Type::EnvoyInternal); + create_socket = false; } if (create_socket) { diff --git a/source/server/listener_manager_impl.cc b/source/server/listener_manager_impl.cc index d3354a2ea568..f764263ddd6c 100644 --- a/source/server/listener_manager_impl.cc +++ b/source/server/listener_manager_impl.cc @@ -334,14 +334,15 @@ ListenerManagerStats ListenerManagerImpl::generateStats(Stats::Scope& scope) { bool ListenerManagerImpl::addOrUpdateListener(const envoy::config::listener::v3::Listener& config, const std::string& version_info, bool added_via_api) { - - // TODO(lambdai): Implement internal listener. - if (config.address().has_envoy_internal_address()) { - ENVOY_LOG(debug, - "listener {} has envoy internal address {}. Internal address cannot be used by " - "listener yet", - config.name(), config.address().envoy_internal_address().DebugString()); - return false; + // Internal address type be used with internal listener field. + if (config.address().has_envoy_internal_address() || config.has_internal_listener()) { + if (!config.has_internal_listener() || !config.has_internal_listener()) { + ENVOY_LOG(debug, + "listener {} has envoy internal address {}. Internal address cannot be used by " + "listener yet", + config.name(), config.address().envoy_internal_address().DebugString()); + return false; + } } // TODO(junr03): currently only one ApiListener can be installed via bootstrap to avoid having to diff --git a/test/server/connection_handler_test.cc b/test/server/connection_handler_test.cc index b200d56d1be0..587bac56767b 100644 --- a/test/server/connection_handler_test.cc +++ b/test/server/connection_handler_test.cc @@ -1132,6 +1132,22 @@ TEST_F(ConnectionHandlerTest, TcpBacklogCustom) { handler_->addListener(absl::nullopt, *test_listener); } + +TEST_F(ConnectionHandlerTest, AddInternalListener) { +} + +TEST_F(ConnectionHandlerTest, StopInternalListener) { +} + +TEST_F(ConnectionHandlerTest, InternalListenerAddConnection) { +} + +TEST_F(ConnectionHandlerTest, RemoveInternalListener) { +} + + + + } // namespace } // namespace Server } // namespace Envoy From 4c2d69350ef821f097b7b868845268ccd5b48145 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Fri, 11 Sep 2020 23:03:08 +0000 Subject: [PATCH 015/100] add listener manager test Signed-off-by: Yuchen Dai --- include/envoy/network/listener.h | 4 +- source/common/event/dispatcher_impl.h | 3 +- .../common/network/internal_listener_impl.h | 2 +- source/common/network/utility.cc | 7 +- source/common/network/utility.h | 2 +- source/server/BUILD | 2 +- source/server/connection_handler_impl.cc | 5 +- source/server/connection_handler_impl.h | 3 +- source/server/listener_impl.cc | 2 +- source/server/listener_impl.h | 6 +- test/mocks/event/mocks.h | 4 +- test/server/connection_handler_test.cc | 16 ++--- test/server/listener_manager_impl_test.cc | 66 +++++++++++++++++++ 13 files changed, 92 insertions(+), 30 deletions(-) diff --git a/include/envoy/network/listener.h b/include/envoy/network/listener.h index 9ff169df9bb0..0bb76986d548 100644 --- a/include/envoy/network/listener.h +++ b/include/envoy/network/listener.h @@ -141,9 +141,7 @@ class ListenerConfig { */ virtual UdpPacketWriterFactoryOptRef udpPacketWriterFactory() PURE; - virtual bool isInternalListener() { - return false; - } + virtual bool isInternalListener() { return false; } /** * @return traffic direction of the listener. diff --git a/source/common/event/dispatcher_impl.h b/source/common/event/dispatcher_impl.h index fed10b749504..69e2a9607f46 100644 --- a/source/common/event/dispatcher_impl.h +++ b/source/common/event/dispatcher_impl.h @@ -54,7 +54,8 @@ class DispatcherImpl : Logger::Loggable, Network::Address::InstanceConstSharedPtr source_address, Network::TransportSocketPtr&& transport_socket, const Network::ConnectionSocket::OptionsSharedPtr& options) override; - // Register the internal listener to setup the internal connection. Pass nullptr callback to unregister. + // Register the internal listener to setup the internal connection. Pass nullptr callback to + // unregister. void registerInternalListener(const std::string& internal_listener_id, InternalConnectionCallback internal_conn_callback); diff --git a/source/common/network/internal_listener_impl.h b/source/common/network/internal_listener_impl.h index be4c93220782..1f586019ecbe 100644 --- a/source/common/network/internal_listener_impl.h +++ b/source/common/network/internal_listener_impl.h @@ -22,7 +22,7 @@ class InternalListenerImpl : public BaseListenerImpl { void setupInternalListener(Event::DispatcherImpl& dispatcher, const std::string& internal_listener_id); -// TODO(lambdai): make it private + // TODO(lambdai): make it private public: std::string internal_listener_id_; Event::DispatcherImpl& dispatcher_; diff --git a/source/common/network/utility.cc b/source/common/network/utility.cc index 158bdc79e20f..3c25f9b6ba01 100644 --- a/source/common/network/utility.cc +++ b/source/common/network/utility.cc @@ -512,10 +512,13 @@ Utility::protobufAddressSocketType(const envoy::config::core::v3::Address& proto } } case envoy::config::core::v3::Address::AddressCase::kPipe: - return Socket::Type::Stream; - default: + FALLTHRU; + case envoy::config::core::v3::Address::AddressCase::kEnvoyInternalAddress: + break; + case envoy::config::core::v3::Address::AddressCase::ADDRESS_NOT_SET: NOT_REACHED_GCOVR_EXCL_LINE; } + return Socket::Type::Stream; } Api::IoCallUint64Result Utility::writeToSocket(IoHandle& handle, const Buffer::Instance& buffer, diff --git a/source/common/network/utility.h b/source/common/network/utility.h index be64071e9ea6..4c01afdba800 100644 --- a/source/common/network/utility.h +++ b/source/common/network/utility.h @@ -282,7 +282,7 @@ class Utility { /** * Returns socket type corresponding to SocketAddress.protocol value of the - * given address, or SocketType::Stream if the address is a pipe address. + * given address, or SocketType::Stream if the address is a pipe address or internal address. * @param proto_address the address protobuf * @return socket type */ diff --git a/source/server/BUILD b/source/server/BUILD index e98944e1a404..4527ab7f3223 100644 --- a/source/server/BUILD +++ b/source/server/BUILD @@ -80,8 +80,8 @@ envoy_cc_library( "//source/common/common:non_copyable", "//source/common/event:deferred_task", "//source/common/network:connection_lib", - "//source/common/stats:timespan_lib", "//source/common/network:listener_lib", + "//source/common/stats:timespan_lib", "//source/common/stream_info:stream_info_lib", "//source/extensions/transport_sockets:well_known_names", ], diff --git a/source/server/connection_handler_impl.cc b/source/server/connection_handler_impl.cc index 33498b52f5d1..9f69107b809f 100644 --- a/source/server/connection_handler_impl.cc +++ b/source/server/connection_handler_impl.cc @@ -650,9 +650,8 @@ ConnectionHandlerImpl::ActiveInternalListener::~ActiveInternalListener() { void ConnectionHandlerImpl::ActiveInternalListener::shutdownListener() { internal_listener_->dispatcher_.registerInternalListener( - internal_listener_->internal_listener_id_, - /* connection_callback= */nullptr - ); + internal_listener_->internal_listener_id_, + /* connection_callback= */ nullptr); } // Copied from newConnection(). Invoked by SetupPipeListener. void ConnectionHandlerImpl::ActiveInternalListener::setupNewConnection( diff --git a/source/server/connection_handler_impl.h b/source/server/connection_handler_impl.h index 56a227256c49..581f1b976d6e 100644 --- a/source/server/connection_handler_impl.h +++ b/source/server/connection_handler_impl.h @@ -12,7 +12,6 @@ #include "envoy/network/filter.h" #include "envoy/network/listen_socket.h" #include "envoy/network/listener.h" - #include "envoy/server/active_udp_listener_config.h" #include "envoy/server/listener_manager.h" #include "envoy/stats/scope.h" @@ -20,8 +19,8 @@ #include "common/common/linked_object.h" #include "common/common/non_copyable.h" -#include "common/stream_info/stream_info_impl.h" #include "common/network/internal_listener_impl.h" +#include "common/stream_info/stream_info_impl.h" #include "spdlog/spdlog.h" diff --git a/source/server/listener_impl.cc b/source/server/listener_impl.cc index d0091f9c9484..e2171870240e 100644 --- a/source/server/listener_impl.cc +++ b/source/server/listener_impl.cc @@ -64,7 +64,7 @@ ListenSocketFactoryImpl::ListenSocketFactoryImpl(ListenerComponentFactory& facto const std::string& listener_name, bool reuse_port) : factory_(factory), local_address_(address), socket_type_(socket_type), options_(options), bind_to_port_(bind_to_port), listener_name_(listener_name), reuse_port_(reuse_port) { - // TODO(lambdai): Dispatch by address type. + // TODO(lambdai): Dispatch by address type. bool create_socket = false; if (local_address_->type() == Network::Address::Type::Ip) { if (socket_type_ == Network::Socket::Type::Datagram) { diff --git a/source/server/listener_impl.h b/source/server/listener_impl.h index 818056dfdbec..37bc7d023c0a 100644 --- a/source/server/listener_impl.h +++ b/source/server/listener_impl.h @@ -3,8 +3,10 @@ #include #include "envoy/access_log/access_log.h" +#include "envoy/config/core/v3/address.pb.h" #include "envoy/config/core/v3/base.pb.h" #include "envoy/config/listener/v3/listener.pb.h" +#include "envoy/network/address.h" #include "envoy/network/drain_decision.h" #include "envoy/network/filter.h" #include "envoy/server/drain_manager.h" @@ -57,7 +59,9 @@ class ListenSocketFactoryImpl : public Network::ListenSocketFactory, * @return the socket shared by worker threads; otherwise return null. */ Network::SocketOptRef sharedSocket() const override { - if (!reuse_port_) { + if (!reuse_port_ && + // EnvoyInternalAddress is always handled by worker. + local_address_->type() != Network::Address::Type::EnvoyInternal) { ASSERT(socket_ != nullptr); return *socket_; } diff --git a/test/mocks/event/mocks.h b/test/mocks/event/mocks.h index 940cf5711ecb..01e0372389fa 100644 --- a/test/mocks/event/mocks.h +++ b/test/mocks/event/mocks.h @@ -56,8 +56,8 @@ class MockDispatcher : public Dispatcher { } Network::ClientConnectionPtr - createInternalConnection(Network::Address::InstanceConstSharedPtr internal_address, - Network::Address::InstanceConstSharedPtr local_address) override { + createInternalConnection(Network::Address::InstanceConstSharedPtr, + Network::Address::InstanceConstSharedPtr) override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } diff --git a/test/server/connection_handler_test.cc b/test/server/connection_handler_test.cc index 587bac56767b..17826b6ee1ee 100644 --- a/test/server/connection_handler_test.cc +++ b/test/server/connection_handler_test.cc @@ -1132,21 +1132,13 @@ TEST_F(ConnectionHandlerTest, TcpBacklogCustom) { handler_->addListener(absl::nullopt, *test_listener); } +TEST_F(ConnectionHandlerTest, AddInternalListener) {} -TEST_F(ConnectionHandlerTest, AddInternalListener) { -} - -TEST_F(ConnectionHandlerTest, StopInternalListener) { -} - -TEST_F(ConnectionHandlerTest, InternalListenerAddConnection) { -} - -TEST_F(ConnectionHandlerTest, RemoveInternalListener) { -} - +TEST_F(ConnectionHandlerTest, StopInternalListener) {} +TEST_F(ConnectionHandlerTest, InternalListenerAddConnection) {} +TEST_F(ConnectionHandlerTest, RemoveInternalListener) {} } // namespace } // namespace Server diff --git a/test/server/listener_manager_impl_test.cc b/test/server/listener_manager_impl_test.cc index c7d66354dcfb..db49f764803b 100644 --- a/test/server/listener_manager_impl_test.cc +++ b/test/server/listener_manager_impl_test.cc @@ -4824,6 +4824,72 @@ TEST_F(ListenerManagerImplTest, TcpBacklogCustomConfig) { EXPECT_EQ(100U, manager_->listeners().back().get().tcpBacklogSize()); } +// Test that internal listener config can be added. +TEST_F(ListenerManagerImplTest, InternalListenerBasic) { + const envoy::config::listener::v3::Listener listener = parseListenerFromV3Yaml(R"EOF( +internal_listener: {} +reuse_port: false +address: + envoy_internal_address: + server_listener_name: listener_foo +filter_chains: + filters: [] + )EOF"); + + manager_->addOrUpdateListener(listener, "", true); + EXPECT_EQ(1U, manager_->listeners().size()); +} + +// Test internal listener can be updated and drained. +TEST_F(ListenerManagerImplForInPlaceFilterChainUpdateTest, InternalListenerUpdate) { + const envoy::config::listener::v3::Listener listener_proto = parseListenerFromV3Yaml(R"EOF( +name: listener_name_foo +internal_listener: {} +reuse_port: false +address: + envoy_internal_address: + server_listener_name: listener_foo +filter_chains: + filters: [] + )EOF"); + + EXPECT_CALL(*worker_, start(_)); + manager_->startWorkers(guard_dog_); + + ListenerHandle* listener_foo = expectListenerCreate(false, true); + + // expectAddListener(listener_proto, listener_foo) except no listen socket + { + // EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, {true})); + EXPECT_CALL(*worker_, addListener(_, _, _)); + manager_->addOrUpdateListener(listener_proto, "", true); + worker_->callAddCompletion(true); + EXPECT_EQ(1UL, manager_->listeners().size()); + checkStats(__LINE__, 1, 0, 0, 0, 1, 0, 0); + } + ListenerHandle* listener_foo_update1 = expectListenerCreate(false, true); + + auto new_listener_proto = listener_proto; + new_listener_proto.set_traffic_direction(::envoy::config::core::v3::TrafficDirection::INBOUND); + expectUpdateToThenDrain(new_listener_proto, listener_foo); + + // expectRemove(new_listener_proto, listener_foo_update1) except no socket close_ + { + EXPECT_CALL(*worker_, stopListener(_, _)); + // EXPECT_CALL(*listener_factory_.socket_, close()); + EXPECT_CALL(*listener_foo_update1->drain_manager_, startDrainSequence(_)); + EXPECT_TRUE(manager_->removeListener(new_listener_proto.name())); + + EXPECT_CALL(*worker_, removeListener(_, _)); + listener_foo_update1->drain_manager_->drain_sequence_completion_(); + + EXPECT_CALL(*listener_foo_update1, onDestroy()); + worker_->callRemovalCompletion(); + } + EXPECT_EQ(0UL, manager_->listeners().size()); + EXPECT_EQ(0, server_.stats_store_.counter("listener_manager.listener_in_place_updated").value()); +} + } // namespace } // namespace Server } // namespace Envoy From cfca89508410b1e2927794b09cad2b6805527b7d Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Fri, 11 Sep 2020 23:04:05 +0000 Subject: [PATCH 016/100] refactor ConnectionSocketImpl: has SocketImpl instead of inherit Signed-off-by: Yuchen Dai --- source/common/network/listen_socket_impl.h | 59 +++++++++++++++++++--- source/common/network/socket_impl.h | 2 +- 2 files changed, 54 insertions(+), 7 deletions(-) diff --git a/source/common/network/listen_socket_impl.h b/source/common/network/listen_socket_impl.h index 55299c953956..a201a6b8c1c6 100644 --- a/source/common/network/listen_socket_impl.h +++ b/source/common/network/listen_socket_impl.h @@ -76,19 +76,19 @@ class UdsListenSocket : public ListenSocketImpl { Socket::Type socketType() const override { return Socket::Type::Stream; } }; -class ConnectionSocketImpl : public SocketImpl, public ConnectionSocket { +class ConnectionSocketImpl : public ConnectionSocket { public: ConnectionSocketImpl(IoHandlePtr&& io_handle, const Address::InstanceConstSharedPtr& local_address, const Address::InstanceConstSharedPtr& remote_address) - : SocketImpl(std::move(io_handle), local_address), remote_address_(remote_address), + : socket_(std::move(io_handle), local_address), remote_address_(remote_address), direct_remote_address_(remote_address) {} ConnectionSocketImpl(Socket::Type type, const Address::InstanceConstSharedPtr& local_address, const Address::InstanceConstSharedPtr& remote_address) - : SocketImpl(type, local_address), remote_address_(remote_address), + : socket_(type, local_address), remote_address_(remote_address), direct_remote_address_(remote_address) { - setLocalAddress(local_address); + socket_.setLocalAddress(local_address); } // Network::Socket @@ -99,8 +99,46 @@ class ConnectionSocketImpl : public SocketImpl, public ConnectionSocket { const Address::InstanceConstSharedPtr& directRemoteAddress() const override { return direct_remote_address_; } + const Address::InstanceConstSharedPtr& localAddress() const override { + return socket_.localAddress(); + } + void setLocalAddress(const Address::InstanceConstSharedPtr& local_address) override { + socket_.setLocalAddress(local_address); + } + IoHandle& ioHandle() override { return socket_.ioHandle(); } + + const IoHandle& ioHandle() const override { return socket_.ioHandle(); } + Address::Type addressType() const override { return socket_.addressType(); } + absl::optional ipVersion() const override { return socket_.ipVersion(); } + void close() override { return socket_.close(); } + bool isOpen() const override { return socket_.isOpen(); } + Api::SysCallIntResult bind(const Address::InstanceConstSharedPtr address) override { + return socket_.bind(address); + } + Api::SysCallIntResult listen(int backlog) override { return socket_.listen(backlog); } + Api::SysCallIntResult connect(const Address::InstanceConstSharedPtr address) override { + return socket_.connect(address); + } + Api::SysCallIntResult setBlockingForTest(bool blocking) override { + return socket_.setBlockingForTest(blocking); + } + + Api::SysCallIntResult setSocketOption(int level, int optname, const void* optval, + socklen_t optlen) override { + return socket_.setSocketOption(level, optname, optval, optlen); + } + + Api::SysCallIntResult getSocketOption(int level, int optname, void* optval, + socklen_t* optlen) const override { + return socket_.getSocketOption(level, optname, optval, optlen); + } + + void addOption(const OptionConstSharedPtr& option) override { return socket_.addOption(option); } + void addOptions(const OptionsSharedPtr& option) override { return socket_.addOptions(option); } + const OptionsSharedPtr& options() const override { return socket_.options(); } + void restoreLocalAddress(const Address::InstanceConstSharedPtr& local_address) override { - setLocalAddress(local_address); + socket_.setLocalAddress(local_address); local_address_restored_ = true; } void setRemoteAddress(const Address::InstanceConstSharedPtr& remote_address) override { @@ -129,6 +167,7 @@ class ConnectionSocketImpl : public SocketImpl, public ConnectionSocket { absl::string_view requestedServerName() const override { return server_name_; } protected: + SocketImpl socket_; Address::InstanceConstSharedPtr remote_address_; const Address::InstanceConstSharedPtr direct_remote_address_; bool local_address_restored_{false}; @@ -159,6 +198,14 @@ class AcceptedSocketImpl : public ConnectionSocketImpl { static std::atomic global_accepted_socket_count_; }; +// InternalSocketImpl used with internal listener. The owned IoHandle is not referring to any OS fd. +class InternalSocketImpl : public ConnectionSocketImpl { + InternalSocketImpl(IoHandlePtr&& io_handle, const Address::InstanceConstSharedPtr& local_address, + const Address::InstanceConstSharedPtr& remote_address) + : ConnectionSocketImpl(std::move(io_handle), local_address, remote_address) {} + ~InternalSocketImpl() override = default; +}; + // ConnectionSocket used with client connections. class ClientSocketImpl : public ConnectionSocketImpl { public: @@ -167,7 +214,7 @@ class ClientSocketImpl : public ConnectionSocketImpl { : ConnectionSocketImpl(Network::ioHandleForAddr(Socket::Type::Stream, remote_address), nullptr, remote_address) { if (options) { - addOptions(options); + socket_.addOptions(options); } } }; diff --git a/source/common/network/socket_impl.h b/source/common/network/socket_impl.h index 1704b6a005f1..087226c198d6 100644 --- a/source/common/network/socket_impl.h +++ b/source/common/network/socket_impl.h @@ -53,9 +53,9 @@ class SocketImpl : public virtual Socket { Address::Type addressType() const override { return addr_type_; } absl::optional ipVersion() const override; -protected: SocketImpl(IoHandlePtr&& io_handle, const Address::InstanceConstSharedPtr& local_address); +protected: const IoHandlePtr io_handle_; Address::InstanceConstSharedPtr local_address_; OptionsSharedPtr options_; From 07c1ecbfc2bd8a3dad19de60980a9854872bbba9 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Mon, 14 Sep 2020 20:07:36 +0000 Subject: [PATCH 017/100] rename listener to stream_listener in tcpsocket Signed-off-by: Yuchen Dai --- include/envoy/network/listener.h | 2 + .../common/network/internal_listener_impl.cc | 14 ++++-- source/common/network/listen_socket_impl.h | 9 ++-- source/server/connection_handler_impl.cc | 50 ++++++++++++++----- source/server/connection_handler_impl.h | 18 ++++--- 5 files changed, 65 insertions(+), 28 deletions(-) diff --git a/include/envoy/network/listener.h b/include/envoy/network/listener.h index 0bb76986d548..6f3422d598bd 100644 --- a/include/envoy/network/listener.h +++ b/include/envoy/network/listener.h @@ -198,6 +198,8 @@ class InternalListenerCallbacks { virtual void setupNewConnection(Network::ConnectionPtr server_conn, Network::ConnectionSocketPtr socket) PURE; + virtual void onNewSocket(Network::ConnectionSocketPtr socket, + Network::ConnectionPtr server_conn) PURE; }; /** diff --git a/source/common/network/internal_listener_impl.cc b/source/common/network/internal_listener_impl.cc index e864429359f1..58da8c4a3337 100644 --- a/source/common/network/internal_listener_impl.cc +++ b/source/common/network/internal_listener_impl.cc @@ -13,20 +13,28 @@ #include "common/network/address_impl.h" #include "common/network/io_socket_handle_impl.h" +#include "absl/strings/str_cat.h" + namespace Envoy { namespace Network { - +namespace { + uint64_t next_internal_connection_id = 0; +} void InternalListenerImpl::setupInternalListener(Event::DispatcherImpl& dispatcher, const std::string& listener_id) { dispatcher.registerInternalListener( listener_id, [this](const Address::InstanceConstSharedPtr& address, Network::ConnectionPtr server_conn) { - Network::ConnectionSocketPtr socket = std::make_unique( + address->asString() + auto socket = std::make_unique( nullptr, // Local address, // Remote - std::make_shared("127.0.0.1")); + std::make_shared(absl::StrCat( + address->asString(), + "-", + ++next_internal_connection_id)); cb_.setupNewConnection(std::move(server_conn), std::move(socket)); }); } diff --git a/source/common/network/listen_socket_impl.h b/source/common/network/listen_socket_impl.h index a201a6b8c1c6..200c73ed09b1 100644 --- a/source/common/network/listen_socket_impl.h +++ b/source/common/network/listen_socket_impl.h @@ -198,12 +198,13 @@ class AcceptedSocketImpl : public ConnectionSocketImpl { static std::atomic global_accepted_socket_count_; }; -// InternalSocketImpl used with internal listener. The owned IoHandle is not referring to any OS fd. -class InternalSocketImpl : public ConnectionSocketImpl { - InternalSocketImpl(IoHandlePtr&& io_handle, const Address::InstanceConstSharedPtr& local_address, +// InternalConnectionSocketImpl used with internal listener. The owned IoHandle is not referring to any OS fd. +class InternalConnectionSocketImpl : public ConnectionSocketImpl { +public: + InternalConnectionSocketImpl(IoHandlePtr&& io_handle, const Address::InstanceConstSharedPtr& local_address, const Address::InstanceConstSharedPtr& remote_address) : ConnectionSocketImpl(std::move(io_handle), local_address, remote_address) {} - ~InternalSocketImpl() override = default; + ~InternalConnectionSocketImpl() override = default; }; // ConnectionSocket used with client connections. diff --git a/source/server/connection_handler_impl.cc b/source/server/connection_handler_impl.cc index 9f69107b809f..d03eb06afdaa 100644 --- a/source/server/connection_handler_impl.cc +++ b/source/server/connection_handler_impl.cc @@ -42,7 +42,7 @@ void ConnectionHandlerImpl::addListener(absl::optional overridden_list Network::ListenerConfig& config) { ActiveListenerDetails details; if (config.isInternalListener()) { - + //TODO(lambdai): register internal listener here. } else if (config.listenSocketFactory().socketType() == Network::Socket::Type::Stream) { if (overridden_listener.has_value()) { for (auto& listener : listeners_) { @@ -233,12 +233,12 @@ ConnectionHandlerImpl::findActiveTcpListenerByAddress(const Network::Address::In } void ConnectionHandlerImpl::ActiveTcpSocket::onTimeout() { - listener_.stats_.downstream_pre_cx_timeout_.inc(); + stream_listener_.stats_.downstream_pre_cx_timeout_.inc(); ASSERT(inserted()); ENVOY_LOG(debug, "listener filter times out after {} ms", - listener_.listener_filters_timeout_.count()); + stream_listener_.listener_filters_timeout_.count()); - if (listener_.continue_on_listener_filters_timeout_) { + if (stream_listener_.continue_on_listener_filters_timeout_) { ENVOY_LOG(debug, "fallback to default listener filter"); newConnection(); } @@ -246,22 +246,22 @@ void ConnectionHandlerImpl::ActiveTcpSocket::onTimeout() { } void ConnectionHandlerImpl::ActiveTcpSocket::startTimer() { - if (listener_.listener_filters_timeout_.count() > 0) { - timer_ = listener_.parent_.dispatcher_.createTimer([this]() -> void { onTimeout(); }); - timer_->enableTimer(listener_.listener_filters_timeout_); + if (stream_listener_.listener_filters_timeout_.count() > 0) { + timer_ = stream_listener_.parent_.dispatcher_.createTimer([this]() -> void { onTimeout(); }); + timer_->enableTimer(stream_listener_.listener_filters_timeout_); } } void ConnectionHandlerImpl::ActiveTcpSocket::unlink() { - ActiveTcpSocketPtr removed = removeFromList(listener_.sockets_); + ActiveTcpSocketPtr removed = removeFromList(stream_listener_.sockets_); if (removed->timer_ != nullptr) { removed->timer_->disableTimer(); } // Emit logs if a connection is not established. if (!connected_) { - emitLogs(*listener_.config_, *stream_info_); + emitLogs(*stream_listener_.config_, *stream_info_); } - listener_.parent_.dispatcher_.deferredDelete(std::move(removed)); + stream_listener_.parent_.dispatcher_.deferredDelete(std::move(removed)); } void ConnectionHandlerImpl::ActiveTcpSocket::continueFilterChain(bool success) { @@ -316,7 +316,7 @@ void ConnectionHandlerImpl::ActiveTcpSocket::newConnection() { if (hand_off_restored_destination_connections_ && socket_->localAddressRestored()) { // Find a listener associated with the original destination address. - new_listener = listener_.parent_.findActiveTcpListenerByAddress(*socket_->localAddress()); + new_listener = stream_listener_.parent_.findActiveTcpListenerByAddress(*socket_->localAddress()); } if (new_listener.has_value()) { // Hands off connections redirected by iptables to the listener associated with the @@ -326,7 +326,7 @@ void ConnectionHandlerImpl::ActiveTcpSocket::newConnection() { // initially accepted. Note also that we must account for the number of connections properly // across both listeners. // TODO(mattklein123): See note in ~ActiveTcpSocket() related to making this accounting better. - listener_.decNumConnections(); + stream_listener_.decNumConnections(); new_listener.value().get().incNumConnections(); new_listener.value().get().onAcceptWorker(std::move(socket_), false, true); } else { @@ -341,7 +341,7 @@ void ConnectionHandlerImpl::ActiveTcpSocket::newConnection() { // Particularly the assigned events need to reset before assigning new events in the follow up. accept_filters_.clear(); // Create a new connection on this listener. - listener_.newConnection(std::move(socket_), std::move(stream_info_)); + stream_listener_.newConnection(std::move(socket_), std::move(stream_info_)); } } @@ -653,6 +653,30 @@ void ConnectionHandlerImpl::ActiveInternalListener::shutdownListener() { internal_listener_->internal_listener_id_, /* connection_callback= */ nullptr); } + +void ConnectionHandlerImpl::ActiveInternalListener::onNewSocket(Network::ConnectionSocketPtr , + Network::ConnectionPtr) { + // TODO(lambdai): FIX ME after resolve reference to ActiveInternalListener. + ActiveTcpSocketPtr active_socket = nullptr; + // std::make_unique( + // *this, std::move(socket), /* hand_off_restored_destination_connections=*/false); + // Create and run the filters + config_->filterChainFactory().createListenerFilterChain(*active_socket); + active_socket->continueFilterChain(true); + + // Move active_socket to the sockets_ list if filter iteration needs to continue later. + // Otherwise we let active_socket be destructed when it goes out of scope. + if (active_socket->iter_ != active_socket->accept_filters_.end()) { + active_socket->startTimer(); + LinkedList::moveIntoListBack(std::move(active_socket), sockets_); + } else { + // If active_socket is about to be destructed, emit logs if a connection is not created. + if (!active_socket->connected_) { + emitLogs(*config_, *active_socket->stream_info_); + } + } +} + // Copied from newConnection(). Invoked by SetupPipeListener. void ConnectionHandlerImpl::ActiveInternalListener::setupNewConnection( Network::ConnectionPtr server_conn, Network::ConnectionSocketPtr socket) { diff --git a/source/server/connection_handler_impl.h b/source/server/connection_handler_impl.h index 581f1b976d6e..e0c092bcb359 100644 --- a/source/server/connection_handler_impl.h +++ b/source/server/connection_handler_impl.h @@ -20,6 +20,7 @@ #include "common/common/linked_object.h" #include "common/common/non_copyable.h" #include "common/network/internal_listener_impl.h" +#include "common/network/listen_socket_impl.h" #include "common/stream_info/stream_info_impl.h" #include "spdlog/spdlog.h" @@ -209,7 +210,8 @@ class ConnectionHandlerImpl : public Network::ConnectionHandler, // Network::InternalListenerCallbacks void setupNewConnection(Network::ConnectionPtr server_conn, Network::ConnectionSocketPtr socket) override; - + void onNewSocket(Network::ConnectionSocketPtr socket, + Network::ConnectionPtr server_conn) override; // ActiveListenerImplBase Network::Listener* listener() override { return internal_listener_.get(); } void pauseListening() override { internal_listener_->disable(); } @@ -310,19 +312,19 @@ class ConnectionHandlerImpl : public Network::ConnectionHandler, public Event::DeferredDeletable { ActiveTcpSocket(ActiveTcpListener& listener, Network::ConnectionSocketPtr&& socket, bool hand_off_restored_destination_connections) - : listener_(listener), socket_(std::move(socket)), + : stream_listener_(listener), socket_(std::move(socket)), hand_off_restored_destination_connections_(hand_off_restored_destination_connections), iter_(accept_filters_.end()), stream_info_(std::make_unique( - listener_.parent_.dispatcher_.timeSource(), + stream_listener_.parent_.dispatcher_.timeSource(), StreamInfo::FilterState::LifeSpan::Connection)) { - listener_.stats_.downstream_pre_cx_active_.inc(); + stream_listener_.stats_.downstream_pre_cx_active_.inc(); stream_info_->setDownstreamLocalAddress(socket_->localAddress()); stream_info_->setDownstreamRemoteAddress(socket_->remoteAddress()); stream_info_->setDownstreamDirectRemoteAddress(socket_->directRemoteAddress()); } ~ActiveTcpSocket() override { accept_filters_.clear(); - listener_.stats_.downstream_pre_cx_active_.dec(); + stream_listener_.stats_.downstream_pre_cx_active_.dec(); // If the underlying socket is no longer attached, it means that it has been transferred to // an active connection. In this case, the active connection will decrement the number @@ -332,7 +334,7 @@ class ConnectionHandlerImpl : public Network::ConnectionHandler, // ActiveTcpConnection, having a shared object which does accounting (but would require // another allocation, etc.). if (socket_ != nullptr) { - listener_.decNumConnections(); + stream_listener_.decNumConnections(); } } @@ -379,7 +381,7 @@ class ConnectionHandlerImpl : public Network::ConnectionHandler, // Network::ListenerFilterCallbacks Network::ConnectionSocket& socket() override { return *socket_.get(); } - Event::Dispatcher& dispatcher() override { return listener_.parent_.dispatcher_; } + Event::Dispatcher& dispatcher() override { return stream_listener_.parent_.dispatcher_; } void continueFilterChain(bool success) override; void setDynamicMetadata(const std::string& name, const ProtobufWkt::Struct& value) override; envoy::config::core::v3::Metadata& dynamicMetadata() override { @@ -389,7 +391,7 @@ class ConnectionHandlerImpl : public Network::ConnectionHandler, return stream_info_->dynamicMetadata(); }; - ActiveTcpListener& listener_; + ActiveTcpListener& stream_listener_; Network::ConnectionSocketPtr socket_; const bool hand_off_restored_destination_connections_; std::list accept_filters_; From 171b1d901833824a845f722a3d1bbfb747223751 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Mon, 14 Sep 2020 21:33:25 +0000 Subject: [PATCH 018/100] extract generic listener filter Signed-off-by: Yuchen Dai --- source/common/network/BUILD | 8 ++++ .../common/network/generic_listener_filter.h | 40 +++++++++++++++++++ source/server/BUILD | 1 + source/server/connection_handler_impl.h | 38 +++--------------- 4 files changed, 54 insertions(+), 33 deletions(-) create mode 100644 source/common/network/generic_listener_filter.h diff --git a/source/common/network/BUILD b/source/common/network/BUILD index 60c11da5ea45..eed6888c77d5 100644 --- a/source/common/network/BUILD +++ b/source/common/network/BUILD @@ -226,6 +226,14 @@ envoy_cc_library( ], ) +envoy_cc_library( + name = "generic_listener_filter_lib", + hdrs = ["generic_listener_filter.h"], + deps = [ + "//include/envoy/network:filter_interface", + ], +) + envoy_cc_library( name = "listener_lib", srcs = [ diff --git a/source/common/network/generic_listener_filter.h b/source/common/network/generic_listener_filter.h new file mode 100644 index 000000000000..ed04783aa1a3 --- /dev/null +++ b/source/common/network/generic_listener_filter.h @@ -0,0 +1,40 @@ +#include "envoy/network/filter.h" + +namespace Envoy { +namespace Network { + +/** + * GenericListenerFilter wraps another ListenerFilter to provides the common listener filter + * attributes such as ListenerFilterMatcher. + */ +class GenericListenerFilter : public Network::ListenerFilter { +public: + GenericListenerFilter(const Network::ListenerFilterMatcherSharedPtr& matcher, + Network::ListenerFilterPtr listener_filter) + : listener_filter_(std::move(listener_filter)), matcher_(std::move(matcher)) {} + Network::FilterStatus onAccept(ListenerFilterCallbacks& cb) override { + if (isDisabled(cb)) { + return Network::FilterStatus::Continue; + } + return listener_filter_->onAccept(cb); + } + /** + * Check if this filter filter should be disabled on the incoming socket. + * @param cb the callbacks the filter instance can use to communicate with the filter chain. + **/ + bool isDisabled(ListenerFilterCallbacks& cb) { + if (matcher_ == nullptr) { + return false; + } else { + return matcher_->matches(cb); + } + } + +private: + const Network::ListenerFilterPtr listener_filter_; + const Network::ListenerFilterMatcherSharedPtr matcher_; +}; +using ListenerFilterWrapperPtr = std::unique_ptr; + +} // namespace Network +} // namespace Envoy \ No newline at end of file diff --git a/source/server/BUILD b/source/server/BUILD index 4527ab7f3223..22ef1c6a95af 100644 --- a/source/server/BUILD +++ b/source/server/BUILD @@ -80,6 +80,7 @@ envoy_cc_library( "//source/common/common:non_copyable", "//source/common/event:deferred_task", "//source/common/network:connection_lib", + "//source/common/network:generic_listener_filter_lib", "//source/common/network:listener_lib", "//source/common/stats:timespan_lib", "//source/common/stream_info:stream_info_lib", diff --git a/source/server/connection_handler_impl.h b/source/server/connection_handler_impl.h index e0c092bcb359..bb14b769bd1b 100644 --- a/source/server/connection_handler_impl.h +++ b/source/server/connection_handler_impl.h @@ -22,6 +22,7 @@ #include "common/network/internal_listener_impl.h" #include "common/network/listen_socket_impl.h" #include "common/stream_info/stream_info_impl.h" +#include "common/network/generic_listener_filter.h" #include "spdlog/spdlog.h" @@ -343,40 +344,11 @@ class ConnectionHandlerImpl : public Network::ConnectionHandler, void unlink(); void newConnection(); - class GenericListenerFilter : public Network::ListenerFilter { - public: - GenericListenerFilter(const Network::ListenerFilterMatcherSharedPtr& matcher, - Network::ListenerFilterPtr listener_filter) - : listener_filter_(std::move(listener_filter)), matcher_(std::move(matcher)) {} - Network::FilterStatus onAccept(ListenerFilterCallbacks& cb) override { - if (isDisabled(cb)) { - return Network::FilterStatus::Continue; - } - return listener_filter_->onAccept(cb); - } - /** - * Check if this filter filter should be disabled on the incoming socket. - * @param cb the callbacks the filter instance can use to communicate with the filter chain. - **/ - bool isDisabled(ListenerFilterCallbacks& cb) { - if (matcher_ == nullptr) { - return false; - } else { - return matcher_->matches(cb); - } - } - - private: - const Network::ListenerFilterPtr listener_filter_; - const Network::ListenerFilterMatcherSharedPtr matcher_; - }; - using ListenerFilterWrapperPtr = std::unique_ptr; - // Network::ListenerFilterManager void addAcceptFilter(const Network::ListenerFilterMatcherSharedPtr& listener_filter_matcher, Network::ListenerFilterPtr&& filter) override { - accept_filters_.emplace_back( - std::make_unique(listener_filter_matcher, std::move(filter))); + accept_filters_.emplace_back(std::make_unique( + listener_filter_matcher, std::move(filter))); } // Network::ListenerFilterCallbacks @@ -394,8 +366,8 @@ class ConnectionHandlerImpl : public Network::ConnectionHandler, ActiveTcpListener& stream_listener_; Network::ConnectionSocketPtr socket_; const bool hand_off_restored_destination_connections_; - std::list accept_filters_; - std::list::iterator iter_; + std::list accept_filters_; + std::list::iterator iter_; Event::TimerPtr timer_; std::unique_ptr stream_info_; bool connected_{false}; From c99aa54ab75caaa664451a0ef8b39af3f091025c Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Mon, 14 Sep 2020 23:37:27 +0000 Subject: [PATCH 019/100] active internal socket Signed-off-by: Yuchen Dai --- include/envoy/network/listener.h | 2 +- .../common/network/internal_listener_impl.cc | 2 +- source/common/network/listen_socket_impl.h | 8 +- source/server/connection_handler_impl.cc | 124 +++++++++++++++--- source/server/connection_handler_impl.h | 93 ++++++++++++- 5 files changed, 202 insertions(+), 27 deletions(-) diff --git a/include/envoy/network/listener.h b/include/envoy/network/listener.h index 6f3422d598bd..86a8a27a50ba 100644 --- a/include/envoy/network/listener.h +++ b/include/envoy/network/listener.h @@ -199,7 +199,7 @@ class InternalListenerCallbacks { virtual void setupNewConnection(Network::ConnectionPtr server_conn, Network::ConnectionSocketPtr socket) PURE; virtual void onNewSocket(Network::ConnectionSocketPtr socket, - Network::ConnectionPtr server_conn) PURE; + Network::ConnectionSocketPtr server_socket) PURE; }; /** diff --git a/source/common/network/internal_listener_impl.cc b/source/common/network/internal_listener_impl.cc index 58da8c4a3337..da0f69864dea 100644 --- a/source/common/network/internal_listener_impl.cc +++ b/source/common/network/internal_listener_impl.cc @@ -18,7 +18,7 @@ namespace Envoy { namespace Network { namespace { - uint64_t next_internal_connection_id = 0; +uint64_t next_internal_connection_id = 0; } void InternalListenerImpl::setupInternalListener(Event::DispatcherImpl& dispatcher, const std::string& listener_id) { diff --git a/source/common/network/listen_socket_impl.h b/source/common/network/listen_socket_impl.h index 200c73ed09b1..b79e0c31e142 100644 --- a/source/common/network/listen_socket_impl.h +++ b/source/common/network/listen_socket_impl.h @@ -198,11 +198,13 @@ class AcceptedSocketImpl : public ConnectionSocketImpl { static std::atomic global_accepted_socket_count_; }; -// InternalConnectionSocketImpl used with internal listener. The owned IoHandle is not referring to any OS fd. +// InternalConnectionSocketImpl used with internal listener. The owned IoHandle is not referring to +// any OS fd. class InternalConnectionSocketImpl : public ConnectionSocketImpl { public: - InternalConnectionSocketImpl(IoHandlePtr&& io_handle, const Address::InstanceConstSharedPtr& local_address, - const Address::InstanceConstSharedPtr& remote_address) + InternalConnectionSocketImpl(IoHandlePtr&& io_handle, + const Address::InstanceConstSharedPtr& local_address, + const Address::InstanceConstSharedPtr& remote_address) : ConnectionSocketImpl(std::move(io_handle), local_address, remote_address) {} ~InternalConnectionSocketImpl() override = default; }; diff --git a/source/server/connection_handler_impl.cc b/source/server/connection_handler_impl.cc index d03eb06afdaa..0fbf51da5b26 100644 --- a/source/server/connection_handler_impl.cc +++ b/source/server/connection_handler_impl.cc @@ -42,7 +42,7 @@ void ConnectionHandlerImpl::addListener(absl::optional overridden_list Network::ListenerConfig& config) { ActiveListenerDetails details; if (config.isInternalListener()) { - //TODO(lambdai): register internal listener here. + // TODO(lambdai): register internal listener here. } else if (config.listenSocketFactory().socketType() == Network::Socket::Type::Stream) { if (overridden_listener.has_value()) { for (auto& listener : listeners_) { @@ -316,7 +316,8 @@ void ConnectionHandlerImpl::ActiveTcpSocket::newConnection() { if (hand_off_restored_destination_connections_ && socket_->localAddressRestored()) { // Find a listener associated with the original destination address. - new_listener = stream_listener_.parent_.findActiveTcpListenerByAddress(*socket_->localAddress()); + new_listener = + stream_listener_.parent_.findActiveTcpListenerByAddress(*socket_->localAddress()); } if (new_listener.has_value()) { // Hands off connections redirected by iptables to the listener associated with the @@ -378,12 +379,12 @@ void ConnectionHandlerImpl::ActiveTcpListener::onAcceptWorker( // Move active_socket to the sockets_ list if filter iteration needs to continue later. // Otherwise we let active_socket be destructed when it goes out of scope. - if (active_socket->iter_ != active_socket->accept_filters_.end()) { + if (!active_socket->isListenerFiltersCompleted()) { active_socket->startTimer(); LinkedList::moveIntoListBack(std::move(active_socket), sockets_); } else { // If active_socket is about to be destructed, emit logs if a connection is not created. - if (!active_socket->connected_) { + if (!active_socket->isConnected()) { emitLogs(*config_, *active_socket->stream_info_); } } @@ -610,9 +611,104 @@ void ActiveRawUdpListener::addReadFilter(Network::UdpListenerReadFilterPtr&& fil Network::UdpListener& ActiveRawUdpListener::udpListener() { return *udp_listener_; } +void ConnectionHandlerImpl::ActiveInternalSocket::onTimeout() { + stream_listener_.stats_.downstream_pre_cx_timeout_.inc(); + ASSERT(inserted()); + ENVOY_LOG(debug, "listener filter times out after {} ms", + stream_listener_.listener_filters_timeout_.count()); + + if (stream_listener_.continue_on_listener_filters_timeout_) { + ENVOY_LOG(debug, "fallback to default listener filter"); + newConnection(); + } + unlink(); +} + +void ConnectionHandlerImpl::ActiveInternalSocket::startTimer() { + if (stream_listener_.listener_filters_timeout_.count() > 0) { + timer_ = stream_listener_.parent_.dispatcher_.createTimer([this]() -> void { onTimeout(); }); + timer_->enableTimer(stream_listener_.listener_filters_timeout_); + } +} + +void ConnectionHandlerImpl::ActiveInternalSocket::unlink() { + auto removed = removeFromList(stream_listener_.sockets_); + if (removed->timer_ != nullptr) { + removed->timer_->disableTimer(); + } + // Emit logs if a connection is not established. + if (!connected_) { + emitLogs(*stream_listener_.config_, *stream_info_); + } + stream_listener_.parent_.dispatcher_.deferredDelete(std::move(removed)); +} + +void ConnectionHandlerImpl::ActiveInternalSocket::continueFilterChain(bool success) { + if (success) { + bool no_error = true; + if (iter_ == accept_filters_.end()) { + iter_ = accept_filters_.begin(); + } else { + iter_ = std::next(iter_); + } + + for (; iter_ != accept_filters_.end(); iter_++) { + Network::FilterStatus status = (*iter_)->onAccept(*this); + if (status == Network::FilterStatus::StopIteration) { + // The filter is responsible for calling us again at a later time to continue the filter + // chain from the next filter. + if (!socket().ioHandle().isOpen()) { + // break the loop but should not create new connection + no_error = false; + break; + } else { + // Blocking at the filter but no error + return; + } + } + } + // Successfully ran all the accept filters. + if (no_error) { + newConnection(); + } else { + // Signal the caller that no extra filter chain iteration is needed. + iter_ = accept_filters_.end(); + } + } + + // Filter execution concluded, unlink and delete this ActiveTcpSocket if it was linked. + if (inserted()) { + unlink(); + } +} + +void ConnectionHandlerImpl::ActiveInternalSocket::setDynamicMetadata( + const std::string& name, const ProtobufWkt::Struct& value) { + stream_info_->setDynamicMetadata(name, value); +} + +void ConnectionHandlerImpl::ActiveInternalSocket::newConnection() { + connected_ = true; + + // Set default transport protocol if none of the listener filters did it. + if (socket_->detectedTransportProtocol().empty()) { + socket_->setDetectedTransportProtocol( + Extensions::TransportSockets::TransportProtocolNames::get().RawBuffer); + } + // TODO(lambdai): add integration test + // TODO: Address issues in wider scope. See https://github.com/envoyproxy/envoy/issues/8925 + // Erase accept filter states because accept filters may not get the opportunity to clean up. + // Particularly the assigned events need to reset before assigning new events in the follow up. + accept_filters_.clear(); + // Create a new connection on this listener. + stream_listener_.newConnection(std::move(socket_), stream_info_->dynamicMetadata()); +} + ConnectionHandlerImpl::ActiveInternalListener::ActiveInternalListener( ConnectionHandlerImpl& parent, Network::ListenerConfig& config) - : ConnectionHandlerImpl::ActiveListenerImplBase(parent, &config), parent_(parent) {} + : ConnectionHandlerImpl::ActiveListenerImplBase(parent, &config), parent_(parent), + listener_filters_timeout_(config.listenerFiltersTimeout()), + continue_on_listener_filters_timeout_(config.continueOnListenerFiltersTimeout()) {} void ConnectionHandlerImpl::ActiveInternalListener::updateListenerConfig( Network::ListenerConfig& config) { @@ -626,7 +722,7 @@ ConnectionHandlerImpl::ActiveInternalListener::~ActiveInternalListener() { // Purge sockets that have not progressed to connections. This should only happen when // a listener filter stops iteration and never resumes. while (!sockets_.empty()) { - ActiveTcpSocketPtr removed = sockets_.front()->removeFromList(sockets_); + auto removed = sockets_.front()->removeFromList(sockets_); parent_.dispatcher_.deferredDelete(std::move(removed)); } @@ -654,24 +750,22 @@ void ConnectionHandlerImpl::ActiveInternalListener::shutdownListener() { /* connection_callback= */ nullptr); } -void ConnectionHandlerImpl::ActiveInternalListener::onNewSocket(Network::ConnectionSocketPtr , - Network::ConnectionPtr) { - // TODO(lambdai): FIX ME after resolve reference to ActiveInternalListener. - ActiveTcpSocketPtr active_socket = nullptr; - // std::make_unique( - // *this, std::move(socket), /* hand_off_restored_destination_connections=*/false); +void ConnectionHandlerImpl::ActiveInternalListener::onNewSocket( + Network::ConnectionSocketPtr, Network::ConnectionSocketPtr socket) { + ActiveInternalSocketPtr active_socket = + std::make_unique(*this, std::move(socket)); // Create and run the filters config_->filterChainFactory().createListenerFilterChain(*active_socket); active_socket->continueFilterChain(true); // Move active_socket to the sockets_ list if filter iteration needs to continue later. // Otherwise we let active_socket be destructed when it goes out of scope. - if (active_socket->iter_ != active_socket->accept_filters_.end()) { + if (!active_socket->isListenerFiltersCompleted()) { active_socket->startTimer(); LinkedList::moveIntoListBack(std::move(active_socket), sockets_); } else { // If active_socket is about to be destructed, emit logs if a connection is not created. - if (!active_socket->connected_) { + if (!active_socket->isListenerFiltersCompleted()) { emitLogs(*config_, *active_socket->stream_info_); } } @@ -736,7 +830,7 @@ void ConnectionHandlerImpl::ActiveInternalListener::newConnection( stream_info->setDownstreamRemoteAddress(socket->remoteAddress()); stream_info->setDownstreamDirectRemoteAddress(socket->directRemoteAddress()); - // merge from the given dynamic metadata if it's not empty + // Merge from the given dynamic metadata if it's not empty. if (dynamic_metadata.filter_metadata_size() > 0) { stream_info->dynamicMetadata().MergeFrom(dynamic_metadata); } diff --git a/source/server/connection_handler_impl.h b/source/server/connection_handler_impl.h index bb14b769bd1b..850103c05386 100644 --- a/source/server/connection_handler_impl.h +++ b/source/server/connection_handler_impl.h @@ -19,10 +19,10 @@ #include "common/common/linked_object.h" #include "common/common/non_copyable.h" +#include "common/network/generic_listener_filter.h" #include "common/network/internal_listener_impl.h" #include "common/network/listen_socket_impl.h" #include "common/stream_info/stream_info_impl.h" -#include "common/network/generic_listener_filter.h" #include "spdlog/spdlog.h" @@ -106,6 +106,8 @@ class ConnectionHandlerImpl : public Network::ConnectionHandler, using ActiveTcpSocketPtr = std::unique_ptr; class ActiveConnections; using ActiveConnectionsPtr = std::unique_ptr; + struct ActiveInternalSocket; + using ActiveInternalSocketPtr = std::unique_ptr; /** * Wrapper for an active tcp listener owned by this handler. @@ -212,7 +214,7 @@ class ConnectionHandlerImpl : public Network::ConnectionHandler, void setupNewConnection(Network::ConnectionPtr server_conn, Network::ConnectionSocketPtr socket) override; void onNewSocket(Network::ConnectionSocketPtr socket, - Network::ConnectionPtr server_conn) override; + Network::ConnectionSocketPtr server_conn) override; // ActiveListenerImplBase Network::Listener* listener() override { return internal_listener_.get(); } void pauseListening() override { internal_listener_->disable(); } @@ -251,8 +253,9 @@ class ConnectionHandlerImpl : public Network::ConnectionHandler, ConnectionHandlerImpl& parent_; std::unique_ptr internal_listener_; - - std::list sockets_; + const std::chrono::milliseconds listener_filters_timeout_; + const bool continue_on_listener_filters_timeout_; + std::list sockets_; absl::node_hash_map connections_by_context_; // The number of connections currently active on this listener. This is typically used for @@ -315,9 +318,10 @@ class ConnectionHandlerImpl : public Network::ConnectionHandler, bool hand_off_restored_destination_connections) : stream_listener_(listener), socket_(std::move(socket)), hand_off_restored_destination_connections_(hand_off_restored_destination_connections), - iter_(accept_filters_.end()), stream_info_(std::make_unique( - stream_listener_.parent_.dispatcher_.timeSource(), - StreamInfo::FilterState::LifeSpan::Connection)) { + stream_info_(std::make_unique( + stream_listener_.parent_.dispatcher_.timeSource(), + StreamInfo::FilterState::LifeSpan::Connection)), + iter_(accept_filters_.end()) { stream_listener_.stats_.downstream_pre_cx_active_.inc(); stream_info_->setDownstreamLocalAddress(socket_->localAddress()); stream_info_->setDownstreamRemoteAddress(socket_->remoteAddress()); @@ -343,6 +347,8 @@ class ConnectionHandlerImpl : public Network::ConnectionHandler, void startTimer(); void unlink(); void newConnection(); + bool isListenerFiltersCompleted() { return iter_ == accept_filters_.end(); } + bool isConnected() { return connected_; } // Network::ListenerFilterManager void addAcceptFilter(const Network::ListenerFilterMatcherSharedPtr& listener_filter_matcher, @@ -366,10 +372,83 @@ class ConnectionHandlerImpl : public Network::ConnectionHandler, ActiveTcpListener& stream_listener_; Network::ConnectionSocketPtr socket_; const bool hand_off_restored_destination_connections_; + Event::TimerPtr timer_; + std::unique_ptr stream_info_; + + private: std::list accept_filters_; std::list::iterator iter_; + bool connected_{false}; + }; + + /** + * Wrapper for an active accepted internal socket owned by this handler. + */ + struct ActiveInternalSocket : public Network::ListenerFilterManager, + public Network::ListenerFilterCallbacks, + LinkedObject, + public Event::DeferredDeletable { + ActiveInternalSocket(ActiveInternalListener& listener, Network::ConnectionSocketPtr socket) + : stream_listener_(listener), socket_(std::move(socket)), + stream_info_(std::make_unique( + stream_listener_.parent_.dispatcher_.timeSource(), + StreamInfo::FilterState::LifeSpan::Connection)), + iter_(accept_filters_.end()) { + stream_listener_.stats_.downstream_pre_cx_active_.inc(); + stream_info_->setDownstreamLocalAddress(socket_->localAddress()); + stream_info_->setDownstreamRemoteAddress(socket_->remoteAddress()); + stream_info_->setDownstreamDirectRemoteAddress(socket_->directRemoteAddress()); + } + ~ActiveInternalSocket() override { + accept_filters_.clear(); + stream_listener_.stats_.downstream_pre_cx_active_.dec(); + + // If the underlying socket is no longer attached, it means that it has been transferred to + // an active connection. In this case, the active connection will decrement the number + // of listener connections. + // TODO(mattklein123): In general the way we account for the number of listener connections + // is incredibly fragile. Revisit this by potentially merging ActiveInternalSocket and + // ActiveTcpConnection, having a shared object which does accounting (but would require + // another allocation, etc.). + if (socket_ != nullptr) { + stream_listener_.decNumConnections(); + } + } + + void onTimeout(); + void startTimer(); + void unlink(); + void newConnection(); + bool isListenerFiltersCompleted() { return iter_ == accept_filters_.end(); } + bool isConnected() { return connected_; } + + // Network::ListenerFilterManager + void addAcceptFilter(const Network::ListenerFilterMatcherSharedPtr& listener_filter_matcher, + Network::ListenerFilterPtr&& filter) override { + accept_filters_.emplace_back(std::make_unique( + listener_filter_matcher, std::move(filter))); + } + + // Network::ListenerFilterCallbacks + Network::ConnectionSocket& socket() override { return *socket_.get(); } + Event::Dispatcher& dispatcher() override { return stream_listener_.parent_.dispatcher_; } + void continueFilterChain(bool success) override; + void setDynamicMetadata(const std::string& name, const ProtobufWkt::Struct& value) override; + envoy::config::core::v3::Metadata& dynamicMetadata() override { + return stream_info_->dynamicMetadata(); + }; + const envoy::config::core::v3::Metadata& dynamicMetadata() const override { + return stream_info_->dynamicMetadata(); + }; + + ActiveInternalListener& stream_listener_; + Network::ConnectionSocketPtr socket_; Event::TimerPtr timer_; std::unique_ptr stream_info_; + + private: + std::list accept_filters_; + std::list::iterator iter_; bool connected_{false}; }; From b25f28d8f826b5e44dbf3b1ab5bc364f5cd1cd05 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 17 Sep 2020 10:19:33 +0000 Subject: [PATCH 020/100] adding BufferedIoSocketHandleImpl, start with recv Signed-off-by: Yuchen Dai --- source/common/event/file_event_impl.h | 22 +++ source/common/network/BUILD | 26 +++ .../network/buffered_io_socket_handle_impl.cc | 151 ++++++++++++++++++ .../network/buffered_io_socket_handle_impl.h | 128 +++++++++++++++ source/common/network/io_socket_error_impl.h | 19 +++ .../common/network/io_socket_handle_impl.cc | 90 ----------- source/common/network/io_socket_handle_impl.h | 60 ------- source/common/network/peer_buffer.h | 71 ++++++++ .../common/network/socket_interface_impl.cc | 3 +- .../filters/listener/http_inspector/BUILD | 1 + .../http_inspector/http_inspector_test.cc | 73 +++++++++ 11 files changed, 493 insertions(+), 151 deletions(-) create mode 100644 source/common/network/buffered_io_socket_handle_impl.cc create mode 100644 source/common/network/buffered_io_socket_handle_impl.h create mode 100644 source/common/network/peer_buffer.h diff --git a/source/common/event/file_event_impl.h b/source/common/event/file_event_impl.h index d4562538914e..7a4a6573f00a 100644 --- a/source/common/event/file_event_impl.h +++ b/source/common/event/file_event_impl.h @@ -60,5 +60,27 @@ class TimerWrappedFileEventImpl : public FileEvent { SchedulableCallbackPtr schedulable_; }; +/** + * This file event is a helper event to be always active. It works with BufferedIoSocketHandleImpl + * so that the socket handle will call io methods ASAP and obtain the error code. + */ +class AlwaysActiveFileEventImpl : public FileEvent { +public: + AlwaysActiveFileEventImpl(SchedulableCallbackPtr schedulable) + : schedulable_(std::move(schedulable)) {} + + ~AlwaysActiveFileEventImpl() override { + if (schedulable_->enabled()) { + schedulable_->cancel(); + } + } + // Event::FileEvent + void activate(uint32_t) override { schedulable_->scheduleCallbackNextIteration(); } + void setEnabled(uint32_t) override { schedulable_->scheduleCallbackNextIteration(); } + +private: + SchedulableCallbackPtr schedulable_; +}; + } // namespace Event } // namespace Envoy diff --git a/source/common/network/BUILD b/source/common/network/BUILD index eed6888c77d5..64d13f1bcb42 100644 --- a/source/common/network/BUILD +++ b/source/common/network/BUILD @@ -145,6 +145,7 @@ envoy_cc_library( hdrs = ["io_socket_error_impl.h"], deps = [ "//include/envoy/api:io_error_interface", + "//include/envoy/api:os_sys_calls_interface", "//source/common/common:assert_lib", "//source/common/common:utility_lib", ], @@ -457,3 +458,28 @@ envoy_cc_library( "//source/common/common:macros", ], ) + +envoy_cc_library( + name = "peer_buffer_lib", + srcs = ["peer_buffer.cc"], + hdrs = ["peer_buffer.h"], + deps = [ + ":utility_lib", + "//include/envoy/network:connection_interface", + "//include/envoy/network:transport_socket_interface", + "//source/common/buffer:buffer_lib", + "//source/common/buffer:watermark_buffer_lib", + "//source/common/common:empty_string", + "//source/common/http:headers_lib", + ], +) + +envoy_cc_library( + name = "buffered_io_socket_handle_lib", + srcs = ["buffered_io_socket_handle_impl.cc"], + hdrs = ["buffered_io_socket_handle_impl.h"], + deps = [ + "default_socket_interface_lib", + ":peer_buffer_lib", + ], +) diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc new file mode 100644 index 000000000000..e2c4dc0fe478 --- /dev/null +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -0,0 +1,151 @@ +#include "common/network/buffered_io_socket_handle_impl.h" + +#include "envoy/buffer/buffer.h" +#include "envoy/common/platform.h" + +#include "common/api/os_sys_calls_impl.h" +#include "common/common/assert.h" +#include "common/common/utility.h" +#include "common/event/file_event_impl.h" +#include "common/network/address_impl.h" + +#include "absl/container/fixed_array.h" +#include "absl/types/optional.h" + +namespace Envoy { +namespace Network { + +Api::IoCallUint64Result BufferedIoSocketHandleImpl::close() { + ASSERT(!closed_); + if (!peer_closed_) { + ASSERT(writable_peer_); + // Notify the peer we won't write more data. shutdown(WRITE). + writable_peer_->setWriteEnd(); + // Notify the peer that we no longer accept data. shutdown(RD). + writable_peer_->onPeerDestroy(); + writable_peer_->maybeSetNewData(); + writable_peer_ = nullptr; + peer_closed_ = true; + } + closed_ = true; + return IoSocketError::ioResultSocketInvalidAddress(); +} + +bool BufferedIoSocketHandleImpl::isOpen() const { return !closed_; } + +Api::IoCallUint64Result BufferedIoSocketHandleImpl::readv(uint64_t, Buffer::RawSlice*, uint64_t) { + return IoSocketError::ioResultSocketInvalidAddress(); +} + +Api::IoCallUint64Result BufferedIoSocketHandleImpl::writev(const Buffer::RawSlice*, uint64_t) { + return IoSocketError::ioResultSocketInvalidAddress(); +} + +Api::IoCallUint64Result BufferedIoSocketHandleImpl::sendmsg(const Buffer::RawSlice*, uint64_t, int, + const Address::Ip*, + const Address::Instance&) { + return IoSocketError::ioResultSocketInvalidAddress(); +} + +Api::IoCallUint64Result BufferedIoSocketHandleImpl::recvmsg(Buffer::RawSlice*, const uint64_t, + uint32_t, RecvMsgOutput&) { + return IoSocketError::ioResultSocketInvalidAddress(); +} + +Api::IoCallUint64Result BufferedIoSocketHandleImpl::recvmmsg(RawSliceArrays&, uint32_t, + RecvMsgOutput&) { + return IoSocketError::ioResultSocketInvalidAddress(); +} + +Api::IoCallUint64Result BufferedIoSocketHandleImpl::recv(void* buffer, size_t length, int flags) { + if (flags | MSG_PEEK) { + // No data and the writer closed. + if (owned_buffer_.length() == 0) { + + if (read_end_stream_) { + return sysCallResultToIoCallResult(Api::SysCallSizeResult{-1, SOCKET_ERROR_INTR}); + } else { + return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), + IoSocketError::deleteIoError)}; + } + } else { + auto min_len = std::min(owned_buffer_.length(), length); + owned_buffer_.copyOut(0, min_len, buffer); + return {min_len, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; + } + } else { + // TODO(lambdai): implement non-PEEK for proxy_protocol listener filter. + return IoSocketError::ioResultSocketInvalidAddress(); + } +} + +bool BufferedIoSocketHandleImpl::supportsMmsg() const { return false; } + +bool BufferedIoSocketHandleImpl::supportsUdpGro() const { return false; } + +Api::SysCallIntResult makeInvalidSyscall() { + return Api::SysCallIntResult{-1, SOCKET_ERROR_NOT_SUP /*SOCKET_ERROR_NOT_SUP*/}; +} + +Api::SysCallIntResult BufferedIoSocketHandleImpl::bind(Address::InstanceConstSharedPtr) { + return makeInvalidSyscall(); +} + +Api::SysCallIntResult BufferedIoSocketHandleImpl::listen(int) { return makeInvalidSyscall(); } + +IoHandlePtr BufferedIoSocketHandleImpl::accept(struct sockaddr*, socklen_t*) { + + NOT_IMPLEMENTED_GCOVR_EXCL_LINE; +} + +Api::SysCallIntResult BufferedIoSocketHandleImpl::connect(Address::InstanceConstSharedPtr) { + return makeInvalidSyscall(); +} + +Api::SysCallIntResult BufferedIoSocketHandleImpl::setOption(int, int, const void*, socklen_t) { + return makeInvalidSyscall(); +} + +Api::SysCallIntResult BufferedIoSocketHandleImpl::getOption(int, int, void*, socklen_t*) { + return makeInvalidSyscall(); +} + +Api::SysCallIntResult BufferedIoSocketHandleImpl::setBlocking(bool) { return makeInvalidSyscall(); } + +absl::optional BufferedIoSocketHandleImpl::domain() { return absl::nullopt; } + +Address::InstanceConstSharedPtr BufferedIoSocketHandleImpl::localAddress() { + throw EnvoyException(fmt::format("getsockname failed for BufferedIoSocketHandleImpl")); +} + +Address::InstanceConstSharedPtr BufferedIoSocketHandleImpl::peerAddress() { + + throw EnvoyException(fmt::format("getsockname failed for BufferedIoSocketHandleImpl")); +} + +Event::FileEventPtr BufferedIoSocketHandleImpl::createFileEvent(Event::Dispatcher& dispatcher, + Event::FileReadyCb cb, + Event::FileTriggerType, + uint32_t events) { + return std::make_unique( + dispatcher.createSchedulableCallback([cb, events]() -> void { cb(events); })); +} + +Api::SysCallIntResult BufferedIoSocketHandleImpl::shutdown(int how) { + if ((how | ENVOY_SHUT_WR) || (how | ENVOY_SHUT_RDWR)) { + ASSERT(!closed_); + if (!peer_closed_) { + ASSERT(writable_peer_); + // Notify the peer we won't write more data. shutdown(WRITE). + writable_peer_->setWriteEnd(); + writable_peer_->maybeSetNewData(); + writable_peer_ = nullptr; + peer_closed_ = true; + } + } + // TODO(lambdai): return correct error code. + return {0, 0}; +} + +} // namespace Network +} // namespace Envoy \ No newline at end of file diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/common/network/buffered_io_socket_handle_impl.h new file mode 100644 index 000000000000..390fe90480b6 --- /dev/null +++ b/source/common/network/buffered_io_socket_handle_impl.h @@ -0,0 +1,128 @@ +#pragma once + +#include "envoy/api/io_error.h" +#include "envoy/api/os_sys_calls.h" +#include "envoy/common/platform.h" +#include "envoy/event/dispatcher.h" +#include "envoy/network/io_handle.h" + +#include "common/buffer/watermark_buffer.h" +#include "common/common/logger.h" +#include "common/network/io_socket_error_impl.h" +#include "common/network/peer_buffer.h" + +namespace Envoy { +namespace Network { + +/** + * IoHandle implementation which provides a buffer as data source. + */ +class BufferedIoSocketHandleImpl : public IoHandle, + public WritablePeer, + public ReadableSource, + protected Logger::Loggable { +public: + BufferedIoSocketHandleImpl() + : closed_{false}, owned_buffer_( + [this]() -> void { + over_high_watermark_ = false; + triggered_high_to_low_watermark_ = true; + }, + [this]() -> void { over_high_watermark_ = true; }, []() -> void {}) {} + + ~BufferedIoSocketHandleImpl() override { ASSERT(closed_); } + + // IoHandle + os_fd_t fdDoNotUse() const override { return INVALID_SOCKET; } + + Api::IoCallUint64Result close() override; + + bool isOpen() const override; + + Api::IoCallUint64Result readv(uint64_t max_length, Buffer::RawSlice* slices, + uint64_t num_slice) override; + + Api::IoCallUint64Result writev(const Buffer::RawSlice* slices, uint64_t num_slice) override; + + Api::IoCallUint64Result sendmsg(const Buffer::RawSlice* slices, uint64_t num_slice, int flags, + const Address::Ip* self_ip, + const Address::Instance& peer_address) override; + + Api::IoCallUint64Result recvmsg(Buffer::RawSlice* slices, const uint64_t num_slice, + uint32_t self_port, RecvMsgOutput& output) override; + + Api::IoCallUint64Result recvmmsg(RawSliceArrays& slices, uint32_t self_port, + RecvMsgOutput& output) override; + Api::IoCallUint64Result recv(void* buffer, size_t length, int flags) override; + + bool supportsMmsg() const override; + bool supportsUdpGro() const override; + + Api::SysCallIntResult bind(Address::InstanceConstSharedPtr address) override; + Api::SysCallIntResult listen(int backlog) override; + IoHandlePtr accept(struct sockaddr* addr, socklen_t* addrlen) override; + Api::SysCallIntResult connect(Address::InstanceConstSharedPtr address) override; + Api::SysCallIntResult setOption(int level, int optname, const void* optval, + socklen_t optlen) override; + Api::SysCallIntResult getOption(int level, int optname, void* optval, socklen_t* optlen) override; + Api::SysCallIntResult setBlocking(bool blocking) override; + absl::optional domain() override; + Address::InstanceConstSharedPtr localAddress() override; + Address::InstanceConstSharedPtr peerAddress() override; + Event::FileEventPtr createFileEvent(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, + Event::FileTriggerType trigger, uint32_t events) override; + Api::SysCallIntResult shutdown(int how) override; + + Buffer::WatermarkBuffer& getBufferForTest() { return owned_buffer_; } + void scheduleWriteEvent() {} + void scheduleNextEvent() {} + + void setWritablePeer(WritablePeer* writable_peer) { + // Swapping writable peer is undefined behavior. + ASSERT(!writable_peer_); + ASSERT(!peer_closed_); + writable_peer_ = writable_peer; + } + + // WritablePeer + void setWriteEnd() override { read_end_stream_ = true; } + void maybeSetNewData() override { + if (last_read_to_empty_) { + last_read_to_empty_ = false; + scheduleWriteEvent(); + scheduleNextEvent(); + } + } + void onPeerDestroy() override { + writable_peer_ = nullptr; + peer_closed_ = true; + } + Buffer::Instance* getWriteBuffer() override { return &owned_buffer_; } + // ReadableSource + bool isPeerShutDownWrite() const override { return read_end_stream_; } + bool isOverHighWatermark() const override { return over_high_watermark_; } + bool isReadable() const override { return isPeerShutDownWrite() || owned_buffer_.length() > 0; } + +private: + // Support isOpen() and close(). IoHandle owner must invoke close() to avoid potential resource + // leak. + bool closed_; + // Drained to empty. The following write should switch the state to false. + bool last_read_to_empty_{true}; + // True if owned_buffer_ is not addable. Note that owned_buffer_ may have pending data to drain. + bool read_end_stream_{false}; + Buffer::WatermarkBuffer owned_buffer_; + + // bool shutdown_{false}; + // Destination of the write(). + WritablePeer* writable_peer_{nullptr}; + + // The flag whether the peer is valid. Any write attempt should check flag. + bool peer_closed_{false}; + + bool over_high_watermark_{false}; + bool triggered_high_to_low_watermark_{true}; +}; + +} // namespace Network +} // namespace Envoy \ No newline at end of file diff --git a/source/common/network/io_socket_error_impl.h b/source/common/network/io_socket_error_impl.h index 50d08b55f26a..b98d51f1caf3 100644 --- a/source/common/network/io_socket_error_impl.h +++ b/source/common/network/io_socket_error_impl.h @@ -1,6 +1,7 @@ #pragma once #include "envoy/api/io_error.h" +#include "envoy/api/os_sys_calls_common.h" #include "common/common/assert.h" @@ -33,5 +34,23 @@ class IoSocketError : public Api::IoError { int errno_; }; +// Converts a SysCallSizeResult to IoCallUint64Result. +template +Api::IoCallUint64Result sysCallResultToIoCallResult(const Api::SysCallResult& result) { + if (result.rc_ >= 0) { + // Return nullptr as IoError upon success. + return Api::IoCallUint64Result(result.rc_, + Api::IoErrorPtr(nullptr, IoSocketError::deleteIoError)); + } + RELEASE_ASSERT(result.errno_ != SOCKET_ERROR_INVAL, "Invalid argument passed in."); + return Api::IoCallUint64Result( + /*rc=*/0, + (result.errno_ == SOCKET_ERROR_AGAIN + // EAGAIN is frequent enough that its memory allocation should be avoided. + ? Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), + IoSocketError::deleteIoError) + : Api::IoErrorPtr(new IoSocketError(result.errno_), IoSocketError::deleteIoError))); +} + } // namespace Network } // namespace Envoy diff --git a/source/common/network/io_socket_handle_impl.cc b/source/common/network/io_socket_handle_impl.cc index 3e84da7c639e..a3d1e5f7a7e0 100644 --- a/source/common/network/io_socket_handle_impl.cc +++ b/source/common/network/io_socket_handle_impl.cc @@ -489,95 +489,5 @@ Event::FileEventPtr IoSocketHandleImpl::createFileEvent(Event::Dispatcher& dispa Api::SysCallIntResult IoSocketHandleImpl::shutdown(int how) { return Api::OsSysCallsSingleton::get().shutdown(fd_, how); } - -Api::IoCallUint64Result NullIoSocketHandleImpl::close() { - closed_ = true; - return IoSocketError::ioResultSocketInvalidAddress(); -} - -bool NullIoSocketHandleImpl::isOpen() const { return !closed_; } - -Api::IoCallUint64Result NullIoSocketHandleImpl::readv(uint64_t, Buffer::RawSlice*, uint64_t) { - return IoSocketError::ioResultSocketInvalidAddress(); -} - -Api::IoCallUint64Result NullIoSocketHandleImpl::writev(const Buffer::RawSlice*, uint64_t) { - return IoSocketError::ioResultSocketInvalidAddress(); -} - -Api::IoCallUint64Result NullIoSocketHandleImpl::sendmsg(const Buffer::RawSlice*, uint64_t, int, - const Address::Ip*, - const Address::Instance&) { - return IoSocketError::ioResultSocketInvalidAddress(); -} - -Api::IoCallUint64Result NullIoSocketHandleImpl::recvmsg(Buffer::RawSlice*, const uint64_t, uint32_t, - RecvMsgOutput&) { - return IoSocketError::ioResultSocketInvalidAddress(); -} - -Api::IoCallUint64Result NullIoSocketHandleImpl::recvmmsg(RawSliceArrays&, uint32_t, - RecvMsgOutput&) { - return IoSocketError::ioResultSocketInvalidAddress(); -} - -Api::IoCallUint64Result NullIoSocketHandleImpl::recv(void*, size_t, int) { - return IoSocketError::ioResultSocketInvalidAddress(); -} - -bool NullIoSocketHandleImpl::supportsMmsg() const { return false; } - -bool NullIoSocketHandleImpl::supportsUdpGro() const { return false; } - -Api::SysCallIntResult makeInvalidSyscall() { - return Api::SysCallIntResult{-1, SOCKET_ERROR_NOT_SUP /*SOCKET_ERROR_NOT_SUP*/}; -} - -Api::SysCallIntResult NullIoSocketHandleImpl::bind(Address::InstanceConstSharedPtr) { - return makeInvalidSyscall(); -} - -Api::SysCallIntResult NullIoSocketHandleImpl::listen(int) { return makeInvalidSyscall(); } - -IoHandlePtr NullIoSocketHandleImpl::accept(struct sockaddr*, socklen_t*) { - - return std::make_unique(); -} - -Api::SysCallIntResult NullIoSocketHandleImpl::connect(Address::InstanceConstSharedPtr) { - return makeInvalidSyscall(); -} - -Api::SysCallIntResult NullIoSocketHandleImpl::setOption(int, int, const void*, socklen_t) { - return makeInvalidSyscall(); -} - -Api::SysCallIntResult NullIoSocketHandleImpl::getOption(int, int, void*, socklen_t*) { - return makeInvalidSyscall(); -} - -Api::SysCallIntResult NullIoSocketHandleImpl::setBlocking(bool) { return makeInvalidSyscall(); } - -absl::optional NullIoSocketHandleImpl::domain() { return absl::nullopt; } - -Address::InstanceConstSharedPtr NullIoSocketHandleImpl::localAddress() { - throw EnvoyException(fmt::format("getsockname failed for NullIoSocketHandleImpl")); -} - -Address::InstanceConstSharedPtr NullIoSocketHandleImpl::peerAddress() { - - throw EnvoyException(fmt::format("getsockname failed for NullIoSocketHandleImpl")); -} - -Event::FileEventPtr NullIoSocketHandleImpl::createFileEvent(Event::Dispatcher& dispatcher, - Event::FileReadyCb cb, - Event::FileTriggerType, - uint32_t events) { - return std::make_unique( - dispatcher.createSchedulableCallback([cb, events]() -> void { cb(events); })); -} - -Api::SysCallIntResult NullIoSocketHandleImpl::shutdown(int) { return makeInvalidSyscall(); } - } // namespace Network } // namespace Envoy diff --git a/source/common/network/io_socket_handle_impl.h b/source/common/network/io_socket_handle_impl.h index cf7fd5da9d15..6973b2707393 100644 --- a/source/common/network/io_socket_handle_impl.h +++ b/source/common/network/io_socket_handle_impl.h @@ -92,65 +92,5 @@ class IoSocketHandleImpl : public IoHandle, protected Logger::Loggable { -public: - NullIoSocketHandleImpl() : closed_{false} { - ENVOY_LOG(debug, - "creating socket to invalid address. Please update envoy to support this address."); - } - - ~NullIoSocketHandleImpl() override { ASSERT(closed_); } - - os_fd_t fdDoNotUse() const override { return INVALID_SOCKET; } - - Api::IoCallUint64Result close() override; - - bool isOpen() const override; - - Api::IoCallUint64Result readv(uint64_t max_length, Buffer::RawSlice* slices, - uint64_t num_slice) override; - - Api::IoCallUint64Result writev(const Buffer::RawSlice* slices, uint64_t num_slice) override; - - Api::IoCallUint64Result sendmsg(const Buffer::RawSlice* slices, uint64_t num_slice, int flags, - const Address::Ip* self_ip, - const Address::Instance& peer_address) override; - - Api::IoCallUint64Result recvmsg(Buffer::RawSlice* slices, const uint64_t num_slice, - uint32_t self_port, RecvMsgOutput& output) override; - - Api::IoCallUint64Result recvmmsg(RawSliceArrays& slices, uint32_t self_port, - RecvMsgOutput& output) override; - Api::IoCallUint64Result recv(void* buffer, size_t length, int flags) override; - - bool supportsMmsg() const override; - bool supportsUdpGro() const override; - - Api::SysCallIntResult bind(Address::InstanceConstSharedPtr address) override; - Api::SysCallIntResult listen(int backlog) override; - IoHandlePtr accept(struct sockaddr* addr, socklen_t* addrlen) override; - Api::SysCallIntResult connect(Address::InstanceConstSharedPtr address) override; - Api::SysCallIntResult setOption(int level, int optname, const void* optval, - socklen_t optlen) override; - Api::SysCallIntResult getOption(int level, int optname, void* optval, socklen_t* optlen) override; - Api::SysCallIntResult setBlocking(bool blocking) override; - absl::optional domain() override; - Address::InstanceConstSharedPtr localAddress() override; - Address::InstanceConstSharedPtr peerAddress() override; - Event::FileEventPtr createFileEvent(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, - Event::FileTriggerType trigger, uint32_t events) override; - Api::SysCallIntResult shutdown(int how) override; - -private: - // Support isOpen() and close(). IoHandle owner must invoke close() to avoid potential resource - // leak. - bool closed_; -}; - } // namespace Network } // namespace Envoy diff --git a/source/common/network/peer_buffer.h b/source/common/network/peer_buffer.h new file mode 100644 index 000000000000..b314c13d575f --- /dev/null +++ b/source/common/network/peer_buffer.h @@ -0,0 +1,71 @@ +#include + +#include "envoy/buffer/buffer.h" +#include "envoy/common/pure.h" +#include "envoy/network/io_handle.h" +#include "envoy/network/proxy_protocol.h" +#include "envoy/ssl/connection.h" + +#include "common/common/assert.h" +#include "common/common/logger.h" + +#include "absl/types/optional.h" + +namespace Envoy { +namespace Network { + +/** + * The interface for the writer. + */ +class WritablePeer { +public: + virtual ~WritablePeer() = default; + + /** + * Set the flag to indicate no further write from peer. + */ + virtual void setWriteEnd() PURE; + + /** + * Raised when peer is destroyed. No further write to peer is allowed. + */ + virtual void onPeerDestroy() PURE; + + /** + * Notify that consumable data arrives. The consumable data can be either data to read, or the end + * of stream event. + */ + virtual void maybeSetNewData() PURE; + + /** + * @return the buffer to be written. + */ + virtual Buffer::Instance* getWriteBuffer() PURE; + + /** + * @return false more data is acceptable. + */ + virtual bool isOverHighWatermark() const PURE; + + // virtual bool triggeredHighToLowWatermark() const PURE; + // virtual void clearTriggeredHighToLowWatermark() PURE; + // virtual void setTriggeredHighToLowWatermark() PURE; +}; + +/** + * The interface for the buffer owner who want to consume the buffer. + */ +class ReadableSource { +public: + virtual ~ReadableSource() = default; + + /** + * Read the flag to indicate no further write. Used by early close detection. + */ + virtual bool isPeerShutDownWrite() const PURE; + + virtual bool isOverHighWatermark() const PURE; + virtual bool isReadable() const PURE; +}; +} // namespace Network +} // namespace Envoy \ No newline at end of file diff --git a/source/common/network/socket_interface_impl.cc b/source/common/network/socket_interface_impl.cc index 1d631061f1d8..f00817e46bf9 100644 --- a/source/common/network/socket_interface_impl.cc +++ b/source/common/network/socket_interface_impl.cc @@ -4,6 +4,7 @@ #include "envoy/extensions/network/socket_interface/v3/default_socket_interface.pb.h" #include "common/api/os_sys_calls_impl.h" +#include "common/common/assert.h" #include "common/common/utility.h" #include "common/network/io_socket_handle_impl.h" @@ -40,7 +41,7 @@ IoHandlePtr SocketInterfaceImpl::socket(Socket::Type socket_type, Address::Type domain = AF_UNIX; } else { ASSERT(addr_type == Address::Type::EnvoyInternal); - return std::make_unique(); + NOT_REACHED_GCOVR_EXCL_LINE; } const Api::SysCallSocketResult result = Api::OsSysCallsSingleton::get().socket(domain, flags, 0); diff --git a/test/extensions/filters/listener/http_inspector/BUILD b/test/extensions/filters/listener/http_inspector/BUILD index 4fbabc8c1c71..ef3c15225a92 100644 --- a/test/extensions/filters/listener/http_inspector/BUILD +++ b/test/extensions/filters/listener/http_inspector/BUILD @@ -23,6 +23,7 @@ envoy_extension_cc_test( deps = [ "//source/common/common:hex_lib", "//source/common/http:utility_lib", + "//source/common/network:buffered_io_socket_handle_lib", "//source/extensions/filters/listener/http_inspector:http_inspector_lib", "//test/mocks/api:api_mocks", "//test/mocks/network:network_mocks", diff --git a/test/extensions/filters/listener/http_inspector/http_inspector_test.cc b/test/extensions/filters/listener/http_inspector/http_inspector_test.cc index 713c2aa6902d..8bf668fab269 100644 --- a/test/extensions/filters/listener/http_inspector/http_inspector_test.cc +++ b/test/extensions/filters/listener/http_inspector/http_inspector_test.cc @@ -1,5 +1,8 @@ +#include + #include "common/common/hex.h" #include "common/http/utility.h" +#include "common/network/buffered_io_socket_handle_impl.h" #include "common/network/io_socket_handle_impl.h" #include "extensions/filters/listener/http_inspector/http_inspector.h" @@ -654,6 +657,76 @@ TEST_F(HttpInspectorTest, Http1WithLargeHeader) { EXPECT_EQ(1, cfg_->stats().http10_found_.value()); } +class HttpInspectorTestWithBufferIoSocket : public testing::Test { +public: + HttpInspectorTestWithBufferIoSocket() : cfg_(std::make_shared(store_)) { + io_handle_ = std::make_unique(); + io_handle_peer_ = std::make_unique(); + io_handle_->setWritablePeer(io_handle_peer_.get()); + io_handle_peer_->setWritablePeer(io_handle_.get()); + } + ~HttpInspectorTestWithBufferIoSocket() override { + io_handle_->close(); + io_handle_peer_->close(); + } + + absl::optional init(bool include_inline_recv = true) { + filter_ = std::make_unique(cfg_); + + EXPECT_CALL(cb_, socket()).WillRepeatedly(ReturnRef(socket_)); + EXPECT_CALL(socket_, detectedTransportProtocol()).WillRepeatedly(Return("raw_buffer")); + EXPECT_CALL(cb_, dispatcher()).WillRepeatedly(ReturnRef(dispatcher_)); + EXPECT_CALL(testing::Const(socket_), ioHandle()).WillRepeatedly(ReturnRef(*io_handle_)); + EXPECT_CALL(socket_, ioHandle()).WillRepeatedly(ReturnRef(*io_handle_)); + + if (include_inline_recv) { + // EXPECT_CALL(dispatcher_, + // createFileEvent_(_, _, Event::PlatformDefaultTriggerType, + // Event::FileReadyType::Read | Event::FileReadyType::Closed)) + // .WillOnce(DoAll(SaveArg<1>(&file_event_callback_), + // ReturnNew>())); + + return filter_->onAccept(cb_); + } + return std::nullopt; + } + + Stats::IsolatedStoreImpl store_; + ConfigSharedPtr cfg_; + std::unique_ptr filter_; + Network::MockListenerFilterCallbacks cb_; + Network::MockConnectionSocket socket_; + NiceMock dispatcher_; + Event::FileReadyCb file_event_callback_; + std::unique_ptr io_handle_; + std::unique_ptr io_handle_peer_; +}; + +// Verify peek behavior of BufferedIoSocketHandleImpl. +TEST_F(HttpInspectorTestWithBufferIoSocket, InlineRecv) { + const absl::string_view header = + "GET /anything HTTP/1.0\r\nhost: google.com\r\nuser-agent: curl/7.64.0\r\naccept: " + "*/*\r\nx-forwarded-proto: http\r\nx-request-id: " + "a52df4a0-ed00-4a19-86a7-80e5049c6c84\r\nx-envoy-expected-rq-timeout-ms: " + "15000\r\ncontent-length: 0\r\n\r\n"; + + io_handle_->getBufferForTest().add(header); + const std::vector alpn_protos{Http::Utility::AlpnNames::get().Http10}; + EXPECT_CALL(socket_, setRequestedApplicationProtocols(alpn_protos)); + + EXPECT_EQ(Network::FilterStatus::Continue, init(true)); + EXPECT_EQ(1, cfg_->stats().http10_found_.value()); +} + +// Verify createFileEvent of BufferedIoSocketHandleImpl. +TEST_F(HttpInspectorTestWithBufferIoSocket, InlineRecvAndScheduleEvent) { +} + +// Verify sending data from peer socket triggers read event. +TEST_F(HttpInspectorTestWithBufferIoSocket, InlineRecvAndSendByPeer) { +} + + } // namespace } // namespace HttpInspector } // namespace ListenerFilters From 73c50744ba56ef22ff87ad32b3ee4fa1b5e87d85 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 17 Sep 2020 10:25:48 +0000 Subject: [PATCH 021/100] format Signed-off-by: Yuchen Dai --- source/common/network/BUILD | 1 - .../listener/http_inspector/http_inspector_test.cc | 9 +++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/source/common/network/BUILD b/source/common/network/BUILD index 64d13f1bcb42..cedbc5075d77 100644 --- a/source/common/network/BUILD +++ b/source/common/network/BUILD @@ -461,7 +461,6 @@ envoy_cc_library( envoy_cc_library( name = "peer_buffer_lib", - srcs = ["peer_buffer.cc"], hdrs = ["peer_buffer.h"], deps = [ ":utility_lib", diff --git a/test/extensions/filters/listener/http_inspector/http_inspector_test.cc b/test/extensions/filters/listener/http_inspector/http_inspector_test.cc index 8bf668fab269..3ada50da6a00 100644 --- a/test/extensions/filters/listener/http_inspector/http_inspector_test.cc +++ b/test/extensions/filters/listener/http_inspector/http_inspector_test.cc @@ -713,19 +713,16 @@ TEST_F(HttpInspectorTestWithBufferIoSocket, InlineRecv) { io_handle_->getBufferForTest().add(header); const std::vector alpn_protos{Http::Utility::AlpnNames::get().Http10}; EXPECT_CALL(socket_, setRequestedApplicationProtocols(alpn_protos)); - + EXPECT_EQ(Network::FilterStatus::Continue, init(true)); EXPECT_EQ(1, cfg_->stats().http10_found_.value()); } // Verify createFileEvent of BufferedIoSocketHandleImpl. -TEST_F(HttpInspectorTestWithBufferIoSocket, InlineRecvAndScheduleEvent) { -} +TEST_F(HttpInspectorTestWithBufferIoSocket, InlineRecvAndScheduleEvent) {} // Verify sending data from peer socket triggers read event. -TEST_F(HttpInspectorTestWithBufferIoSocket, InlineRecvAndSendByPeer) { -} - +TEST_F(HttpInspectorTestWithBufferIoSocket, InlineRecvAndSendByPeer) {} } // namespace } // namespace HttpInspector From 8439a67ad9e5fbcec82580dd80df78c076c94109 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Mon, 21 Sep 2020 09:10:02 +0000 Subject: [PATCH 022/100] add buffered_io_socket_handle_test Signed-off-by: Yuchen Dai --- .../network/buffered_io_socket_handle_impl.cc | 27 ++--- .../network/buffered_io_socket_handle_impl.h | 9 +- test/common/network/BUILD | 10 ++ .../buffered_io_socket_handle_impl_test.cc | 104 ++++++++++++++++++ 4 files changed, 128 insertions(+), 22 deletions(-) create mode 100644 test/common/network/buffered_io_socket_handle_impl_test.cc diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc index e2c4dc0fe478..e3bd34854c11 100644 --- a/source/common/network/buffered_io_socket_handle_impl.cc +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -58,24 +58,21 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::recvmmsg(RawSliceArrays&, ui } Api::IoCallUint64Result BufferedIoSocketHandleImpl::recv(void* buffer, size_t length, int flags) { - if (flags | MSG_PEEK) { - // No data and the writer closed. - if (owned_buffer_.length() == 0) { - - if (read_end_stream_) { - return sysCallResultToIoCallResult(Api::SysCallSizeResult{-1, SOCKET_ERROR_INTR}); - } else { - return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), - IoSocketError::deleteIoError)}; - } + // No data and the writer closed. + if (owned_buffer_.length() == 0) { + if (read_end_stream_) { + return sysCallResultToIoCallResult(Api::SysCallSizeResult{-1, SOCKET_ERROR_INTR}); } else { - auto min_len = std::min(owned_buffer_.length(), length); - owned_buffer_.copyOut(0, min_len, buffer); - return {min_len, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; + return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), + IoSocketError::deleteIoError)}; } } else { - // TODO(lambdai): implement non-PEEK for proxy_protocol listener filter. - return IoSocketError::ioResultSocketInvalidAddress(); + auto min_len = std::min(owned_buffer_.length(), length); + owned_buffer_.copyOut(0, min_len, buffer); + if (!(flags & MSG_PEEK)) { + owned_buffer_.drain(min_len); + } + return {min_len, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } } diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/common/network/buffered_io_socket_handle_impl.h index 390fe90480b6..3b65f362b5ad 100644 --- a/source/common/network/buffered_io_socket_handle_impl.h +++ b/source/common/network/buffered_io_socket_handle_impl.h @@ -87,11 +87,8 @@ class BufferedIoSocketHandleImpl : public IoHandle, // WritablePeer void setWriteEnd() override { read_end_stream_ = true; } void maybeSetNewData() override { - if (last_read_to_empty_) { - last_read_to_empty_ = false; - scheduleWriteEvent(); - scheduleNextEvent(); - } + scheduleWriteEvent(); + scheduleNextEvent(); } void onPeerDestroy() override { writable_peer_ = nullptr; @@ -107,8 +104,6 @@ class BufferedIoSocketHandleImpl : public IoHandle, // Support isOpen() and close(). IoHandle owner must invoke close() to avoid potential resource // leak. bool closed_; - // Drained to empty. The following write should switch the state to false. - bool last_read_to_empty_{true}; // True if owned_buffer_ is not addable. Note that owned_buffer_ may have pending data to drain. bool read_end_stream_{false}; Buffer::WatermarkBuffer owned_buffer_; diff --git a/test/common/network/BUILD b/test/common/network/BUILD index 31b558b10c50..08aa3bb3774d 100644 --- a/test/common/network/BUILD +++ b/test/common/network/BUILD @@ -380,6 +380,16 @@ envoy_cc_test( ], ) +envoy_cc_test( + name = "buffered_io_socket_handle_impl_test", + srcs = ["buffered_io_socket_handle_impl_test.cc"], + deps = [ + "//source/common/common:utility_lib", + "//source/common/network:address_lib", + "//source/common/network:buffered_io_socket_handle_lib", + ], +) + envoy_cc_test( name = "transport_socket_options_impl_test", srcs = ["transport_socket_options_impl_test.cc"], diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc new file mode 100644 index 000000000000..eb762409b814 --- /dev/null +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -0,0 +1,104 @@ +#include "common/network/buffered_io_socket_handle_impl.h" + +#include "absl/container/fixed_array.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include + +using testing::_; +using testing::InSequence; +using testing::Invoke; +using testing::NiceMock; +using testing::Return; +using testing::WithArgs; + +namespace Envoy { +namespace Network { +namespace { + +class BufferedIoSocketHandleTest : public testing::Test { +public: + BufferedIoSocketHandleTest() : buf_(1024) { + io_handle_ = std::make_unique(); + io_handle_peer_ = std::make_unique(); + io_handle_->setWritablePeer(io_handle_peer_.get()); + io_handle_peer_->setWritablePeer(io_handle_.get()); + } + ~BufferedIoSocketHandleTest() override { + io_handle_->close(); + io_handle_peer_->close(); + } + void expectAgain() { + auto res = io_handle_->recv(buf_.data(), buf_.size(), MSG_PEEK); + EXPECT_FALSE(res.ok()); + EXPECT_EQ(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); + } + std::unique_ptr io_handle_; + std::unique_ptr io_handle_peer_; + absl::FixedArray buf_; +}; + +// Test recv side effects. +TEST_F(BufferedIoSocketHandleTest, TestBasicRecv) { + auto res = io_handle_->recv(buf_.data(), buf_.size(), 0); + // EAGAIN. + EXPECT_FALSE(res.ok()); + EXPECT_EQ(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); + io_handle_->setWriteEnd(); + res = io_handle_->recv(buf_.data(), buf_.size(), 0); + EXPECT_FALSE(res.ok()); + EXPECT_NE(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); +} + +// Test recv side effects. +TEST_F(BufferedIoSocketHandleTest, TestBasicPeek) { + auto res = io_handle_->recv(buf_.data(), buf_.size(), MSG_PEEK); + // EAGAIN. + EXPECT_FALSE(res.ok()); + EXPECT_EQ(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); + io_handle_->setWriteEnd(); + res = io_handle_->recv(buf_.data(), buf_.size(), MSG_PEEK); + EXPECT_FALSE(res.ok()); + EXPECT_NE(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); +} + +TEST_F(BufferedIoSocketHandleTest, TestRecvDrain) { + auto& internal_buffer = io_handle_->getBufferForTest(); + internal_buffer.add("abcd"); + auto res = io_handle_->recv(buf_.data(), buf_.size(), 0); + EXPECT_TRUE(res.ok()); + EXPECT_EQ(4, res.rc_); + EXPECT_EQ(absl::string_view(buf_.data(), 4), "abcd"); + EXPECT_EQ(0, internal_buffer.length()); + expectAgain(); +} + +// This test fixture test that io handle is impacted by peer. +class BufferedIoSocketHandlePeerTest : public testing::Test { +public: + BufferedIoSocketHandlePeerTest() : buf_(1024) { + io_handle_ = std::make_unique(); + io_handle_peer_ = std::make_unique(); + io_handle_->setWritablePeer(io_handle_peer_.get()); + io_handle_peer_->setWritablePeer(io_handle_.get()); + } + ~BufferedIoSocketHandlePeerTest() override { + io_handle_->close(); + io_handle_peer_->close(); + } + void expectAgain() { + auto res = io_handle_->recv(buf_.data(), buf_.size(), MSG_PEEK); + EXPECT_FALSE(res.ok()); + EXPECT_EQ(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); + } + std::unique_ptr io_handle_; + std::unique_ptr io_handle_peer_; + absl::FixedArray buf_; +}; + +TEST_F(BufferedIoSocketHandlePeerTest, TestRecvDrain) {} + +} // namespace +} // namespace Network +} // namespace Envoy \ No newline at end of file From d7cff5cc620a88c4272a3b1791fb30c8d3bb1fe4 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Mon, 21 Sep 2020 19:32:55 +0000 Subject: [PATCH 023/100] add flow control test Signed-off-by: Yuchen Dai --- .../network/buffered_io_socket_handle_impl.h | 3 ++ source/common/network/peer_buffer.h | 2 +- .../buffered_io_socket_handle_impl_test.cc | 39 ++++++++++++++++++- 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/common/network/buffered_io_socket_handle_impl.h index 3b65f362b5ad..7dc31e2ac937 100644 --- a/source/common/network/buffered_io_socket_handle_impl.h +++ b/source/common/network/buffered_io_socket_handle_impl.h @@ -94,6 +94,9 @@ class BufferedIoSocketHandleImpl : public IoHandle, writable_peer_ = nullptr; peer_closed_ = true; } + bool isWritable() const override { + return !isOverHighWatermark(); + } Buffer::Instance* getWriteBuffer() override { return &owned_buffer_; } // ReadableSource bool isPeerShutDownWrite() const override { return read_end_stream_; } diff --git a/source/common/network/peer_buffer.h b/source/common/network/peer_buffer.h index b314c13d575f..fc09f577ffd6 100644 --- a/source/common/network/peer_buffer.h +++ b/source/common/network/peer_buffer.h @@ -45,7 +45,7 @@ class WritablePeer { /** * @return false more data is acceptable. */ - virtual bool isOverHighWatermark() const PURE; + virtual bool isWritable() const PURE; // virtual bool triggeredHighToLowWatermark() const PURE; // virtual void clearTriggeredHighToLowWatermark() PURE; diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index eb762409b814..4c28f79c4427 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -1,10 +1,10 @@ +#include + #include "common/network/buffered_io_socket_handle_impl.h" #include "absl/container/fixed_array.h" - #include "gmock/gmock.h" #include "gtest/gtest.h" -#include using testing::_; using testing::InSequence; @@ -74,6 +74,41 @@ TEST_F(BufferedIoSocketHandleTest, TestRecvDrain) { expectAgain(); } +TEST_F(BufferedIoSocketHandleTest, FlowControl) { + auto& internal_buffer = io_handle_->getBufferForTest(); + WritablePeer* handle_as_peer = io_handle_.get(); + internal_buffer.setWatermarks(128); + EXPECT_FALSE(io_handle_->isReadable()); + EXPECT_TRUE(io_handle_peer_->isWritable()); + + std::string big_chunk(256, 'a'); + internal_buffer.add(big_chunk); + EXPECT_TRUE(io_handle_->isReadable()); + EXPECT_FALSE(handle_as_peer->isWritable()); + + bool writable_flipped = false; + // During the repeated recv, the writable flag must switch to true. + while (internal_buffer.length() > 0) { + SCOPED_TRACE(internal_buffer.length()); + EXPECT_TRUE(io_handle_->isReadable()); + bool writable = handle_as_peer->isWritable(); + if (writable) { + writable_flipped = true; + } else { + ASSERT_FALSE(writable_flipped); + } + auto res = io_handle_->recv(buf_.data(), 32, 0); + EXPECT_TRUE(res.ok()); + EXPECT_EQ(32, res.rc_); + } + ASSERT_EQ(0, internal_buffer.length()); + ASSERT_TRUE(writable_flipped); + + // Finally the buffer is empty. + EXPECT_FALSE(io_handle_->isReadable()); + EXPECT_TRUE(handle_as_peer->isWritable()); +} + // This test fixture test that io handle is impacted by peer. class BufferedIoSocketHandlePeerTest : public testing::Test { public: From 808ea0534e3af4e2142b14d5ff79c10854df4cf1 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Wed, 23 Sep 2020 22:45:59 +0000 Subject: [PATCH 024/100] add EventScheduleBasic test Signed-off-by: Yuchen Dai --- source/common/event/file_event_impl.h | 107 +++++++++++++----- .../network/buffered_io_socket_handle_impl.cc | 13 ++- .../network/buffered_io_socket_handle_impl.h | 19 +++- test/common/network/BUILD | 1 + .../buffered_io_socket_handle_impl_test.cc | 44 ++++--- 5 files changed, 128 insertions(+), 56 deletions(-) diff --git a/source/common/event/file_event_impl.h b/source/common/event/file_event_impl.h index 7a4a6573f00a..be2f6f8ee8c8 100644 --- a/source/common/event/file_event_impl.h +++ b/source/common/event/file_event_impl.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include "envoy/event/file_event.h" @@ -8,6 +9,10 @@ #include "common/event/event_impl_base.h" namespace Envoy { +namespace Network { +class BufferedIoSocketHandleImpl; +} + namespace Event { /** @@ -42,44 +47,94 @@ class FileEventImpl : public FileEvent, ImplBase { const bool activate_fd_events_next_event_loop_; }; -class TimerWrappedFileEventImpl : public FileEvent { +// Forward declare for friend class. +class UserSpaceFileEventFactory; + +class EventListener { public: - TimerWrappedFileEventImpl(SchedulableCallbackPtr schedulable) - : schedulable_(std::move(schedulable)) {} + virtual ~EventListener() = default; + virtual uint32_t triggeredEvents() PURE; + virtual void onEventEnabled(uint32_t enabled_events) PURE; + virtual void onEventActivated(uint32_t enabled_events) PURE; + virtual uint32_t getAndClearEpheralEvents() PURE; +}; - ~TimerWrappedFileEventImpl() { - if (schedulable_->enabled()) { - schedulable_->cancel(); - } +// Return the enabled events except EV_CLOSED. This implementation is generally good since only +// epoll supports EV_CLOSED. The event owner must assume EV_CLOSED is not reliable. Also event owner +// must assume OS could notify events which are not actually triggered. +class DefaultEventListener : public EventListener { +public: + ~DefaultEventListener() override = default; + uint32_t triggeredEvents() override { return pending_events_ & (~EV_CLOSED); } + void onEventEnabled(uint32_t enabled_events) override { pending_events_ = enabled_events; } + void onEventActivated(uint32_t activated_events) override { + ephermal_events_ |= activated_events; + } + uint32_t getAndClearEpheralEvents() override { + auto res = ephermal_events_; + ephermal_events_ = 0; + return res; } - // Event::FileEvent - void activate(uint32_t) override { schedulable_->scheduleCallbackNextIteration(); } - void setEnabled(uint32_t) override { schedulable_->scheduleCallbackNextIteration(); } private: - SchedulableCallbackPtr schedulable_; + // The persisted intrested events and ready events. + uint32_t pending_events_; + // The events set by activate() and will be cleared after the io callback. + uint32_t ephermal_events_; }; -/** - * This file event is a helper event to be always active. It works with BufferedIoSocketHandleImpl - * so that the socket handle will call io methods ASAP and obtain the error code. - */ -class AlwaysActiveFileEventImpl : public FileEvent { +// A FileEvent implementation which is +class UserSpaceFileEventImpl : public FileEvent { public: - AlwaysActiveFileEventImpl(SchedulableCallbackPtr schedulable) - : schedulable_(std::move(schedulable)) {} - - ~AlwaysActiveFileEventImpl() override { - if (schedulable_->enabled()) { - schedulable_->cancel(); - } + ~UserSpaceFileEventImpl() override { + //if (schedulable_.enabled()) { + schedulable_.cancel(); + //} + ASSERT(event_counter_ == 1); + --event_counter_; } + // Event::FileEvent - void activate(uint32_t) override { schedulable_->scheduleCallbackNextIteration(); } - void setEnabled(uint32_t) override { schedulable_->scheduleCallbackNextIteration(); } + void activate(uint32_t events) override { + event_listener_.onEventEnabled(events); + schedulable_.scheduleCallbackNextIteration(); + } + + void setEnabled(uint32_t events) override { + event_listener_.onEventEnabled(events); + schedulable_.scheduleCallbackNextIteration(); + } + + EventListener& getEventListener() { return event_listener_; } + void onEvents() { + cb_(); + } + friend class UserSpaceFileEventFactory; + friend class Network::BufferedIoSocketHandleImpl; private: - SchedulableCallbackPtr schedulable_; + UserSpaceFileEventImpl(Event::FileReadyCb cb, uint32_t events, SchedulableCallback& schedulable_cb, int& event_counter) + : schedulable_(schedulable_cb), cb_([this, cb]() { + auto all_events = getEventListener().triggeredEvents(); + auto epheral_events = getEventListener().getAndClearEpheralEvents(); + cb(all_events | epheral_events); + }), + event_counter_(event_counter) { + event_listener_.onEventEnabled(events); + } + DefaultEventListener event_listener_; + SchedulableCallback& schedulable_; + std::function cb_; + int& event_counter_; +}; + +class UserSpaceFileEventFactory { +public: + static std::unique_ptr + createUserSpaceFileEventImpl(Event::Dispatcher& , Event::FileReadyCb cb, + Event::FileTriggerType, uint32_t events, SchedulableCallback& scheduable_cb, int& event_counter) { + return std::unique_ptr(new UserSpaceFileEventImpl(cb, events, scheduable_cb, event_counter)); + } }; } // namespace Event diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc index e3bd34854c11..fe4eb289a770 100644 --- a/source/common/network/buffered_io_socket_handle_impl.cc +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -122,10 +122,17 @@ Address::InstanceConstSharedPtr BufferedIoSocketHandleImpl::peerAddress() { Event::FileEventPtr BufferedIoSocketHandleImpl::createFileEvent(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, - Event::FileTriggerType, + Event::FileTriggerType trigger_type, uint32_t events) { - return std::make_unique( - dispatcher.createSchedulableCallback([cb, events]() -> void { cb(events); })); + ASSERT(event_counter_ == 0); + ++event_counter_; + io_callback_ = dispatcher.createSchedulableCallback([this]() { user_file_event_->onEvents(); }); + auto res = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( + dispatcher, cb, trigger_type, events, *io_callback_, event_counter_); + user_file_event_ = res.get(); + // Blindly activate the events. + io_callback_->scheduleCallbackNextIteration(); + return res; } Api::SysCallIntResult BufferedIoSocketHandleImpl::shutdown(int how) { diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/common/network/buffered_io_socket_handle_impl.h index 7dc31e2ac937..a3ae428acb94 100644 --- a/source/common/network/buffered_io_socket_handle_impl.h +++ b/source/common/network/buffered_io_socket_handle_impl.h @@ -6,10 +6,12 @@ #include "envoy/event/dispatcher.h" #include "envoy/network/io_handle.h" +#include "common/event/file_event_impl.h" #include "common/buffer/watermark_buffer.h" #include "common/common/logger.h" #include "common/network/io_socket_error_impl.h" #include "common/network/peer_buffer.h" +#include namespace Envoy { namespace Network { @@ -75,7 +77,12 @@ class BufferedIoSocketHandleImpl : public IoHandle, Buffer::WatermarkBuffer& getBufferForTest() { return owned_buffer_; } void scheduleWriteEvent() {} - void scheduleNextEvent() {} + void scheduleNextEvent() { + // It's possible there is no pending file event so as no io_callback. + if (io_callback_) { + io_callback_->scheduleCallbackNextIteration(); + } + } void setWritablePeer(WritablePeer* writable_peer) { // Swapping writable peer is undefined behavior. @@ -94,9 +101,7 @@ class BufferedIoSocketHandleImpl : public IoHandle, writable_peer_ = nullptr; peer_closed_ = true; } - bool isWritable() const override { - return !isOverHighWatermark(); - } + bool isWritable() const override { return !isOverHighWatermark(); } Buffer::Instance* getWriteBuffer() override { return &owned_buffer_; } // ReadableSource bool isPeerShutDownWrite() const override { return read_end_stream_; } @@ -107,6 +112,12 @@ class BufferedIoSocketHandleImpl : public IoHandle, // Support isOpen() and close(). IoHandle owner must invoke close() to avoid potential resource // leak. bool closed_; + + Event::UserSpaceFileEventImpl* user_file_event_; + int event_counter_{0}; + // Trigger of the io event. + Event::SchedulableCallbackPtr io_callback_; + // True if owned_buffer_ is not addable. Note that owned_buffer_ may have pending data to drain. bool read_end_stream_{false}; Buffer::WatermarkBuffer owned_buffer_; diff --git a/test/common/network/BUILD b/test/common/network/BUILD index 08aa3bb3774d..ba1aa58a4bf4 100644 --- a/test/common/network/BUILD +++ b/test/common/network/BUILD @@ -384,6 +384,7 @@ envoy_cc_test( name = "buffered_io_socket_handle_impl_test", srcs = ["buffered_io_socket_handle_impl_test.cc"], deps = [ + "//test/mocks/event:event_mocks", "//source/common/common:utility_lib", "//source/common/network:address_lib", "//source/common/network:buffered_io_socket_handle_lib", diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index 4c28f79c4427..9157c1b04409 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -2,6 +2,8 @@ #include "common/network/buffered_io_socket_handle_impl.h" +#include "test/mocks/event/mocks.h" + #include "absl/container/fixed_array.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -17,6 +19,10 @@ namespace Envoy { namespace Network { namespace { +class MockFileEventCallback { +public: + MOCK_METHOD(void, called, (uint32_t arg)); +}; class BufferedIoSocketHandleTest : public testing::Test { public: BufferedIoSocketHandleTest() : buf_(1024) { @@ -34,6 +40,11 @@ class BufferedIoSocketHandleTest : public testing::Test { EXPECT_FALSE(res.ok()); EXPECT_EQ(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); } + NiceMock dispatcher_{}; + + // Owned by BufferedIoSocketHandle. + NiceMock* scheduable_cb_; + MockFileEventCallback cb_; std::unique_ptr io_handle_; std::unique_ptr io_handle_peer_; absl::FixedArray buf_; @@ -109,30 +120,17 @@ TEST_F(BufferedIoSocketHandleTest, FlowControl) { EXPECT_TRUE(handle_as_peer->isWritable()); } -// This test fixture test that io handle is impacted by peer. -class BufferedIoSocketHandlePeerTest : public testing::Test { -public: - BufferedIoSocketHandlePeerTest() : buf_(1024) { - io_handle_ = std::make_unique(); - io_handle_peer_ = std::make_unique(); - io_handle_->setWritablePeer(io_handle_peer_.get()); - io_handle_peer_->setWritablePeer(io_handle_.get()); - } - ~BufferedIoSocketHandlePeerTest() override { - io_handle_->close(); - io_handle_peer_->close(); - } - void expectAgain() { - auto res = io_handle_->recv(buf_.data(), buf_.size(), MSG_PEEK); - EXPECT_FALSE(res.ok()); - EXPECT_EQ(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); - } - std::unique_ptr io_handle_; - std::unique_ptr io_handle_peer_; - absl::FixedArray buf_; -}; +TEST_F(BufferedIoSocketHandleTest, EventScheduleBasic) { + scheduable_cb_ = new NiceMock(&dispatcher_); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + auto ev = io_handle_->createFileEvent( + dispatcher_, [this](uint32_t events) { cb_.called(events); }, + Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); -TEST_F(BufferedIoSocketHandlePeerTest, TestRecvDrain) {} + EXPECT_CALL(cb_, called(_)); + scheduable_cb_->invokeCallback(); + ev.reset(); +} } // namespace } // namespace Network From 50479caf0465431363c40c58661466ef48a1ce14 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Wed, 23 Sep 2020 23:50:36 +0000 Subject: [PATCH 025/100] add more event test Signed-off-by: Yuchen Dai --- source/common/event/file_event_impl.h | 35 +++-- .../buffered_io_socket_handle_impl_test.cc | 129 ++++++++++++++++++ 2 files changed, 149 insertions(+), 15 deletions(-) diff --git a/source/common/event/file_event_impl.h b/source/common/event/file_event_impl.h index be2f6f8ee8c8..8f45b7e208fa 100644 --- a/source/common/event/file_event_impl.h +++ b/source/common/event/file_event_impl.h @@ -65,7 +65,7 @@ class EventListener { class DefaultEventListener : public EventListener { public: ~DefaultEventListener() override = default; - uint32_t triggeredEvents() override { return pending_events_ & (~EV_CLOSED); } + uint32_t triggeredEvents() override { return pending_events_ & (~Event::FileReadyType::Closed); } void onEventEnabled(uint32_t enabled_events) override { pending_events_ = enabled_events; } void onEventActivated(uint32_t activated_events) override { ephermal_events_ |= activated_events; @@ -78,42 +78,45 @@ class DefaultEventListener : public EventListener { private: // The persisted intrested events and ready events. - uint32_t pending_events_; + uint32_t pending_events_{}; // The events set by activate() and will be cleared after the io callback. - uint32_t ephermal_events_; + uint32_t ephermal_events_{}; }; // A FileEvent implementation which is class UserSpaceFileEventImpl : public FileEvent { public: ~UserSpaceFileEventImpl() override { - //if (schedulable_.enabled()) { - schedulable_.cancel(); + // if (schedulable_.enabled()) { + schedulable_.cancel(); //} - ASSERT(event_counter_ == 1); + ASSERT(event_counter_ == 1); --event_counter_; } // Event::FileEvent void activate(uint32_t events) override { event_listener_.onEventEnabled(events); - schedulable_.scheduleCallbackNextIteration(); + if (!schedulable_.enabled()) { + schedulable_.scheduleCallbackNextIteration(); + } } void setEnabled(uint32_t events) override { event_listener_.onEventEnabled(events); - schedulable_.scheduleCallbackNextIteration(); + if (!schedulable_.enabled()) { + schedulable_.scheduleCallbackNextIteration(); + } } EventListener& getEventListener() { return event_listener_; } - void onEvents() { - cb_(); - } + void onEvents() { cb_(); } friend class UserSpaceFileEventFactory; friend class Network::BufferedIoSocketHandleImpl; private: - UserSpaceFileEventImpl(Event::FileReadyCb cb, uint32_t events, SchedulableCallback& schedulable_cb, int& event_counter) + UserSpaceFileEventImpl(Event::FileReadyCb cb, uint32_t events, + SchedulableCallback& schedulable_cb, int& event_counter) : schedulable_(schedulable_cb), cb_([this, cb]() { auto all_events = getEventListener().triggeredEvents(); auto epheral_events = getEventListener().getAndClearEpheralEvents(); @@ -131,9 +134,11 @@ class UserSpaceFileEventImpl : public FileEvent { class UserSpaceFileEventFactory { public: static std::unique_ptr - createUserSpaceFileEventImpl(Event::Dispatcher& , Event::FileReadyCb cb, - Event::FileTriggerType, uint32_t events, SchedulableCallback& scheduable_cb, int& event_counter) { - return std::unique_ptr(new UserSpaceFileEventImpl(cb, events, scheduable_cb, event_counter)); + createUserSpaceFileEventImpl(Event::Dispatcher&, Event::FileReadyCb cb, Event::FileTriggerType, + uint32_t events, SchedulableCallback& scheduable_cb, + int& event_counter) { + return std::unique_ptr( + new UserSpaceFileEventImpl(cb, events, scheduable_cb, event_counter)); } }; diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index 9157c1b04409..c2067eb085c6 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -2,6 +2,7 @@ #include "common/network/buffered_io_socket_handle_impl.h" +#include "envoy/event/file_event.h" #include "test/mocks/event/mocks.h" #include "absl/container/fixed_array.h" @@ -132,6 +133,134 @@ TEST_F(BufferedIoSocketHandleTest, EventScheduleBasic) { ev.reset(); } +TEST_F(BufferedIoSocketHandleTest, TestSetEnabledTriggerEventSchedule) { + scheduable_cb_ = new NiceMock(&dispatcher_); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + auto ev = io_handle_->createFileEvent( + dispatcher_, [this](uint32_t events) { cb_.called(events); }, + Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + + ASSERT_TRUE(scheduable_cb_->enabled()); + EXPECT_CALL(cb_, called(Event::FileReadyType::Read)); + scheduable_cb_->invokeCallback(); + ASSERT_FALSE(scheduable_cb_->enabled()); + + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + ev->setEnabled(Event::FileReadyType::Read); + ASSERT_TRUE(scheduable_cb_->enabled()); + EXPECT_CALL(cb_, called(_)); + scheduable_cb_->invokeCallback(); + ASSERT_FALSE(scheduable_cb_->enabled()); + + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + ev->setEnabled(Event::FileReadyType::Write); + ASSERT_TRUE(scheduable_cb_->enabled()); + EXPECT_CALL(cb_, called(Event::FileReadyType::Write)); + scheduable_cb_->invokeCallback(); + ASSERT_FALSE(scheduable_cb_->enabled()); + + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + ev->setEnabled(Event::FileReadyType::Write | Event::FileReadyType::Read); + ASSERT_TRUE(scheduable_cb_->enabled()); + EXPECT_CALL(cb_, called(Event::FileReadyType::Write | Event::FileReadyType::Read)); + scheduable_cb_->invokeCallback(); + ASSERT_FALSE(scheduable_cb_->enabled()); + ev.reset(); +} + +TEST_F(BufferedIoSocketHandleTest, TestReadAndWriteAreEdgeTriggered) { + scheduable_cb_ = new NiceMock(&dispatcher_); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + auto ev = io_handle_->createFileEvent( + dispatcher_, [this](uint32_t events) { cb_.called(events); }, + Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + + EXPECT_CALL(cb_, called(_)); + scheduable_cb_->invokeCallback(); + + // Neither read and write will trigger self readiness. + EXPECT_CALL(cb_, called(_)).Times(0); + + // Drain 1 bytes. + auto& internal_buffer = io_handle_->getBufferForTest(); + internal_buffer.add("abcd"); + auto res = io_handle_->recv(buf_.data(), 1, 0); + EXPECT_TRUE(res.ok()); + EXPECT_EQ(1, res.rc_); + + ASSERT_FALSE(scheduable_cb_->enabled()); + ev.reset(); +} + +TEST_F(BufferedIoSocketHandleTest, TestSetDisabledBlockEventSchedule) { + scheduable_cb_ = new NiceMock(&dispatcher_); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + auto ev = io_handle_->createFileEvent( + dispatcher_, [this](uint32_t events) { cb_.called(events); }, + Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + + ev->setEnabled(0); + + EXPECT_CALL(cb_, called(0)); + scheduable_cb_->invokeCallback(); + + ASSERT_FALSE(scheduable_cb_->enabled()); + ev.reset(); +} + +TEST_F(BufferedIoSocketHandleTest, TestEventResetClearCallback) { + scheduable_cb_ = new NiceMock(&dispatcher_); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + auto ev = io_handle_->createFileEvent( + dispatcher_, [this](uint32_t events) { cb_.called(events); }, + Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + ASSERT_TRUE(scheduable_cb_->enabled()); + + ev.reset(); + ASSERT_FALSE(scheduable_cb_->enabled()); +} + +TEST_F(BufferedIoSocketHandleTest, TestDrainToLowWaterMarkTriggerReadEvent) { + auto& internal_buffer = io_handle_->getBufferForTest(); + WritablePeer* handle_as_peer = io_handle_.get(); + internal_buffer.setWatermarks(128); + EXPECT_FALSE(io_handle_->isReadable()); + EXPECT_TRUE(io_handle_peer_->isWritable()); + + std::string big_chunk(256, 'a'); + internal_buffer.add(big_chunk); + EXPECT_TRUE(io_handle_->isReadable()); + EXPECT_FALSE(handle_as_peer->isWritable()); + + bool writable_flipped = false; + // During the repeated recv, the writable flag must switch to true. + while (internal_buffer.length() > 0) { + SCOPED_TRACE(internal_buffer.length()); + EXPECT_TRUE(io_handle_->isReadable()); + bool writable = handle_as_peer->isWritable(); + if (writable) { + writable_flipped = true; + } else { + ASSERT_FALSE(writable_flipped); + } + auto res = io_handle_->recv(buf_.data(), 32, 0); + EXPECT_TRUE(res.ok()); + EXPECT_EQ(32, res.rc_); + } + ASSERT_EQ(0, internal_buffer.length()); + ASSERT_TRUE(writable_flipped); + + // Finally the buffer is empty. + EXPECT_FALSE(io_handle_->isReadable()); + EXPECT_TRUE(handle_as_peer->isWritable()); +} + +TEST_F(BufferedIoSocketHandleTest, TestClose) { +} + +TEST_F(BufferedIoSocketHandleTest, TestShutdown) { +} + } // namespace } // namespace Network } // namespace Envoy \ No newline at end of file From 5fdec415522d3b2f6c0189b084be13dd5e47032f Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 24 Sep 2020 09:27:56 +0000 Subject: [PATCH 026/100] add test close Signed-off-by: Yuchen Dai --- .../network/buffered_io_socket_handle_impl.h | 17 +++- source/common/network/peer_buffer.h | 5 ++ .../buffered_io_socket_handle_impl_test.cc | 86 ++++++++++++++----- 3 files changed, 83 insertions(+), 25 deletions(-) diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/common/network/buffered_io_socket_handle_impl.h index a3ae428acb94..4a1e125a3fe4 100644 --- a/source/common/network/buffered_io_socket_handle_impl.h +++ b/source/common/network/buffered_io_socket_handle_impl.h @@ -29,8 +29,15 @@ class BufferedIoSocketHandleImpl : public IoHandle, [this]() -> void { over_high_watermark_ = false; triggered_high_to_low_watermark_ = true; + if (writable_peer_) { + writable_peer_->onPeerBufferWritable(); + } }, - [this]() -> void { over_high_watermark_ = true; }, []() -> void {}) {} + [this]() -> void { + over_high_watermark_ = true; + // low to high is checked by peer after peer writes data. + }, + []() -> void {}) {} ~BufferedIoSocketHandleImpl() override { ASSERT(closed_); } @@ -77,6 +84,8 @@ class BufferedIoSocketHandleImpl : public IoHandle, Buffer::WatermarkBuffer& getBufferForTest() { return owned_buffer_; } void scheduleWriteEvent() {} + void scheduleReadEvent() {} + void scheduleNextEvent() { // It's possible there is no pending file event so as no io_callback. if (io_callback_) { @@ -94,13 +103,17 @@ class BufferedIoSocketHandleImpl : public IoHandle, // WritablePeer void setWriteEnd() override { read_end_stream_ = true; } void maybeSetNewData() override { - scheduleWriteEvent(); + scheduleReadEvent(); scheduleNextEvent(); } void onPeerDestroy() override { writable_peer_ = nullptr; peer_closed_ = true; } + void onPeerBufferWritable() override { + scheduleWriteEvent(); + scheduleNextEvent(); + } bool isWritable() const override { return !isOverHighWatermark(); } Buffer::Instance* getWriteBuffer() override { return &owned_buffer_; } // ReadableSource diff --git a/source/common/network/peer_buffer.h b/source/common/network/peer_buffer.h index fc09f577ffd6..8f11dd22a59a 100644 --- a/source/common/network/peer_buffer.h +++ b/source/common/network/peer_buffer.h @@ -47,6 +47,11 @@ class WritablePeer { */ virtual bool isWritable() const PURE; + /** + * Raised by the peer when the peer switch from high water mark to low. + */ + virtual void onPeerBufferWritable() PURE; + // virtual bool triggeredHighToLowWatermark() const PURE; // virtual void clearTriggeredHighToLowWatermark() PURE; // virtual void setTriggeredHighToLowWatermark() PURE; diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index c2067eb085c6..7a627eb7b23f 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -33,8 +33,12 @@ class BufferedIoSocketHandleTest : public testing::Test { io_handle_peer_->setWritablePeer(io_handle_.get()); } ~BufferedIoSocketHandleTest() override { - io_handle_->close(); - io_handle_peer_->close(); + if (io_handle_->isOpen()) { + io_handle_->close(); + } + if (io_handle_peer_->isOpen()) { + io_handle_peer_->close(); + } } void expectAgain() { auto res = io_handle_->recv(buf_.data(), buf_.size(), MSG_PEEK); @@ -232,35 +236,71 @@ TEST_F(BufferedIoSocketHandleTest, TestDrainToLowWaterMarkTriggerReadEvent) { EXPECT_TRUE(io_handle_->isReadable()); EXPECT_FALSE(handle_as_peer->isWritable()); - bool writable_flipped = false; - // During the repeated recv, the writable flag must switch to true. - while (internal_buffer.length() > 0) { - SCOPED_TRACE(internal_buffer.length()); - EXPECT_TRUE(io_handle_->isReadable()); - bool writable = handle_as_peer->isWritable(); - if (writable) { - writable_flipped = true; - } else { - ASSERT_FALSE(writable_flipped); - } - auto res = io_handle_->recv(buf_.data(), 32, 0); - EXPECT_TRUE(res.ok()); - EXPECT_EQ(32, res.rc_); + // Clear invoke callback on peer. + scheduable_cb_ = new NiceMock(&dispatcher_); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + auto ev = io_handle_peer_->createFileEvent( + dispatcher_, [this](uint32_t events) { cb_.called(events); }, + Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + ASSERT_TRUE(scheduable_cb_->enabled()); + EXPECT_CALL(cb_, called(_)); + scheduable_cb_->invokeCallback(); + ASSERT_FALSE(scheduable_cb_->enabled()); + + { + auto res = io_handle_->recv(buf_.data(), 1, 0); + EXPECT_FALSE(handle_as_peer->isWritable()); + } + { + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()).Times(1); + auto res = io_handle_->recv(buf_.data(), 232, 0); + EXPECT_TRUE(handle_as_peer->isWritable()); } - ASSERT_EQ(0, internal_buffer.length()); - ASSERT_TRUE(writable_flipped); - // Finally the buffer is empty. - EXPECT_FALSE(io_handle_->isReadable()); - EXPECT_TRUE(handle_as_peer->isWritable()); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()).Times(1); + io_handle_->close(); } TEST_F(BufferedIoSocketHandleTest, TestClose) { -} + std::string accumulator; + scheduable_cb_ = new NiceMock(&dispatcher_); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + bool should_close = false; + auto ev = io_handle_->createFileEvent( + dispatcher_, + [this, &should_close, handle = io_handle_.get(), &accumulator](uint32_t events) { + if (events & Event::FileReadyType::Read) { + auto res = io_handle_->recv(buf_.data(), buf_.size(), 0); + if (res.ok()) { + accumulator += absl::string_view(buf_.data(), res.rc_); + } else if (res.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { + ENVOY_LOG_MISC(debug, "lambdai: EAGAIN"); + } else { + ENVOY_LOG_MISC(debug, "lambdai: close, not schedule event"); + should_close = true; + } + } + }, + Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + scheduable_cb_->invokeCallback(); + + // Not closed yet. + ASSERT_FALSE(should_close); + + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + io_handle_peer_->close(); -TEST_F(BufferedIoSocketHandleTest, TestShutdown) { + ASSERT_TRUE(scheduable_cb_->enabled()); + scheduable_cb_->invokeCallback(); + ASSERT_TRUE(should_close); + + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()).Times(0); + io_handle_->close(); + ev.reset(); } +TEST_F(BufferedIoSocketHandleTest, TestShutdown) {} + } // namespace } // namespace Network } // namespace Envoy \ No newline at end of file From b55e03ef1f6be0cff3a1c9332e0e8272b22dcb6a Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 24 Sep 2020 09:34:03 +0000 Subject: [PATCH 027/100] add shutdown test Signed-off-by: Yuchen Dai --- .../buffered_io_socket_handle_impl_test.cc | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index 7a627eb7b23f..77c4a05005f6 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -299,7 +299,42 @@ TEST_F(BufferedIoSocketHandleTest, TestClose) { ev.reset(); } -TEST_F(BufferedIoSocketHandleTest, TestShutdown) {} +TEST_F(BufferedIoSocketHandleTest, TestShutdown) { + std::string accumulator; + scheduable_cb_ = new NiceMock(&dispatcher_); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + bool should_close = false; + auto ev = io_handle_->createFileEvent( + dispatcher_, + [this, &should_close, handle = io_handle_.get(), &accumulator](uint32_t events) { + if (events & Event::FileReadyType::Read) { + auto res = io_handle_->recv(buf_.data(), buf_.size(), 0); + if (res.ok()) { + accumulator += absl::string_view(buf_.data(), res.rc_); + } else if (res.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { + ENVOY_LOG_MISC(debug, "lambdai: EAGAIN"); + } else { + ENVOY_LOG_MISC(debug, "lambdai: close, not schedule event"); + should_close = true; + } + } + }, + Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + scheduable_cb_->invokeCallback(); + + // Not closed yet. + ASSERT_FALSE(should_close); + + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + io_handle_peer_->shutdown(ENVOY_SHUT_WR); + + ASSERT_TRUE(scheduable_cb_->enabled()); + scheduable_cb_->invokeCallback(); + ASSERT_TRUE(should_close); + + io_handle_->close(); + ev.reset(); +} } // namespace } // namespace Network From 4a7970cd78d757682d4655422f56e3931eb4e6cd Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Fri, 25 Sep 2020 00:13:34 +0000 Subject: [PATCH 028/100] fixing test: working on TestReadFlowAfterShutdownWrite Signed-off-by: Yuchen Dai --- .../network/buffered_io_socket_handle_impl.cc | 53 ++++++++- .../buffered_io_socket_handle_impl_test.cc | 103 ++++++++++++++++++ 2 files changed, 150 insertions(+), 6 deletions(-) diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc index fe4eb289a770..eba8193d582a 100644 --- a/source/common/network/buffered_io_socket_handle_impl.cc +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -33,12 +33,54 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::close() { bool BufferedIoSocketHandleImpl::isOpen() const { return !closed_; } -Api::IoCallUint64Result BufferedIoSocketHandleImpl::readv(uint64_t, Buffer::RawSlice*, uint64_t) { - return IoSocketError::ioResultSocketInvalidAddress(); +Api::IoCallUint64Result BufferedIoSocketHandleImpl::readv(uint64_t max_length, + Buffer::RawSlice* slices, + uint64_t num_slice) { + if (owned_buffer_.length() == 0) { + if (read_end_stream_) { + return sysCallResultToIoCallResult(Api::SysCallSizeResult{-1, SOCKET_ERROR_INTR}); + } else { + return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), + IoSocketError::deleteIoError)}; + } + } else { + absl::FixedArray iov(num_slice); + uint64_t num_slices_to_read = 0; + uint64_t num_bytes_to_read = 0; + for (; num_slices_to_read < num_slice && num_bytes_to_read < max_length; num_slices_to_read++) { + auto min_len = std::min(std::min(owned_buffer_.length(), max_length) - num_bytes_to_read, + uint64_t(slices[num_slices_to_read].len_)); + owned_buffer_.copyOut(num_bytes_to_read, min_len, slices[num_slices_to_read].mem_); + num_bytes_to_read += min_len; + } + ASSERT(num_bytes_to_read <= max_length); + owned_buffer_.drain(num_bytes_to_read); + return {num_bytes_to_read, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; + } } -Api::IoCallUint64Result BufferedIoSocketHandleImpl::writev(const Buffer::RawSlice*, uint64_t) { - return IoSocketError::ioResultSocketInvalidAddress(); +Api::IoCallUint64Result BufferedIoSocketHandleImpl::writev(const Buffer::RawSlice* slices, + uint64_t num_slice) { + if (!writable_peer_) { + return sysCallResultToIoCallResult(Api::SysCallSizeResult{-1, SOCKET_ERROR_INTR}); + } + if (!writable_peer_->isWritable()) { + return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), + IoSocketError::deleteIoError)}; + } + // Write along with iteration. Buffer guarantee the fragment is always appendable. + uint64_t num_bytes_to_write = 0; + for (uint64_t i = 0; i < num_slice; i++) { + if (slices[i].mem_ != nullptr && slices[i].len_ != 0) { + // Buffer::BufferFragmentImpl fragment( + // slices[i].mem_, slices[i].len_, + // [](const void*, size_t, const Buffer::BufferFragmentImpl*) {}); + writable_peer_->getWriteBuffer()->add(slices[i].mem_, slices[i].len_); + num_bytes_to_write += slices[i].len_; + } + } + writable_peer_->maybeSetNewData(); + return {num_bytes_to_write, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } Api::IoCallUint64Result BufferedIoSocketHandleImpl::sendmsg(const Buffer::RawSlice*, uint64_t, int, @@ -136,7 +178,7 @@ Event::FileEventPtr BufferedIoSocketHandleImpl::createFileEvent(Event::Dispatche } Api::SysCallIntResult BufferedIoSocketHandleImpl::shutdown(int how) { - if ((how | ENVOY_SHUT_WR) || (how | ENVOY_SHUT_RDWR)) { + if ((how == ENVOY_SHUT_WR) || (how == ENVOY_SHUT_RDWR)) { ASSERT(!closed_); if (!peer_closed_) { ASSERT(writable_peer_); @@ -147,7 +189,6 @@ Api::SysCallIntResult BufferedIoSocketHandleImpl::shutdown(int how) { peer_closed_ = true; } } - // TODO(lambdai): return correct error code. return {0, 0}; } diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index 77c4a05005f6..37b6021ef20f 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -262,6 +262,8 @@ TEST_F(BufferedIoSocketHandleTest, TestDrainToLowWaterMarkTriggerReadEvent) { } TEST_F(BufferedIoSocketHandleTest, TestClose) { + auto& internal_buffer = io_handle_->getBufferForTest(); + internal_buffer.add("abcd"); std::string accumulator; scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); @@ -296,10 +298,14 @@ TEST_F(BufferedIoSocketHandleTest, TestClose) { EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()).Times(0); io_handle_->close(); + EXPECT_EQ(4, accumulator.size()); ev.reset(); } TEST_F(BufferedIoSocketHandleTest, TestShutdown) { + auto& internal_buffer = io_handle_->getBufferForTest(); + internal_buffer.add("abcd"); + std::string accumulator; scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); @@ -331,8 +337,105 @@ TEST_F(BufferedIoSocketHandleTest, TestShutdown) { ASSERT_TRUE(scheduable_cb_->enabled()); scheduable_cb_->invokeCallback(); ASSERT_TRUE(should_close); + EXPECT_EQ(4, accumulator.size()); + io_handle_->close(); + ev.reset(); +} + +TEST_F(BufferedIoSocketHandleTest, TestWriteToPeer) { + std::string raw_data("0123456789"); + absl::InlinedVector slices{ + // Contains 1 byte. + Buffer::RawSlice{static_cast(raw_data.data()), 1}, + // Contains 0 byte. + Buffer::RawSlice{nullptr, 1}, + // Contains 0 byte. + Buffer::RawSlice{raw_data.data() + 1, 0}, + // Contains 2 byte. + Buffer::RawSlice{raw_data.data() + 1, 2}, + }; + io_handle_peer_->writev(slices.data(), slices.size()); + auto& internal_buffer = io_handle_->getBufferForTest(); + EXPECT_EQ(3, internal_buffer.length()); + EXPECT_EQ("012", internal_buffer.toString()); +} + +TEST_F(BufferedIoSocketHandleTest, TestWriteScheduleWritableEvent) { + std::string accumulator; + scheduable_cb_ = new NiceMock(&dispatcher_); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + bool should_close = false; + auto ev = io_handle_->createFileEvent( + dispatcher_, + [this, &should_close, handle = io_handle_.get(), &accumulator](uint32_t events) { + if (events & Event::FileReadyType::Read) { + auto& internal_buffer = handle->getBufferForTest(); + Buffer::RawSlice slice; + internal_buffer.reserve(1024, &slice, 1); + auto res = io_handle_->readv(1024, &slice, 1); + if (res.ok()) { + accumulator += absl::string_view(static_cast(slice.mem_), res.rc_); + } else if (res.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { + ENVOY_LOG_MISC(debug, "lambdai: EAGAIN"); + } else { + ENVOY_LOG_MISC(debug, "lambdai: close, not schedule event"); + should_close = true; + } + } + }, + Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + scheduable_cb_->invokeCallback(); + EXPECT_FALSE(scheduable_cb_->enabled()); + + std::string raw_data("0123456789"); + Buffer::RawSlice slice{static_cast(raw_data.data()), raw_data.size()}; + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + io_handle_peer_->writev(&slice, 1); + + EXPECT_TRUE(scheduable_cb_->enabled()); + scheduable_cb_->invokeCallback(); + EXPECT_EQ("0123456789", accumulator); + EXPECT_FALSE(should_close); io_handle_->close(); +} + +TEST_F(BufferedIoSocketHandleTest, TestReadFlowAfterShutdownWrite) { + + io_handle_peer_->shutdown(ENVOY_SHUT_WR); + + std::string accumulator; + scheduable_cb_ = new NiceMock(&dispatcher_); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + bool should_close = false; + auto ev = io_handle_peer_->createFileEvent( + dispatcher_, + [this, &should_close, handle = io_handle_peer_.get(), &accumulator](uint32_t events) { + if (events & Event::FileReadyType::Read) { + auto res = io_handle_peer_->recv(buf_.data(), buf_.size(), 0); + if (res.ok()) { + accumulator += absl::string_view(buf_.data(), res.rc_); + } else if (res.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { + ENVOY_LOG_MISC(debug, "lambdai: EAGAIN"); + } else { + ENVOY_LOG_MISC(debug, "lambdai: close, not schedule event"); + should_close = true; + } + } + }, + Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + scheduable_cb_->invokeCallback(); + + EXPECT_FALSE(scheduable_cb_->enabled()); + std::string raw_data("0123456789"); + Buffer::RawSlice slice{static_cast(raw_data.data()), raw_data.size()}; + io_handle_->writev(&slice, 1); + EXPECT_TRUE(scheduable_cb_->enabled()); + + scheduable_cb_->invokeCallback(); + EXPECT_FALSE(scheduable_cb_->enabled()); + EXPECT_EQ(raw_data, accumulator); + ev.reset(); } From 5ffedb4f67c93f76f774f6247c188b5acb7efdf0 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Fri, 25 Sep 2020 16:34:36 +0000 Subject: [PATCH 029/100] close buffered_io_socket_handle_impl_test Signed-off-by: Yuchen Dai --- source/common/event/file_event_impl.h | 3 +- .../network/buffered_io_socket_handle_impl.cc | 14 ++-- .../network/buffered_io_socket_handle_impl.h | 41 ++++++----- source/common/network/peer_buffer.h | 3 +- test/common/network/BUILD | 2 +- .../buffered_io_socket_handle_impl_test.cc | 72 ++++++++++++++----- 6 files changed, 86 insertions(+), 49 deletions(-) diff --git a/source/common/event/file_event_impl.h b/source/common/event/file_event_impl.h index 8f45b7e208fa..a756c197ea4d 100644 --- a/source/common/event/file_event_impl.h +++ b/source/common/event/file_event_impl.h @@ -1,8 +1,9 @@ #pragma once -#include #include +#include + #include "envoy/event/file_event.h" #include "common/event/dispatcher_impl.h" diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc index eba8193d582a..d882d989461e 100644 --- a/source/common/network/buffered_io_socket_handle_impl.cc +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -17,7 +17,7 @@ namespace Network { Api::IoCallUint64Result BufferedIoSocketHandleImpl::close() { ASSERT(!closed_); - if (!peer_closed_) { + if (!write_shutdown_) { ASSERT(writable_peer_); // Notify the peer we won't write more data. shutdown(WRITE). writable_peer_->setWriteEnd(); @@ -25,7 +25,7 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::close() { writable_peer_->onPeerDestroy(); writable_peer_->maybeSetNewData(); writable_peer_ = nullptr; - peer_closed_ = true; + write_shutdown_ = true; } closed_ = true; return IoSocketError::ioResultSocketInvalidAddress(); @@ -64,7 +64,7 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::writev(const Buffer::RawSlic if (!writable_peer_) { return sysCallResultToIoCallResult(Api::SysCallSizeResult{-1, SOCKET_ERROR_INTR}); } - if (!writable_peer_->isWritable()) { + if (writable_peer_->isWriteEndSet() || !writable_peer_->isWritable()) { return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), IoSocketError::deleteIoError)}; } @@ -72,9 +72,6 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::writev(const Buffer::RawSlic uint64_t num_bytes_to_write = 0; for (uint64_t i = 0; i < num_slice; i++) { if (slices[i].mem_ != nullptr && slices[i].len_ != 0) { - // Buffer::BufferFragmentImpl fragment( - // slices[i].mem_, slices[i].len_, - // [](const void*, size_t, const Buffer::BufferFragmentImpl*) {}); writable_peer_->getWriteBuffer()->add(slices[i].mem_, slices[i].len_); num_bytes_to_write += slices[i].len_; } @@ -180,13 +177,12 @@ Event::FileEventPtr BufferedIoSocketHandleImpl::createFileEvent(Event::Dispatche Api::SysCallIntResult BufferedIoSocketHandleImpl::shutdown(int how) { if ((how == ENVOY_SHUT_WR) || (how == ENVOY_SHUT_RDWR)) { ASSERT(!closed_); - if (!peer_closed_) { + if (!write_shutdown_) { ASSERT(writable_peer_); // Notify the peer we won't write more data. shutdown(WRITE). writable_peer_->setWriteEnd(); writable_peer_->maybeSetNewData(); - writable_peer_ = nullptr; - peer_closed_ = true; + write_shutdown_ = true; } } return {0, 0}; diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/common/network/buffered_io_socket_handle_impl.h index 4a1e125a3fe4..9e1daa8f181e 100644 --- a/source/common/network/buffered_io_socket_handle_impl.h +++ b/source/common/network/buffered_io_socket_handle_impl.h @@ -1,17 +1,18 @@ #pragma once +#include + #include "envoy/api/io_error.h" #include "envoy/api/os_sys_calls.h" #include "envoy/common/platform.h" #include "envoy/event/dispatcher.h" #include "envoy/network/io_handle.h" -#include "common/event/file_event_impl.h" #include "common/buffer/watermark_buffer.h" #include "common/common/logger.h" +#include "common/event/file_event_impl.h" #include "common/network/io_socket_error_impl.h" #include "common/network/peer_buffer.h" -#include namespace Envoy { namespace Network { @@ -25,19 +26,22 @@ class BufferedIoSocketHandleImpl : public IoHandle, protected Logger::Loggable { public: BufferedIoSocketHandleImpl() - : closed_{false}, owned_buffer_( - [this]() -> void { - over_high_watermark_ = false; - triggered_high_to_low_watermark_ = true; - if (writable_peer_) { - writable_peer_->onPeerBufferWritable(); - } - }, - [this]() -> void { - over_high_watermark_ = true; - // low to high is checked by peer after peer writes data. - }, - []() -> void {}) {} + : closed_{false}, + owned_buffer_( + [this]() -> void { + over_high_watermark_ = false; + triggered_high_to_low_watermark_ = true; + if (writable_peer_) { + ENVOY_LOG_MISC(debug, "lambdai: {} switch to low water mark {}", + static_cast(this), static_cast(writable_peer_)); + writable_peer_->onPeerBufferWritable(); + } + }, + [this]() -> void { + over_high_watermark_ = true; + // low to high is checked by peer after peer writes data. + }, + []() -> void {}) {} ~BufferedIoSocketHandleImpl() override { ASSERT(closed_); } @@ -96,19 +100,20 @@ class BufferedIoSocketHandleImpl : public IoHandle, void setWritablePeer(WritablePeer* writable_peer) { // Swapping writable peer is undefined behavior. ASSERT(!writable_peer_); - ASSERT(!peer_closed_); + ASSERT(!write_shutdown_); writable_peer_ = writable_peer; } // WritablePeer void setWriteEnd() override { read_end_stream_ = true; } + bool isWriteEndSet() override { return read_end_stream_; } void maybeSetNewData() override { scheduleReadEvent(); scheduleNextEvent(); } void onPeerDestroy() override { writable_peer_ = nullptr; - peer_closed_ = true; + write_shutdown_ = true; } void onPeerBufferWritable() override { scheduleWriteEvent(); @@ -140,7 +145,7 @@ class BufferedIoSocketHandleImpl : public IoHandle, WritablePeer* writable_peer_{nullptr}; // The flag whether the peer is valid. Any write attempt should check flag. - bool peer_closed_{false}; + bool write_shutdown_{false}; bool over_high_watermark_{false}; bool triggered_high_to_low_watermark_{true}; diff --git a/source/common/network/peer_buffer.h b/source/common/network/peer_buffer.h index 8f11dd22a59a..6e0da2dc022c 100644 --- a/source/common/network/peer_buffer.h +++ b/source/common/network/peer_buffer.h @@ -25,6 +25,7 @@ class WritablePeer { * Set the flag to indicate no further write from peer. */ virtual void setWriteEnd() PURE; + virtual bool isWriteEndSet() PURE; /** * Raised when peer is destroyed. No further write to peer is allowed. @@ -48,7 +49,7 @@ class WritablePeer { virtual bool isWritable() const PURE; /** - * Raised by the peer when the peer switch from high water mark to low. + * Raised by the peer when the peer switch from high water mark to low. */ virtual void onPeerBufferWritable() PURE; diff --git a/test/common/network/BUILD b/test/common/network/BUILD index ba1aa58a4bf4..3885903c0936 100644 --- a/test/common/network/BUILD +++ b/test/common/network/BUILD @@ -384,10 +384,10 @@ envoy_cc_test( name = "buffered_io_socket_handle_impl_test", srcs = ["buffered_io_socket_handle_impl_test.cc"], deps = [ - "//test/mocks/event:event_mocks", "//source/common/common:utility_lib", "//source/common/network:address_lib", "//source/common/network:buffered_io_socket_handle_lib", + "//test/mocks/event:event_mocks", ], ) diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index 37b6021ef20f..67c5b205e0ad 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -1,8 +1,10 @@ #include +#include "envoy/event/file_event.h" + +#include "common/buffer/buffer_impl.h" #include "common/network/buffered_io_socket_handle_impl.h" -#include "envoy/event/file_event.h" #include "test/mocks/event/mocks.h" #include "absl/container/fixed_array.h" @@ -276,9 +278,9 @@ TEST_F(BufferedIoSocketHandleTest, TestClose) { if (res.ok()) { accumulator += absl::string_view(buf_.data(), res.rc_); } else if (res.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { - ENVOY_LOG_MISC(debug, "lambdai: EAGAIN"); + ENVOY_LOG_MISC(debug, "read returns EAGAIN"); } else { - ENVOY_LOG_MISC(debug, "lambdai: close, not schedule event"); + ENVOY_LOG_MISC(debug, "will close"); should_close = true; } } @@ -318,9 +320,9 @@ TEST_F(BufferedIoSocketHandleTest, TestShutdown) { if (res.ok()) { accumulator += absl::string_view(buf_.data(), res.rc_); } else if (res.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { - ENVOY_LOG_MISC(debug, "lambdai: EAGAIN"); + ENVOY_LOG_MISC(debug, "read returns EAGAIN"); } else { - ENVOY_LOG_MISC(debug, "lambdai: close, not schedule event"); + ENVOY_LOG_MISC(debug, "will close"); should_close = true; } } @@ -367,18 +369,18 @@ TEST_F(BufferedIoSocketHandleTest, TestWriteScheduleWritableEvent) { bool should_close = false; auto ev = io_handle_->createFileEvent( dispatcher_, - [this, &should_close, handle = io_handle_.get(), &accumulator](uint32_t events) { + [&should_close, handle = io_handle_.get(), &accumulator](uint32_t events) { if (events & Event::FileReadyType::Read) { - auto& internal_buffer = handle->getBufferForTest(); + Buffer::OwnedImpl buf; Buffer::RawSlice slice; - internal_buffer.reserve(1024, &slice, 1); - auto res = io_handle_->readv(1024, &slice, 1); + buf.reserve(1024, &slice, 1); + auto res = handle->readv(1024, &slice, 1); if (res.ok()) { accumulator += absl::string_view(static_cast(slice.mem_), res.rc_); } else if (res.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { - ENVOY_LOG_MISC(debug, "lambdai: EAGAIN"); + ENVOY_LOG_MISC(debug, "read returns EAGAIN"); } else { - ENVOY_LOG_MISC(debug, "lambdai: close, not schedule event"); + ENVOY_LOG_MISC(debug, "will close"); should_close = true; } } @@ -400,25 +402,28 @@ TEST_F(BufferedIoSocketHandleTest, TestWriteScheduleWritableEvent) { io_handle_->close(); } -TEST_F(BufferedIoSocketHandleTest, TestReadFlowAfterShutdownWrite) { - +TEST_F(BufferedIoSocketHandleTest, TestReadAfterShutdownWrite) { io_handle_peer_->shutdown(ENVOY_SHUT_WR); - + ENVOY_LOG_MISC(debug, "lambdai: after {} shutdown write ", + static_cast(io_handle_peer_.get())); std::string accumulator; scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); bool should_close = false; auto ev = io_handle_peer_->createFileEvent( dispatcher_, - [this, &should_close, handle = io_handle_peer_.get(), &accumulator](uint32_t events) { + [&should_close, handle = io_handle_peer_.get(), &accumulator](uint32_t events) { if (events & Event::FileReadyType::Read) { - auto res = io_handle_peer_->recv(buf_.data(), buf_.size(), 0); + Buffer::OwnedImpl buf; + Buffer::RawSlice slice; + buf.reserve(1024, &slice, 1); + auto res = handle->readv(1024, &slice, 1); if (res.ok()) { - accumulator += absl::string_view(buf_.data(), res.rc_); + accumulator += absl::string_view(static_cast(slice.mem_), res.rc_); } else if (res.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { - ENVOY_LOG_MISC(debug, "lambdai: EAGAIN"); + ENVOY_LOG_MISC(debug, "read returns EAGAIN"); } else { - ENVOY_LOG_MISC(debug, "lambdai: close, not schedule event"); + ENVOY_LOG_MISC(debug, "will close"); should_close = true; } } @@ -429,6 +434,7 @@ TEST_F(BufferedIoSocketHandleTest, TestReadFlowAfterShutdownWrite) { EXPECT_FALSE(scheduable_cb_->enabled()); std::string raw_data("0123456789"); Buffer::RawSlice slice{static_cast(raw_data.data()), raw_data.size()}; + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); io_handle_->writev(&slice, 1); EXPECT_TRUE(scheduable_cb_->enabled()); @@ -436,9 +442,37 @@ TEST_F(BufferedIoSocketHandleTest, TestReadFlowAfterShutdownWrite) { EXPECT_FALSE(scheduable_cb_->enabled()); EXPECT_EQ(raw_data, accumulator); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + io_handle_->close(); ev.reset(); } +TEST_F(BufferedIoSocketHandleTest, TestNotififyWritableAfterShutdownWrite) { + auto& peer_internal_buffer = io_handle_peer_->getBufferForTest(); + peer_internal_buffer.setWatermarks(128); + std::string big_chunk(256, 'a'); + peer_internal_buffer.add(big_chunk); + EXPECT_FALSE(io_handle_peer_->isWritable()); + + io_handle_peer_->shutdown(ENVOY_SHUT_WR); + ENVOY_LOG_MISC(debug, "lambdai: after {} shutdown write ", + static_cast(io_handle_peer_.get())); + + scheduable_cb_ = new NiceMock(&dispatcher_); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + auto ev = io_handle_->createFileEvent( + dispatcher_, [&, handle = io_handle_.get()](uint32_t) {}, Event::PlatformDefaultTriggerType, + Event::FileReadyType::Read); + scheduable_cb_->invokeCallback(); + EXPECT_FALSE(scheduable_cb_->enabled()); + + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + peer_internal_buffer.drain(peer_internal_buffer.length()); + EXPECT_TRUE(scheduable_cb_->enabled()); + + io_handle_->close(); +} + } // namespace } // namespace Network } // namespace Envoy \ No newline at end of file From 81d4c2e1944f88623d8b0ab245ad62616166e4f1 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Sat, 26 Sep 2020 23:29:40 +0000 Subject: [PATCH 030/100] add basic closing client connection test Signed-off-by: Yuchen Dai --- source/common/network/connection_impl.cc | 76 ++++++++++++++++++++++++ source/common/network/connection_impl.h | 56 +++++++++++++++++ test/common/network/BUILD | 25 +++++++- 3 files changed, 156 insertions(+), 1 deletion(-) diff --git a/source/common/network/connection_impl.cc b/source/common/network/connection_impl.cc index f297d9cc024b..abea65494791 100644 --- a/source/common/network/connection_impl.cc +++ b/source/common/network/connection_impl.cc @@ -4,6 +4,7 @@ #include #include +#include "common/common/macros.h" #include "envoy/common/exception.h" #include "envoy/common/platform.h" #include "envoy/config/core/v3/base.pb.h" @@ -774,5 +775,80 @@ void ClientConnectionImpl::connect() { } } } + +ClosingClientConnectionImpl::ClosingClientConnectionImpl( + Event::Dispatcher& dispatcher, const Address::InstanceConstSharedPtr& remote_address, + const Network::Address::InstanceConstSharedPtr& source_address) + + : dispatcher_(dispatcher), remote_address_(remote_address), source_address_(source_address), + stream_info_(dispatcher.timeSource()) {} +void ClosingClientConnectionImpl::connect() {} + +void ClosingClientConnectionImpl::addFilter(FilterSharedPtr) {} +void ClosingClientConnectionImpl::addWriteFilter(WriteFilterSharedPtr) {} +void ClosingClientConnectionImpl::addReadFilter(ReadFilterSharedPtr) {} +bool ClosingClientConnectionImpl::initializeReadFilters() { return true; } +void ClosingClientConnectionImpl::addConnectionCallbacks(ConnectionCallbacks& cb) { + callbacks_.push_back(&cb); +} +void ClosingClientConnectionImpl::addBytesSentCallback(BytesSentCb) {} +void ClosingClientConnectionImpl::enableHalfClose(bool) {} +void ClosingClientConnectionImpl::close(ConnectionCloseType close_type) { + UNREFERENCED_PARAMETER(close_type); + return; + NOT_IMPLEMENTED_GCOVR_EXCL_LINE; +} +Event::Dispatcher& ClosingClientConnectionImpl::dispatcher() { return dispatcher_; } +uint64_t ClosingClientConnectionImpl::id() const { return 0; } +void ClosingClientConnectionImpl::hashKey(std::vector&) const {} +std::string ClosingClientConnectionImpl::nextProtocol() const { return EMPTY_STRING; } +void ClosingClientConnectionImpl::noDelay(bool) {} +void ClosingClientConnectionImpl::readDisable(bool) { + // Always enable read since we want to trigger the read and lead to close(). +} +void ClosingClientConnectionImpl::detectEarlyCloseWhenReadDisabled(bool) {} +bool ClosingClientConnectionImpl::readEnabled() const { return true; } +const Network::Address::InstanceConstSharedPtr& ClosingClientConnectionImpl::remoteAddress() const { + return remote_address_; +} +// TODO(lambdai): add transport socket option add set up the remote address. +const Network::Address::InstanceConstSharedPtr& +ClosingClientConnectionImpl::directRemoteAddress() const { + return remote_address_; +} +absl::optional +ClosingClientConnectionImpl::unixSocketPeerCredentials() const { + return absl::nullopt; +} +const Network::Address::InstanceConstSharedPtr& ClosingClientConnectionImpl::localAddress() const { + return source_address_; +} +void ClosingClientConnectionImpl::setConnectionStats(const ConnectionStats& stats) { + UNREFERENCED_PARAMETER(stats); +} +Ssl::ConnectionInfoConstSharedPtr ClosingClientConnectionImpl::ssl() const { return nullptr; } +absl::string_view ClosingClientConnectionImpl::requestedServerName() const { return EMPTY_STRING; } +Connection::State ClosingClientConnectionImpl::state() const { return Connection::State::Open; } +void ClosingClientConnectionImpl::write(Buffer::Instance& data, bool end_stream) { + UNREFERENCED_PARAMETER(data); + UNREFERENCED_PARAMETER(end_stream); + NOT_IMPLEMENTED_GCOVR_EXCL_LINE; +} +void ClosingClientConnectionImpl::setBufferLimits(uint32_t) {} +uint32_t ClosingClientConnectionImpl::bufferLimit() const { return 65000; } +bool ClosingClientConnectionImpl::localAddressRestored() const { return true; } +bool ClosingClientConnectionImpl::aboveHighWatermark() const { return false; } +const ConnectionSocket::OptionsSharedPtr& ClosingClientConnectionImpl::socketOptions() const { + return socket_->options(); +} +StreamInfo::StreamInfo& ClosingClientConnectionImpl::streamInfo() { return stream_info_; } +const StreamInfo::StreamInfo& ClosingClientConnectionImpl::streamInfo() const { + return stream_info_; +} +void ClosingClientConnectionImpl::setDelayedCloseTimeout(std::chrono::milliseconds) {} +absl::string_view ClosingClientConnectionImpl::transportFailureReason() const { + return EMPTY_STRING; +} + } // namespace Network } // namespace Envoy diff --git a/source/common/network/connection_impl.h b/source/common/network/connection_impl.h index 17ebe609a263..a42524c13097 100644 --- a/source/common/network/connection_impl.h +++ b/source/common/network/connection_impl.h @@ -215,5 +215,61 @@ class ClientConnectionImpl : public ConnectionImpl, virtual public ClientConnect StreamInfo::StreamInfoImpl stream_info_; }; +/** + * libevent implementation of Network::ClientConnection expecting connect() fails immediately. + */ +class ClosingClientConnectionImpl : virtual public ClientConnection { +public: + ClosingClientConnectionImpl(Event::Dispatcher& dispatcher, + const Address::InstanceConstSharedPtr& remote_address, + const Address::InstanceConstSharedPtr& source_address); + + // Network::ClientConnection + void connect() override; + void addFilter(FilterSharedPtr filter) override; + void addReadFilter(ReadFilterSharedPtr filter) override; + void addWriteFilter(WriteFilterSharedPtr filter) override; + bool initializeReadFilters() override; + void addConnectionCallbacks(ConnectionCallbacks& cb) override; + void addBytesSentCallback(BytesSentCb) override; + void enableHalfClose(bool enabled) override; + void close(Network::ConnectionCloseType type) override; + Event::Dispatcher& dispatcher() override; + uint64_t id() const override; + void hashKey(std::vector& hash) const override; + std::string nextProtocol() const override; + void noDelay(bool enable) override; + void readDisable(bool disable) override; + void detectEarlyCloseWhenReadDisabled(bool should_detect) override; + bool readEnabled() const override; + const Network::Address::InstanceConstSharedPtr& remoteAddress() const override; + const Network::Address::InstanceConstSharedPtr& directRemoteAddress() const override; + absl::optional unixSocketPeerCredentials() const override; + const Network::Address::InstanceConstSharedPtr& localAddress() const override; + void setConnectionStats(const ConnectionStats& stats) override; + Ssl::ConnectionInfoConstSharedPtr ssl() const override; + absl::string_view requestedServerName() const override; + State state() const override; + void write(Buffer::Instance& data, bool end_stream) override; + void setBufferLimits(uint32_t limit) override; + uint32_t bufferLimit() const override; + bool localAddressRestored() const override; + bool aboveHighWatermark() const override; + const ConnectionSocket::OptionsSharedPtr& socketOptions() const override; + StreamInfo::StreamInfo& streamInfo() override; + const StreamInfo::StreamInfo& streamInfo() const override; + void setDelayedCloseTimeout(std::chrono::milliseconds timeout) override; + absl::string_view transportFailureReason() const override; + +public: + Event::Dispatcher& dispatcher_; + const Network::Address::InstanceConstSharedPtr remote_address_; + const Network::Address::InstanceConstSharedPtr source_address_; + ConnectionSocketPtr socket_; + + StreamInfo::StreamInfoImpl stream_info_; + std::list callbacks_; +}; + } // namespace Network } // namespace Envoy diff --git a/test/common/network/BUILD b/test/common/network/BUILD index 3885903c0936..0561fc177f01 100644 --- a/test/common/network/BUILD +++ b/test/common/network/BUILD @@ -94,7 +94,29 @@ envoy_cc_test( "@envoy_api//envoy/config/core/v3:pkg_cc_proto", ], ) - +envoy_cc_test( + name = "closing_connection_impl_test", + srcs = ["closing_connection_impl_test.cc"], + deps = [ + "//source/common/buffer:buffer_lib", + "//source/common/common:empty_string", + "//source/common/event:dispatcher_includes", + "//source/common/event:dispatcher_lib", + "//source/common/network:connection_lib", + "//source/common/network:listen_socket_lib", + "//source/common/network:utility_lib", + "//source/common/stats:stats_lib", + "//test/mocks/buffer:buffer_mocks", + "//test/mocks/event:event_mocks", + "//test/mocks/network:network_mocks", + "//test/mocks/stats:stats_mocks", + "//test/test_common:environment_lib", + "//test/test_common:network_utility_lib", + "//test/test_common:simulated_time_system_lib", + "//test/test_common:test_time_lib", + "@envoy_api//envoy/config/core/v3:pkg_cc_proto", + ], +) envoy_cc_test( name = "dns_impl_test", srcs = ["dns_impl_test.cc"], @@ -119,6 +141,7 @@ envoy_cc_test( ], ) + envoy_cc_test( name = "filter_manager_impl_test", srcs = ["filter_manager_impl_test.cc"], From 32eca3fdda46844b4e2ef38a557a7cfe13939e9a Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Sun, 27 Sep 2020 18:52:38 +0000 Subject: [PATCH 031/100] add connection callback and active close test in CLosingClientImpl Signed-off-by: Yuchen Dai --- source/common/network/connection_impl.cc | 39 ++++++++++++++++-------- source/common/network/connection_impl.h | 11 +++++-- 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/source/common/network/connection_impl.cc b/source/common/network/connection_impl.cc index abea65494791..e9a6e383b12c 100644 --- a/source/common/network/connection_impl.cc +++ b/source/common/network/connection_impl.cc @@ -780,8 +780,12 @@ ClosingClientConnectionImpl::ClosingClientConnectionImpl( Event::Dispatcher& dispatcher, const Address::InstanceConstSharedPtr& remote_address, const Network::Address::InstanceConstSharedPtr& source_address) - : dispatcher_(dispatcher), remote_address_(remote_address), source_address_(source_address), - stream_info_(dispatcher.timeSource()) {} + : dispatcher_(dispatcher), + immediate_close_timer_(dispatcher.createTimer([this]() { closeSocket(); })), + remote_address_(remote_address), source_address_(source_address), + stream_info_(dispatcher.timeSource()) { + immediate_close_timer_->enableTimer(std::chrono::milliseconds(0)); +} void ClosingClientConnectionImpl::connect() {} void ClosingClientConnectionImpl::addFilter(FilterSharedPtr) {} @@ -793,10 +797,12 @@ void ClosingClientConnectionImpl::addConnectionCallbacks(ConnectionCallbacks& cb } void ClosingClientConnectionImpl::addBytesSentCallback(BytesSentCb) {} void ClosingClientConnectionImpl::enableHalfClose(bool) {} -void ClosingClientConnectionImpl::close(ConnectionCloseType close_type) { - UNREFERENCED_PARAMETER(close_type); - return; - NOT_IMPLEMENTED_GCOVR_EXCL_LINE; +void ClosingClientConnectionImpl::close(ConnectionCloseType) { + if (is_closed_) { + ASSERT(!immediate_close_timer_->enabled()); + return; + } + closeSocket(); } Event::Dispatcher& ClosingClientConnectionImpl::dispatcher() { return dispatcher_; } uint64_t ClosingClientConnectionImpl::id() const { return 0; } @@ -828,18 +834,16 @@ void ClosingClientConnectionImpl::setConnectionStats(const ConnectionStats& stat } Ssl::ConnectionInfoConstSharedPtr ClosingClientConnectionImpl::ssl() const { return nullptr; } absl::string_view ClosingClientConnectionImpl::requestedServerName() const { return EMPTY_STRING; } -Connection::State ClosingClientConnectionImpl::state() const { return Connection::State::Open; } -void ClosingClientConnectionImpl::write(Buffer::Instance& data, bool end_stream) { - UNREFERENCED_PARAMETER(data); - UNREFERENCED_PARAMETER(end_stream); - NOT_IMPLEMENTED_GCOVR_EXCL_LINE; +Connection::State ClosingClientConnectionImpl::state() const { + return is_closed_ ? Connection::State::Closed : Connection::State::Open; } +void ClosingClientConnectionImpl::write(Buffer::Instance&, bool) {} void ClosingClientConnectionImpl::setBufferLimits(uint32_t) {} uint32_t ClosingClientConnectionImpl::bufferLimit() const { return 65000; } bool ClosingClientConnectionImpl::localAddressRestored() const { return true; } bool ClosingClientConnectionImpl::aboveHighWatermark() const { return false; } const ConnectionSocket::OptionsSharedPtr& ClosingClientConnectionImpl::socketOptions() const { - return socket_->options(); + return socket_options_; } StreamInfo::StreamInfo& ClosingClientConnectionImpl::streamInfo() { return stream_info_; } const StreamInfo::StreamInfo& ClosingClientConnectionImpl::streamInfo() const { @@ -850,5 +854,16 @@ absl::string_view ClosingClientConnectionImpl::transportFailureReason() const { return EMPTY_STRING; } +void ClosingClientConnectionImpl::closeSocket() { + if (is_closed_) { + ASSERT(!immediate_close_timer_->enabled()); + return; + } + is_closed_ = true; + for (ConnectionCallbacks* callback : callbacks_) { + callback->onEvent(ConnectionEvent::RemoteClose); + } + immediate_close_timer_->disableTimer(); +} } // namespace Network } // namespace Envoy diff --git a/source/common/network/connection_impl.h b/source/common/network/connection_impl.h index a42524c13097..06f0ef17afa7 100644 --- a/source/common/network/connection_impl.h +++ b/source/common/network/connection_impl.h @@ -6,6 +6,7 @@ #include #include +#include "envoy/event/timer.h" #include "envoy/network/transport_socket.h" #include "common/buffer/watermark_buffer.h" @@ -216,7 +217,7 @@ class ClientConnectionImpl : public ConnectionImpl, virtual public ClientConnect }; /** - * libevent implementation of Network::ClientConnection expecting connect() fails immediately. + * libevent implementation of Network::ClientConnection. It schedule close() immediately. */ class ClosingClientConnectionImpl : virtual public ClientConnection { public: @@ -261,14 +262,18 @@ class ClosingClientConnectionImpl : virtual public ClientConnection { void setDelayedCloseTimeout(std::chrono::milliseconds timeout) override; absl::string_view transportFailureReason() const override; +private: + void closeSocket(); + public: Event::Dispatcher& dispatcher_; + Event::TimerPtr immediate_close_timer_; const Network::Address::InstanceConstSharedPtr remote_address_; const Network::Address::InstanceConstSharedPtr source_address_; - ConnectionSocketPtr socket_; - + ConnectionSocket::OptionsSharedPtr socket_options_; StreamInfo::StreamInfoImpl stream_info_; std::list callbacks_; + bool is_closed_{false}; }; } // namespace Network From 80a9d2c5854230ca5119b695b8e45b5479f9cfc7 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Mon, 28 Sep 2020 04:10:44 +0000 Subject: [PATCH 032/100] dispatcher: create internal connection to nowhere Signed-off-by: Yuchen Dai --- source/common/event/dispatcher_impl.cc | 5 +- .../network/closing_connection_impl_test.cc | 94 +++++++++++++++++++ 2 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 test/common/network/closing_connection_impl_test.cc diff --git a/source/common/event/dispatcher_impl.cc b/source/common/event/dispatcher_impl.cc index c649a2923aa9..f8d494baf9dd 100644 --- a/source/common/event/dispatcher_impl.cc +++ b/source/common/event/dispatcher_impl.cc @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -119,7 +120,7 @@ DispatcherImpl::createClientConnection(Network::Address::InstanceConstSharedPtr Network::ClientConnectionPtr DispatcherImpl::createInternalConnection(Network::Address::InstanceConstSharedPtr internal_address, - Network::Address::InstanceConstSharedPtr) { + Network::Address::InstanceConstSharedPtr local_address) { ASSERT(isThreadSafe()); if (internal_address == nullptr) { return nullptr; @@ -132,7 +133,7 @@ DispatcherImpl::createInternalConnection(Network::Address::InstanceConstSharedPt if (iter == internal_listeners_.end()) { ENVOY_LOG_MISC(debug, "lambdai: no valid listener registered for envoy internal address {}", internal_address->asString()); - return nullptr; + return std::make_unique(*this, internal_address, local_address); } Network::ConnectionPtr server_conn{}; Network::ClientConnectionPtr client_conn{}; diff --git a/test/common/network/closing_connection_impl_test.cc b/test/common/network/closing_connection_impl_test.cc new file mode 100644 index 000000000000..ffe33ad56889 --- /dev/null +++ b/test/common/network/closing_connection_impl_test.cc @@ -0,0 +1,94 @@ +#include +#include +#include + +#include "envoy/common/platform.h" +#include "envoy/config/core/v3/base.pb.h" + +#include "common/buffer/buffer_impl.h" +#include "common/common/empty_string.h" +#include "common/common/fmt.h" +#include "common/event/dispatcher_impl.h" +#include "common/network/address_impl.h" +#include "common/network/connection_impl.h" +#include "common/network/io_socket_handle_impl.h" +#include "common/network/listen_socket_impl.h" +#include "common/network/utility.h" +#include "common/runtime/runtime_impl.h" + +#include "source/common/network/_virtual_includes/address_lib/common/network/address_impl.h" +#include "source/common/network/_virtual_includes/connection_lib/common/network/connection_impl.h" +#include "test/mocks/buffer/mocks.h" +#include "test/mocks/event/mocks.h" +#include "test/mocks/network/mocks.h" +#include "test/mocks/stats/mocks.h" +#include "test/test_common/environment.h" +#include "test/test_common/network_utility.h" +#include "test/test_common/printers.h" +#include "test/test_common/simulated_time_system.h" +#include "test/test_common/utility.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using testing::_; +using testing::AnyNumber; +using testing::DoAll; +using testing::Eq; +using testing::InSequence; +using testing::Invoke; +using testing::InvokeWithoutArgs; +using testing::Return; +using testing::SaveArg; +using testing::Sequence; +using testing::StrictMock; + +namespace Envoy { +namespace Network { + +class ClosingClientConnectionImplTest : public testing::Test { +protected: + ClosingClientConnectionImplTest() + : api_(Api::createApiForTest()), dispatcher_(api_->allocateDispatcher("test_thread")) {} + + Api::ApiPtr api_; + Event::DispatcherPtr dispatcher_; + const std::shared_ptr remote_address_{ + std::make_shared("listener_addr")}; + const std::shared_ptr source_address_{ + std::make_shared("local_addr")}; +}; + +TEST_F(ClosingClientConnectionImplTest, ActiveClose) { + ClosingClientConnectionImpl conn(*dispatcher_, remote_address_, source_address_); + conn.close(ConnectionCloseType::NoFlush); + EXPECT_EQ(Connection::State::Closed, conn.state()); +} + +TEST_F(ClosingClientConnectionImplTest, PassiveCloseDriveByDispatcher) { + MockConnectionCallbacks client_callbacks; + ClosingClientConnectionImpl conn(*dispatcher_, remote_address_, source_address_); + conn.addConnectionCallbacks(client_callbacks); + EXPECT_EQ(Connection::State::Open, conn.state()); + + EXPECT_CALL(client_callbacks, onEvent(Network::ConnectionEvent::RemoteClose)).Times(1); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + EXPECT_EQ(Connection::State::Closed, conn.state()); +} + +TEST_F(ClosingClientConnectionImplTest, ClosingConnectionCreatedByDispatcher) { + auto conn = dispatcher_->createInternalConnection( + std::make_shared("listener_id"), + std::make_shared("client_id")); + + MockConnectionCallbacks client_callbacks; + conn->addConnectionCallbacks(client_callbacks); + EXPECT_EQ(Connection::State::Open, conn->state()); + + EXPECT_CALL(client_callbacks, onEvent(Network::ConnectionEvent::RemoteClose)).Times(1); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + EXPECT_EQ(Connection::State::Closed, conn->state()); +} + +} // namespace Network +} // namespace Envoy From a5572cbd98e663aec05c5cee41baac932956be1b Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Mon, 28 Sep 2020 06:56:35 +0000 Subject: [PATCH 033/100] fixing create connection Signed-off-by: Yuchen Dai --- include/envoy/network/listener.h | 3 +-- source/common/event/BUILD | 1 + source/common/event/dispatcher_impl.cc | 8 +++--- source/common/event/dispatcher_impl.h | 8 ++++-- source/common/event/file_event_impl.h | 2 +- source/common/network/BUILD | 2 ++ .../network/buffered_io_socket_handle_impl.cc | 2 +- source/common/network/connection_impl.cc | 2 +- .../common/network/internal_listener_impl.cc | 25 ++++++++----------- .../common/network/internal_listener_impl.h | 3 +-- source/server/connection_handler_impl.cc | 16 ++++++++---- source/server/connection_handler_impl.h | 3 +-- test/common/network/BUILD | 3 ++- .../network/closing_connection_impl_test.cc | 1 + 14 files changed, 44 insertions(+), 35 deletions(-) diff --git a/include/envoy/network/listener.h b/include/envoy/network/listener.h index 2382c0a34044..56a820b227fc 100644 --- a/include/envoy/network/listener.h +++ b/include/envoy/network/listener.h @@ -214,8 +214,7 @@ class InternalListenerCallbacks { virtual void setupNewConnection(Network::ConnectionPtr server_conn, Network::ConnectionSocketPtr socket) PURE; - virtual void onNewSocket(Network::ConnectionSocketPtr socket, - Network::ConnectionSocketPtr server_socket) PURE; + virtual void onNewSocket(Network::ConnectionSocketPtr socket) PURE; }; /** diff --git a/source/common/event/BUILD b/source/common/event/BUILD index cf0ded8373e9..a434899ad4d2 100644 --- a/source/common/event/BUILD +++ b/source/common/event/BUILD @@ -30,6 +30,7 @@ envoy_cc_library( "//source/common/common:assert_lib", "//source/common/common:thread_lib", "//source/common/filesystem:watcher_lib", + "//source/common/network:buffered_io_socket_handle_lib", "//source/common/network:connection_lib", "//source/common/network:dns_lib", "//source/common/network:listener_lib", diff --git a/source/common/event/dispatcher_impl.cc b/source/common/event/dispatcher_impl.cc index f8d494baf9dd..3347242425fe 100644 --- a/source/common/event/dispatcher_impl.cc +++ b/source/common/event/dispatcher_impl.cc @@ -19,6 +19,7 @@ #include "common/event/signal_impl.h" #include "common/event/timer_impl.h" #include "common/filesystem/watcher_impl.h" +#include "common/network/buffered_io_socket_handle_impl.h" #include "common/network/connection_impl.h" #include "common/network/dns_impl.h" #include "common/network/tcp_listener_impl.h" @@ -133,12 +134,13 @@ DispatcherImpl::createInternalConnection(Network::Address::InstanceConstSharedPt if (iter == internal_listeners_.end()) { ENVOY_LOG_MISC(debug, "lambdai: no valid listener registered for envoy internal address {}", internal_address->asString()); - return std::make_unique(*this, internal_address, local_address); + return std::make_unique(*this, internal_address, + local_address); } - Network::ConnectionPtr server_conn{}; Network::ClientConnectionPtr client_conn{}; + auto server_io_handle = std::make_unique(); - (iter->second)(internal_address, std::move(server_conn)); + (iter->second)(internal_address, std::move(server_io_handle)); return client_conn; } diff --git a/source/common/event/dispatcher_impl.h b/source/common/event/dispatcher_impl.h index ac2d9fde310c..8e14893d2688 100644 --- a/source/common/event/dispatcher_impl.h +++ b/source/common/event/dispatcher_impl.h @@ -21,6 +21,9 @@ #include "common/signal/fatal_error_handler.h" namespace Envoy { +namespace Network { +class BufferedIoSocketHandleImpl; +} namespace Event { /** @@ -34,8 +37,9 @@ class DispatcherImpl : Logger::Loggable, DispatcherImpl(const std::string& name, Buffer::WatermarkFactoryPtr&& factory, Api::Api& api, Event::TimeSystem& time_system); ~DispatcherImpl() override; - using InternalConnectionCallback = std::function; + using InternalConnectionCallback = + std::function internal_socket)>; /** * @return event_base& the libevent base. */ diff --git a/source/common/event/file_event_impl.h b/source/common/event/file_event_impl.h index a756c197ea4d..ad1b93a6d022 100644 --- a/source/common/event/file_event_impl.h +++ b/source/common/event/file_event_impl.h @@ -78,7 +78,7 @@ class DefaultEventListener : public EventListener { } private: - // The persisted intrested events and ready events. + // The persisted interested events and ready events. uint32_t pending_events_{}; // The events set by activate() and will be cleared after the io callback. uint32_t ephermal_events_{}; diff --git a/source/common/network/BUILD b/source/common/network/BUILD index cedbc5075d77..75d8c421d4c8 100644 --- a/source/common/network/BUILD +++ b/source/common/network/BUILD @@ -239,6 +239,7 @@ envoy_cc_library( name = "listener_lib", srcs = [ "base_listener_impl.cc", + "internal_listener_impl.cc", "tcp_listener_impl.cc", "udp_listener_impl.cc", ], @@ -264,6 +265,7 @@ envoy_cc_library( "//source/common/common:empty_string", "//source/common/common:linked_object", "//source/common/event:dispatcher_includes", + "//source/common/network:buffered_io_socket_handle_lib", "@envoy_api//envoy/config/core/v3:pkg_cc_proto", ], ) diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc index d882d989461e..4e24d8850e4e 100644 --- a/source/common/network/buffered_io_socket_handle_impl.cc +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -68,7 +68,7 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::writev(const Buffer::RawSlic return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), IoSocketError::deleteIoError)}; } - // Write along with iteration. Buffer guarantee the fragment is always appendable. + // Write along with iteration. Buffer guarantee the fragment is always append-able. uint64_t num_bytes_to_write = 0; for (uint64_t i = 0; i < num_slice; i++) { if (slices[i].mem_ != nullptr && slices[i].len_ != 0) { diff --git a/source/common/network/connection_impl.cc b/source/common/network/connection_impl.cc index e9a6e383b12c..d328f8c204a9 100644 --- a/source/common/network/connection_impl.cc +++ b/source/common/network/connection_impl.cc @@ -4,7 +4,6 @@ #include #include -#include "common/common/macros.h" #include "envoy/common/exception.h" #include "envoy/common/platform.h" #include "envoy/config/core/v3/base.pb.h" @@ -14,6 +13,7 @@ #include "common/common/assert.h" #include "common/common/empty_string.h" #include "common/common/enum_to_int.h" +#include "common/common/macros.h" #include "common/network/address_impl.h" #include "common/network/listen_socket_impl.h" #include "common/network/raw_buffer_socket.h" diff --git a/source/common/network/internal_listener_impl.cc b/source/common/network/internal_listener_impl.cc index da0f69864dea..1a8c670c18ef 100644 --- a/source/common/network/internal_listener_impl.cc +++ b/source/common/network/internal_listener_impl.cc @@ -11,6 +11,7 @@ #include "common/common/utility.h" #include "common/event/dispatcher_impl.h" #include "common/network/address_impl.h" +#include "common/network/buffered_io_socket_handle_impl.h" #include "common/network/io_socket_handle_impl.h" #include "absl/strings/str_cat.h" @@ -18,24 +19,18 @@ namespace Envoy { namespace Network { namespace { -uint64_t next_internal_connection_id = 0; +// uint64_t next_internal_connection_id = 0; } -void InternalListenerImpl::setupInternalListener(Event::DispatcherImpl& dispatcher, - const std::string& listener_id) { +void InternalListenerImpl::setupInternalListener(Event::DispatcherImpl& dispatcher) { dispatcher.registerInternalListener( - listener_id, - [this](const Address::InstanceConstSharedPtr& address, Network::ConnectionPtr server_conn) { - address->asString() + internal_listener_id_, + [this](const Address::InstanceConstSharedPtr& client_address, + std::unique_ptr internal_socket) { auto socket = std::make_unique( - nullptr, - // Local - address, - // Remote - std::make_shared(absl::StrCat( - address->asString(), - "-", - ++next_internal_connection_id)); - cb_.setupNewConnection(std::move(server_conn), std::move(socket)); + std::move(internal_socket), + std::make_shared(internal_listener_id_), + client_address); + cb_.onNewSocket(std::move(socket)); }); } diff --git a/source/common/network/internal_listener_impl.h b/source/common/network/internal_listener_impl.h index 1f586019ecbe..a431358f165c 100644 --- a/source/common/network/internal_listener_impl.h +++ b/source/common/network/internal_listener_impl.h @@ -19,8 +19,7 @@ class InternalListenerImpl : public BaseListenerImpl { void enable() override; protected: - void setupInternalListener(Event::DispatcherImpl& dispatcher, - const std::string& internal_listener_id); + void setupInternalListener(Event::DispatcherImpl& dispatcher); // TODO(lambdai): make it private public: diff --git a/source/server/connection_handler_impl.cc b/source/server/connection_handler_impl.cc index c5087584b80c..1a02bc2ad974 100644 --- a/source/server/connection_handler_impl.cc +++ b/source/server/connection_handler_impl.cc @@ -794,10 +794,16 @@ void ConnectionHandlerImpl::ActiveInternalSocket::newConnection() { connected_ = true; // Set default transport protocol if none of the listener filters did it. - if (socket_->detectedTransportProtocol().empty()) { - socket_->setDetectedTransportProtocol( - Extensions::TransportSockets::TransportProtocolNames::get().RawBuffer); - } + if (!socket_->detectedTransportProtocol().empty() && + socket_->detectedTransportProtocol() != + Extensions::TransportSockets::TransportProtocolNames::get().RawBuffer) { + ENVOY_LOG(warn, + "internal connection does not support transport protocol {}, use raw buffer " + "transport socket. ", + socket_->detectedTransportProtocol()); + } + socket_->setDetectedTransportProtocol( + Extensions::TransportSockets::TransportProtocolNames::get().RawBuffer); // TODO(lambdai): add integration test // TODO: Address issues in wider scope. See https://github.com/envoyproxy/envoy/issues/8925 // Erase accept filter states because accept filters may not get the opportunity to clean up. @@ -854,7 +860,7 @@ void ConnectionHandlerImpl::ActiveInternalListener::shutdownListener() { } void ConnectionHandlerImpl::ActiveInternalListener::onNewSocket( - Network::ConnectionSocketPtr, Network::ConnectionSocketPtr socket) { + Network::ConnectionSocketPtr socket) { ActiveInternalSocketPtr active_socket = std::make_unique(*this, std::move(socket)); // Create and run the filters diff --git a/source/server/connection_handler_impl.h b/source/server/connection_handler_impl.h index fd87672c4971..392e3f8b4ebb 100644 --- a/source/server/connection_handler_impl.h +++ b/source/server/connection_handler_impl.h @@ -216,8 +216,7 @@ class ConnectionHandlerImpl : public Network::ConnectionHandler, // Network::InternalListenerCallbacks void setupNewConnection(Network::ConnectionPtr server_conn, Network::ConnectionSocketPtr socket) override; - void onNewSocket(Network::ConnectionSocketPtr socket, - Network::ConnectionSocketPtr server_conn) override; + void onNewSocket(Network::ConnectionSocketPtr socket) override; // ActiveListenerImplBase Network::Listener* listener() override { return internal_listener_.get(); } void pauseListening() override { internal_listener_->disable(); } diff --git a/test/common/network/BUILD b/test/common/network/BUILD index 0561fc177f01..f014f12c7d79 100644 --- a/test/common/network/BUILD +++ b/test/common/network/BUILD @@ -94,6 +94,7 @@ envoy_cc_test( "@envoy_api//envoy/config/core/v3:pkg_cc_proto", ], ) + envoy_cc_test( name = "closing_connection_impl_test", srcs = ["closing_connection_impl_test.cc"], @@ -117,6 +118,7 @@ envoy_cc_test( "@envoy_api//envoy/config/core/v3:pkg_cc_proto", ], ) + envoy_cc_test( name = "dns_impl_test", srcs = ["dns_impl_test.cc"], @@ -141,7 +143,6 @@ envoy_cc_test( ], ) - envoy_cc_test( name = "filter_manager_impl_test", srcs = ["filter_manager_impl_test.cc"], diff --git a/test/common/network/closing_connection_impl_test.cc b/test/common/network/closing_connection_impl_test.cc index ffe33ad56889..d3866e72c1d2 100644 --- a/test/common/network/closing_connection_impl_test.cc +++ b/test/common/network/closing_connection_impl_test.cc @@ -18,6 +18,7 @@ #include "source/common/network/_virtual_includes/address_lib/common/network/address_impl.h" #include "source/common/network/_virtual_includes/connection_lib/common/network/connection_impl.h" + #include "test/mocks/buffer/mocks.h" #include "test/mocks/event/mocks.h" #include "test/mocks/network/mocks.h" From 254daa4efa809831212136744b81abe84d0ab134 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Tue, 29 Sep 2020 07:21:05 +0000 Subject: [PATCH 034/100] basic internal client connection test Signed-off-by: Yuchen Dai --- source/common/event/dispatcher_impl.cc | 20 +++++++-- source/common/event/dispatcher_impl.h | 3 +- source/common/event/file_event_impl.h | 4 +- .../network/buffered_io_socket_handle_impl.cc | 2 +- source/common/network/connection_impl.cc | 12 +++++- source/common/network/connection_impl.h | 7 ++++ .../common/network/internal_listener_impl.cc | 10 ++--- source/common/network/listen_socket_impl.h | 5 +++ test/common/event/BUILD | 1 + test/common/event/dispatcher_impl_test.cc | 41 +++++++++++++++++++ .../network/closing_connection_impl_test.cc | 4 +- 11 files changed, 91 insertions(+), 18 deletions(-) diff --git a/source/common/event/dispatcher_impl.cc b/source/common/event/dispatcher_impl.cc index 3347242425fe..898995dd5321 100644 --- a/source/common/event/dispatcher_impl.cc +++ b/source/common/event/dispatcher_impl.cc @@ -7,6 +7,7 @@ #include #include +#include "common/network/raw_buffer_socket.h" #include "envoy/api/api.h" #include "envoy/network/listen_socket.h" #include "envoy/network/listener.h" @@ -137,10 +138,23 @@ DispatcherImpl::createInternalConnection(Network::Address::InstanceConstSharedPt return std::make_unique(*this, internal_address, local_address); } - Network::ClientConnectionPtr client_conn{}; - auto server_io_handle = std::make_unique(); - (iter->second)(internal_address, std::move(server_io_handle)); + auto client_io_handle_ = std::make_unique(); + auto server_io_handle_ = std::make_unique(); + client_io_handle_->setWritablePeer(server_io_handle_.get()); + server_io_handle_->setWritablePeer(client_io_handle_.get()); + + Network::RawBufferSocketFactory client_transport_socket_factory; + // ConnectionSocket conn_socket + auto client_conn_socket = std::make_unique( + std::move(client_io_handle_), local_address, internal_address); + auto server_conn_socket = std::make_unique( + std::move(server_io_handle_), internal_address, local_address); + auto client_conn = std::make_unique( + *this, internal_address, local_address, client_transport_socket_factory.createTransportSocket(nullptr), nullptr, + std::move(client_conn_socket)); + + (iter->second)(internal_address, std::move(server_conn_socket)); return client_conn; } diff --git a/source/common/event/dispatcher_impl.h b/source/common/event/dispatcher_impl.h index 8e14893d2688..e3230a9e45ca 100644 --- a/source/common/event/dispatcher_impl.h +++ b/source/common/event/dispatcher_impl.h @@ -12,6 +12,7 @@ #include "envoy/event/deferred_deletable.h" #include "envoy/event/dispatcher.h" #include "envoy/network/connection_handler.h" +#include "envoy/network/listen_socket.h" #include "envoy/stats/scope.h" #include "common/common/logger.h" @@ -39,7 +40,7 @@ class DispatcherImpl : Logger::Loggable, ~DispatcherImpl() override; using InternalConnectionCallback = std::function internal_socket)>; + std::unique_ptr internal_socket)>; /** * @return event_base& the libevent base. */ diff --git a/source/common/event/file_event_impl.h b/source/common/event/file_event_impl.h index ad1b93a6d022..e7346a9eab8a 100644 --- a/source/common/event/file_event_impl.h +++ b/source/common/event/file_event_impl.h @@ -120,8 +120,8 @@ class UserSpaceFileEventImpl : public FileEvent { SchedulableCallback& schedulable_cb, int& event_counter) : schedulable_(schedulable_cb), cb_([this, cb]() { auto all_events = getEventListener().triggeredEvents(); - auto epheral_events = getEventListener().getAndClearEpheralEvents(); - cb(all_events | epheral_events); + auto ephemeral_events = getEventListener().getAndClearEpheralEvents(); + cb(all_events | ephemeral_events); }), event_counter_(event_counter) { event_listener_.onEventEnabled(events); diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc index 4e24d8850e4e..17202e09d0a8 100644 --- a/source/common/network/buffered_io_socket_handle_impl.cc +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -28,7 +28,7 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::close() { write_shutdown_ = true; } closed_ = true; - return IoSocketError::ioResultSocketInvalidAddress(); + return Api::ioCallUint64ResultNoError(); } bool BufferedIoSocketHandleImpl::isOpen() const { return !closed_; } diff --git a/source/common/network/connection_impl.cc b/source/common/network/connection_impl.cc index d328f8c204a9..da201ea0ed91 100644 --- a/source/common/network/connection_impl.cc +++ b/source/common/network/connection_impl.cc @@ -707,7 +707,17 @@ ClientConnectionImpl::ClientConnectionImpl( const Network::Address::InstanceConstSharedPtr& source_address, Network::TransportSocketPtr&& transport_socket, const Network::ConnectionSocket::OptionsSharedPtr& options) - : ConnectionImpl(dispatcher, std::make_unique(remote_address, options), + : ClientConnectionImpl(dispatcher, remote_address, source_address, + std::move(transport_socket), options, std::make_unique(remote_address, options)) { +} + +ClientConnectionImpl::ClientConnectionImpl( + Event::Dispatcher& dispatcher, const Address::InstanceConstSharedPtr& remote_address, + const Network::Address::InstanceConstSharedPtr& source_address, + Network::TransportSocketPtr&& transport_socket, + const Network::ConnectionSocket::OptionsSharedPtr& options, + ConnectionSocketPtr conn_socket) + : ConnectionImpl(dispatcher, std::move(conn_socket), std::move(transport_socket), stream_info_, false), stream_info_(dispatcher.timeSource()) { // There are no meaningful socket options or source address semantics for diff --git a/source/common/network/connection_impl.h b/source/common/network/connection_impl.h index 06f0ef17afa7..039bb802cd8b 100644 --- a/source/common/network/connection_impl.h +++ b/source/common/network/connection_impl.h @@ -209,6 +209,13 @@ class ClientConnectionImpl : public ConnectionImpl, virtual public ClientConnect Network::TransportSocketPtr&& transport_socket, const Network::ConnectionSocket::OptionsSharedPtr& options); + ClientConnectionImpl(Event::Dispatcher& dispatcher, + const Address::InstanceConstSharedPtr& remote_address, + const Network::Address::InstanceConstSharedPtr& source_address, + Network::TransportSocketPtr&& transport_socket, + const Network::ConnectionSocket::OptionsSharedPtr& options, + ConnectionSocketPtr conn_socket); + // Network::ClientConnection void connect() override; diff --git a/source/common/network/internal_listener_impl.cc b/source/common/network/internal_listener_impl.cc index 1a8c670c18ef..617138099f56 100644 --- a/source/common/network/internal_listener_impl.cc +++ b/source/common/network/internal_listener_impl.cc @@ -24,13 +24,9 @@ namespace { void InternalListenerImpl::setupInternalListener(Event::DispatcherImpl& dispatcher) { dispatcher.registerInternalListener( internal_listener_id_, - [this](const Address::InstanceConstSharedPtr& client_address, - std::unique_ptr internal_socket) { - auto socket = std::make_unique( - std::move(internal_socket), - std::make_shared(internal_listener_id_), - client_address); - cb_.onNewSocket(std::move(socket)); + [this](const Address::InstanceConstSharedPtr&, + std::unique_ptr internal_conn_socket) { + cb_.onNewSocket(std::move(internal_conn_socket)); }); } diff --git a/source/common/network/listen_socket_impl.h b/source/common/network/listen_socket_impl.h index b79e0c31e142..1d50188430e2 100644 --- a/source/common/network/listen_socket_impl.h +++ b/source/common/network/listen_socket_impl.h @@ -207,6 +207,11 @@ class InternalConnectionSocketImpl : public ConnectionSocketImpl { const Address::InstanceConstSharedPtr& remote_address) : ConnectionSocketImpl(std::move(io_handle), local_address, remote_address) {} ~InternalConnectionSocketImpl() override = default; + + // TODO(lambdai): succeed on limited opitons. + Api::SysCallIntResult getSocketOption(int, int, void*, socklen_t*) const override { + return {0, 0}; + } }; // ConnectionSocket used with client connections. diff --git a/test/common/event/BUILD b/test/common/event/BUILD index b6032fe71825..2c36185208f2 100644 --- a/test/common/event/BUILD +++ b/test/common/event/BUILD @@ -19,6 +19,7 @@ envoy_cc_test( "//source/common/event:dispatcher_lib", "//source/common/stats:isolated_store_lib", "//test/mocks:common_lib", + "//test/mocks/network:connection_mocks", "//test/mocks/stats:stats_mocks", "//test/test_common:simulated_time_system_lib", "//test/test_common:test_runtime_lib", diff --git a/test/common/event/dispatcher_impl_test.cc b/test/common/event/dispatcher_impl_test.cc index c6c6a7a96272..c74ef4f84568 100644 --- a/test/common/event/dispatcher_impl_test.cc +++ b/test/common/event/dispatcher_impl_test.cc @@ -8,7 +8,10 @@ #include "common/event/dispatcher_impl.h" #include "common/event/timer_impl.h" #include "common/stats/isolated_store_impl.h" +#include "common/network/address_impl.h" +#include "common/network/connection_impl.h" +#include "test/mocks/network/connection.h" #include "test/mocks/common.h" #include "test/mocks/stats/mocks.h" #include "test/test_common/simulated_time_system.h" @@ -1147,6 +1150,44 @@ TEST_F(TimerUtilsTest, TimerValueConversion) { checkConversion(std::chrono::milliseconds(600014), 600, 14000); } +class InternalConnectionDispatcherTest : public testing::Test { +protected: + InternalConnectionDispatcherTest() + : api_(Api::createApiForTest()), dispatcher_(api_->allocateDispatcher("test_thread")), + dispatcher_impl_(static_cast(dispatcher_.get())) {} + + Api::ApiPtr api_; + DispatcherPtr dispatcher_; + DispatcherImpl* dispatcher_impl_; + const std::shared_ptr remote_address_{ + std::make_shared("listener_addr")}; + const std::shared_ptr source_address_{ + std::make_shared("local_addr")}; +}; + +TEST_F(InternalConnectionDispatcherTest, CreateInternalClientConnection) { + std::unique_ptr server_conn_socket; + auto socket_save_callback = + [&server_conn_socket](const Network::Address::InstanceConstSharedPtr&, + std::unique_ptr internal_socket) { + server_conn_socket = std::move(internal_socket); + }; + dispatcher_impl_->registerInternalListener(remote_address_->asString(), socket_save_callback); + auto client = dispatcher_->createInternalConnection(remote_address_, source_address_); + + Network::MockConnectionCallbacks client_callbacks; + client->addConnectionCallbacks(client_callbacks); + EXPECT_EQ(Network::Connection::State::Open, client->state()); + + EXPECT_CALL(client_callbacks, onEvent(Network::ConnectionEvent::LocalClose)).Times(1); + client->close(Network::ConnectionCloseType::NoFlush); + EXPECT_EQ(Network::Connection::State::Closed, client->state()); + + EXPECT_TRUE(server_conn_socket->ioHandle().isOpen()); + server_conn_socket->ioHandle().close(); + EXPECT_FALSE(server_conn_socket->ioHandle().isOpen()); +} + } // namespace } // namespace Event } // namespace Envoy diff --git a/test/common/network/closing_connection_impl_test.cc b/test/common/network/closing_connection_impl_test.cc index d3866e72c1d2..20513ec3cf88 100644 --- a/test/common/network/closing_connection_impl_test.cc +++ b/test/common/network/closing_connection_impl_test.cc @@ -16,9 +16,7 @@ #include "common/network/utility.h" #include "common/runtime/runtime_impl.h" -#include "source/common/network/_virtual_includes/address_lib/common/network/address_impl.h" -#include "source/common/network/_virtual_includes/connection_lib/common/network/connection_impl.h" - +#include "test/mocks/network/connection.h" #include "test/mocks/buffer/mocks.h" #include "test/mocks/event/mocks.h" #include "test/mocks/network/mocks.h" From 568e42b09255971002bc435452b6773ced5392b8 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Tue, 29 Sep 2020 09:39:23 +0000 Subject: [PATCH 035/100] fix connect probe and add client write test Signed-off-by: Yuchen Dai --- source/common/network/listen_socket_impl.h | 16 ++++- test/common/event/dispatcher_impl_test.cc | 68 ++++++++++++++++++++++ 2 files changed, 81 insertions(+), 3 deletions(-) diff --git a/source/common/network/listen_socket_impl.h b/source/common/network/listen_socket_impl.h index 1d50188430e2..4501d86cb964 100644 --- a/source/common/network/listen_socket_impl.h +++ b/source/common/network/listen_socket_impl.h @@ -3,7 +3,9 @@ #include #include #include +#include +#include "common/common/logger.h" #include "envoy/common/platform.h" #include "envoy/network/connection.h" #include "envoy/network/listen_socket.h" @@ -208,9 +210,17 @@ class InternalConnectionSocketImpl : public ConnectionSocketImpl { : ConnectionSocketImpl(std::move(io_handle), local_address, remote_address) {} ~InternalConnectionSocketImpl() override = default; - // TODO(lambdai): succeed on limited opitons. - Api::SysCallIntResult getSocketOption(int, int, void*, socklen_t*) const override { - return {0, 0}; + // TODO(lambdai): succeed on limited options. + Api::SysCallIntResult getSocketOption(int level, int optname, void* ptr, socklen_t* len) const override { + if (level == SOL_SOCKET && optname == SO_ERROR) { + memset(ptr, 0, static_cast(*len)); + *(reinterpret_cast(ptr)) = 0; + return {0, 0}; + } else { + ENVOY_LOG_MISC(warn, "unsupported socket option level={} optname={}", level, optname); + return {0, EFAULT}; + } + } }; diff --git a/test/common/event/dispatcher_impl_test.cc b/test/common/event/dispatcher_impl_test.cc index c74ef4f84568..ece54adaaaa4 100644 --- a/test/common/event/dispatcher_impl_test.cc +++ b/test/common/event/dispatcher_impl_test.cc @@ -1,5 +1,6 @@ #include +#include "common/buffer/buffer_impl.h" #include "envoy/thread/thread.h" #include "common/api/api_impl.h" @@ -1188,6 +1189,73 @@ TEST_F(InternalConnectionDispatcherTest, CreateInternalClientConnection) { EXPECT_FALSE(server_conn_socket->ioHandle().isOpen()); } +TEST_F(InternalConnectionDispatcherTest, InternalClientConnectionAndConnect) { + std::unique_ptr server_conn_socket; + auto socket_save_callback = + [&server_conn_socket](const Network::Address::InstanceConstSharedPtr&, + std::unique_ptr internal_socket) { + server_conn_socket = std::move(internal_socket); + }; + dispatcher_impl_->registerInternalListener(remote_address_->asString(), socket_save_callback); + auto client = dispatcher_->createInternalConnection(remote_address_, source_address_); + + Network::MockConnectionCallbacks client_callbacks; + client->addConnectionCallbacks(client_callbacks); + EXPECT_EQ(Network::Connection::State::Open, client->state()); + + EXPECT_CALL(client_callbacks, onEvent(Network::ConnectionEvent::Connected)).Times(1); + dispatcher_impl_->run(Dispatcher::RunType::NonBlock); + + EXPECT_CALL(client_callbacks, onEvent(Network::ConnectionEvent::LocalClose)).Times(1); + client->close(Network::ConnectionCloseType::NoFlush); + EXPECT_EQ(Network::Connection::State::Closed, client->state()); + + EXPECT_TRUE(server_conn_socket->ioHandle().isOpen()); + server_conn_socket->ioHandle().close(); + EXPECT_FALSE(server_conn_socket->ioHandle().isOpen()); +} + +TEST_F(InternalConnectionDispatcherTest, InternalClientConnectionBasicReadWrite) { + std::unique_ptr server_conn_socket; + auto socket_save_callback = + [&server_conn_socket](const Network::Address::InstanceConstSharedPtr&, + std::unique_ptr internal_socket) { + server_conn_socket = std::move(internal_socket); + }; + dispatcher_impl_->registerInternalListener(remote_address_->asString(), socket_save_callback); + auto client = dispatcher_->createInternalConnection(remote_address_, source_address_); + + Network::MockConnectionCallbacks client_callbacks; + client->addConnectionCallbacks(client_callbacks); + EXPECT_EQ(Network::Connection::State::Open, client->state()); + + EXPECT_CALL(client_callbacks, onEvent(Network::ConnectionEvent::Connected)).Times(1); + dispatcher_impl_->run(Dispatcher::RunType::NonBlock); + + // Client connection write. + { + Buffer::OwnedImpl buf; + buf.add("hello"); + // Write to client connection write buffer. + client->write(buf, false); + // Transport socket write from connection write buffer to server connection buffer. + dispatcher_impl_->run(Dispatcher::RunType::NonBlock); + } + + // Server socket read. + { + Buffer::OwnedImpl buf; + Buffer::RawSlice slice; + buf.reserve(1024, &slice, 1); + auto res = server_conn_socket->ioHandle().readv(1024, &slice, 1); + EXPECT_TRUE(res.ok()); + EXPECT_EQ("hello", absl::string_view(static_cast(slice.mem_), res.rc_)); + } + + EXPECT_CALL(client_callbacks, onEvent(Network::ConnectionEvent::LocalClose)).Times(1); + client->close(Network::ConnectionCloseType::NoFlush); + server_conn_socket->ioHandle().close(); +} } // namespace } // namespace Event } // namespace Envoy From 953326b5053f63dd2ca68cbc0799186514cff33a Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Wed, 30 Sep 2020 20:12:06 +0000 Subject: [PATCH 036/100] various fixes: client id on dispatcher, StreamListener for active Internal and Tcp listener Signed-off-by: Yuchen Dai --- include/envoy/network/listener.h | 5 +- source/common/event/dispatcher_impl.cc | 18 ++++- source/common/network/base_listener_impl.cc | 18 +++-- source/common/network/base_listener_impl.h | 6 +- .../common/network/internal_listener_impl.cc | 4 +- .../common/network/internal_listener_impl.h | 4 +- source/common/upstream/upstream_impl.cc | 15 ++-- source/server/admin/admin.h | 3 + source/server/connection_handler_impl.cc | 56 +++++++------- source/server/connection_handler_impl.h | 74 +++++++++++++++++-- source/server/listener_impl.cc | 2 + source/server/listener_impl.h | 4 + test/config/utility.cc | 4 + .../proxy_protocol_regression_test.cc | 3 + .../proxy_protocol/proxy_protocol_test.cc | 6 ++ test/integration/BUILD | 31 ++++++++ test/integration/base_integration_test.cc | 2 +- test/integration/fake_upstream.h | 3 + test/server/connection_handler_test.cc | 3 + 19 files changed, 207 insertions(+), 54 deletions(-) diff --git a/include/envoy/network/listener.h b/include/envoy/network/listener.h index 56a820b227fc..8459797a7212 100644 --- a/include/envoy/network/listener.h +++ b/include/envoy/network/listener.h @@ -146,7 +146,10 @@ class ListenerConfig { */ virtual UdpPacketWriterFactoryOptRef udpPacketWriterFactory() PURE; - virtual bool isInternalListener() { return false; } + /** + * @return true if this listener is internal listener. + */ + virtual bool isInternalListener() PURE; /** * @return the ``UdpListenerWorkerRouter`` for this listener. This will diff --git a/source/common/event/dispatcher_impl.cc b/source/common/event/dispatcher_impl.cc index 898995dd5321..492a76bb3163 100644 --- a/source/common/event/dispatcher_impl.cc +++ b/source/common/event/dispatcher_impl.cc @@ -7,6 +7,7 @@ #include #include +#include "common/network/address_impl.h" #include "common/network/raw_buffer_socket.h" #include "envoy/api/api.h" #include "envoy/network/listen_socket.h" @@ -120,6 +121,14 @@ DispatcherImpl::createClientConnection(Network::Address::InstanceConstSharedPtr std::move(transport_socket), options); } +namespace { +Network::Address::InstanceConstSharedPtr +nextClientAddress(const Network::Address::InstanceConstSharedPtr& server_address) { + uint64_t id = 0; + return std::make_shared(absl::StrCat(server_address->asStringView(), "_", ++id)); +} +} // namespace + Network::ClientConnectionPtr DispatcherImpl::createInternalConnection(Network::Address::InstanceConstSharedPtr internal_address, Network::Address::InstanceConstSharedPtr local_address) { @@ -127,6 +136,9 @@ DispatcherImpl::createInternalConnection(Network::Address::InstanceConstSharedPt if (internal_address == nullptr) { return nullptr; } + if (local_address == nullptr) { + local_address = nextClientAddress(internal_address); + } // Find the internal listener callback. The listener will setup the server connection. auto iter = internal_listeners_.find(internal_address->asString()); for (const auto& [name, _] : internal_listeners_) { @@ -150,8 +162,12 @@ DispatcherImpl::createInternalConnection(Network::Address::InstanceConstSharedPt std::move(client_io_handle_), local_address, internal_address); auto server_conn_socket = std::make_unique( std::move(server_io_handle_), internal_address, local_address); + ENVOY_LOG_MISC(debug, "lambdai: internal address {}", internal_address->asString()); + ENVOY_LOG_MISC(debug, "lambdai: client address {}", local_address->asString()); + auto client_conn = std::make_unique( - *this, internal_address, local_address, client_transport_socket_factory.createTransportSocket(nullptr), nullptr, + *this, internal_address, local_address, + client_transport_socket_factory.createTransportSocket(nullptr), nullptr, std::move(client_conn_socket)); (iter->second)(internal_address, std::move(server_conn_socket)); diff --git a/source/common/network/base_listener_impl.cc b/source/common/network/base_listener_impl.cc index e1adf6b930ec..bc50038bbbf9 100644 --- a/source/common/network/base_listener_impl.cc +++ b/source/common/network/base_listener_impl.cc @@ -15,14 +15,18 @@ namespace Envoy { namespace Network { -BaseListenerImpl::BaseListenerImpl(Event::DispatcherImpl& dispatcher, SocketSharedPtr socket) - : local_address_(nullptr), dispatcher_(dispatcher), socket_(std::move(socket)) { - const auto ip = socket_->localAddress()->ip(); +BaseListenerImpl::BaseListenerImpl(Event::DispatcherImpl& dispatcher, SocketSharedPtr socket, + const Address::InstanceConstSharedPtr& local_address) + : local_address_(local_address), dispatcher_(dispatcher), socket_(std::move(socket)) { + + if (socket_ != nullptr) { + const auto ip = socket_->localAddress()->ip(); - // Only use the listen socket's local address for new connections if it is not the all hosts - // address (e.g., 0.0.0.0 for IPv4). - if (!(ip && ip->isAnyAddress())) { - local_address_ = socket_->localAddress(); + // Only use the listen socket's local address for new connections if it is not the all hosts + // address (e.g., 0.0.0.0 for IPv4). + if (!(ip && ip->isAnyAddress())) { + local_address_ = socket_->localAddress(); + } } } diff --git a/source/common/network/base_listener_impl.h b/source/common/network/base_listener_impl.h index 2cf97dea86c4..0f09bdfd1311 100644 --- a/source/common/network/base_listener_impl.h +++ b/source/common/network/base_listener_impl.h @@ -15,9 +15,11 @@ class BaseListenerImpl : public virtual Listener { public: /** * @param socket the listening socket for this listener. It might be shared - * with other listeners if all listeners use single listen socket. + * with other listeners if all listeners use single listen socket. It could be nullptr for + * internal listener. */ - BaseListenerImpl(Event::DispatcherImpl& dispatcher, SocketSharedPtr socket); + BaseListenerImpl(Event::DispatcherImpl& dispatcher, SocketSharedPtr socket, + const Address::InstanceConstSharedPtr& local_address = nullptr); protected: Address::InstanceConstSharedPtr local_address_; diff --git a/source/common/network/internal_listener_impl.cc b/source/common/network/internal_listener_impl.cc index 617138099f56..86c5781da8ad 100644 --- a/source/common/network/internal_listener_impl.cc +++ b/source/common/network/internal_listener_impl.cc @@ -21,8 +21,8 @@ namespace Network { namespace { // uint64_t next_internal_connection_id = 0; } -void InternalListenerImpl::setupInternalListener(Event::DispatcherImpl& dispatcher) { - dispatcher.registerInternalListener( +void InternalListenerImpl::setupInternalListener() { + dispatcher_.registerInternalListener( internal_listener_id_, [this](const Address::InstanceConstSharedPtr&, std::unique_ptr internal_conn_socket) { diff --git a/source/common/network/internal_listener_impl.h b/source/common/network/internal_listener_impl.h index a431358f165c..429268ed1379 100644 --- a/source/common/network/internal_listener_impl.h +++ b/source/common/network/internal_listener_impl.h @@ -18,10 +18,8 @@ class InternalListenerImpl : public BaseListenerImpl { void disable() override; void enable() override; -protected: - void setupInternalListener(Event::DispatcherImpl& dispatcher); + void setupInternalListener(); - // TODO(lambdai): make it private public: std::string internal_listener_id_; Event::DispatcherImpl& dispatcher_; diff --git a/source/common/upstream/upstream_impl.cc b/source/common/upstream/upstream_impl.cc index e7a5c129a06b..745ae1ff2b3e 100644 --- a/source/common/upstream/upstream_impl.cc +++ b/source/common/upstream/upstream_impl.cc @@ -346,11 +346,16 @@ HostImpl::createConnection(Event::Dispatcher& dispatcher, const ClusterInfo& clu } else { connection_options = options; } - ASSERT(!address->envoyInternalAddress()); - Network::ClientConnectionPtr connection = dispatcher.createClientConnection( - address, cluster.sourceAddress(), - socket_factory.createTransportSocket(std::move(transport_socket_options)), - connection_options); + Network::ClientConnectionPtr connection; + if (address->envoyInternalAddress()) { + ASSERT(cluster.sourceAddress() == nullptr || cluster.sourceAddress()->envoyInternalAddress()); + connection = dispatcher.createInternalConnection(address, cluster.sourceAddress()); + } else { + connection = dispatcher.createClientConnection( + address, cluster.sourceAddress(), + socket_factory.createTransportSocket(std::move(transport_socket_options)), + connection_options); + } connection->setBufferLimits(cluster.perConnectionBufferLimitBytes()); cluster.createNetworkFilterChain(*connection); return connection; diff --git a/source/server/admin/admin.h b/source/server/admin/admin.h index 945885ac3909..f30d164835a2 100644 --- a/source/server/admin/admin.h +++ b/source/server/admin/admin.h @@ -345,6 +345,9 @@ class AdminImpl : public Admin, Network::UdpPacketWriterFactoryOptRef udpPacketWriterFactory() override { NOT_REACHED_GCOVR_EXCL_LINE; } + bool isInternalListener() override { + return false; + } Network::UdpListenerWorkerRouterOptRef udpListenerWorkerRouter() override { NOT_REACHED_GCOVR_EXCL_LINE; } diff --git a/source/server/connection_handler_impl.cc b/source/server/connection_handler_impl.cc index 1a02bc2ad974..ac86ac4fb9d5 100644 --- a/source/server/connection_handler_impl.cc +++ b/source/server/connection_handler_impl.cc @@ -43,7 +43,18 @@ void ConnectionHandlerImpl::addListener(absl::optional overridden_list Network::ListenerConfig& config) { ActiveListenerDetails details; if (config.isInternalListener()) { - // TODO(lambdai): register internal listener here. + if (overridden_listener.has_value()) { + for (auto& listener : listeners_) { + if (listener.second.listener_->listenerTag() == overridden_listener) { + listener.second.tcpListener()->get().updateListenerConfig(config); + return; + } + } + } + auto active_internal_listener = std::make_unique(*this, config); + active_internal_listener->internal_listener_->setupInternalListener(); + details.typed_listener_ = *active_internal_listener; + details.listener_ = std::move(active_internal_listener); } else if (config.listenSocketFactory().socketType() == Network::Socket::Type::Stream) { if (overridden_listener.has_value()) { for (auto& listener : listeners_) { @@ -465,6 +476,10 @@ void ConnectionHandlerImpl::ActiveTcpListener::newConnection( LinkedList::moveIntoList(std::move(active_connection), active_connections.connections_); } } +Stats::TimespanPtr ConnectionHandlerImpl::ActiveTcpListener::newTimespan(TimeSource& time_source) { + return std::make_unique(stats_.downstream_cx_length_ms_, + time_source); +} ConnectionHandlerImpl::ActiveConnections& ConnectionHandlerImpl::ActiveTcpListener::getOrCreateActiveConnections( @@ -534,7 +549,7 @@ void ConnectionHandlerImpl::ActiveTcpListener::post(Network::ConnectionSocketPtr } ConnectionHandlerImpl::ActiveConnections::ActiveConnections( - ConnectionHandlerImpl::ActiveTcpListener& listener, const Network::FilterChain& filter_chain) + ConnectionHandlerImpl::StreamListener& listener, const Network::FilterChain& filter_chain) : listener_(listener), filter_chain_(filter_chain) {} ConnectionHandlerImpl::ActiveConnections::~ActiveConnections() { @@ -547,36 +562,17 @@ ConnectionHandlerImpl::ActiveTcpConnection::ActiveTcpConnection( TimeSource& time_source, std::unique_ptr&& stream_info) : stream_info_(std::move(stream_info)), active_connections_(active_connections), connection_(std::move(new_connection)), - conn_length_(new Stats::HistogramCompletableTimespanImpl( - active_connections_.listener_.stats_.downstream_cx_length_ms_, time_source)) { + conn_length_(active_connections_.listener_.newTimespan(time_source)) { // We just universally set no delay on connections. Theoretically we might at some point want // to make this configurable. connection_->noDelay(true); - auto& listener = active_connections_.listener_; - listener.stats_.downstream_cx_total_.inc(); - listener.stats_.downstream_cx_active_.inc(); - listener.per_worker_stats_.downstream_cx_total_.inc(); - listener.per_worker_stats_.downstream_cx_active_.inc(); - - // Active connections on the handler (not listener). The per listener connections have already - // been incremented at this point either via the connection balancer or in the socket accept - // path if there is no configured balancer. - ++listener.parent_.num_handler_connections_; + active_connections_.listener_.onNewConnection(); } ConnectionHandlerImpl::ActiveTcpConnection::~ActiveTcpConnection() { - emitLogs(*active_connections_.listener_.config_, *stream_info_); - auto& listener = active_connections_.listener_; - listener.stats_.downstream_cx_active_.dec(); - listener.stats_.downstream_cx_destroy_.inc(); - listener.per_worker_stats_.downstream_cx_active_.dec(); + emitLogs(active_connections_.listener_.listenerConfig(), *stream_info_); conn_length_->complete(); - - // Active listener connections (not handler). - listener.decNumConnections(); - - // Active handler connections (not listener). - listener.parent_.decNumConnections(); + active_connections_.listener_.onDestroyConnection(); } ConnectionHandlerImpl::ActiveTcpListenerOptRef @@ -816,6 +812,10 @@ void ConnectionHandlerImpl::ActiveInternalSocket::newConnection() { ConnectionHandlerImpl::ActiveInternalListener::ActiveInternalListener( ConnectionHandlerImpl& parent, Network::ListenerConfig& config) : ConnectionHandlerImpl::ActiveListenerImplBase(parent, &config), parent_(parent), + internal_listener_(std::make_unique( + // TODO(lambdai): promote createInternalConnection to dispatcher interface. + dynamic_cast(parent_.dispatcher_), + config.listenSocketFactory().localAddress()->asString(), *this)), listener_filters_timeout_(config.listenerFiltersTimeout()), continue_on_listener_filters_timeout_(config.continueOnListenerFiltersTimeout()) {} @@ -880,6 +880,12 @@ void ConnectionHandlerImpl::ActiveInternalListener::onNewSocket( } } +Stats::TimespanPtr +ConnectionHandlerImpl::ActiveInternalListener::newTimespan(TimeSource& time_source) { + return std::make_unique(stats_.downstream_cx_length_ms_, + time_source); +} + // Copied from newConnection(). Invoked by SetupPipeListener. void ConnectionHandlerImpl::ActiveInternalListener::setupNewConnection( Network::ConnectionPtr server_conn, Network::ConnectionSocketPtr socket) { diff --git a/source/server/connection_handler_impl.h b/source/server/connection_handler_impl.h index 392e3f8b4ebb..90803e39c25d 100644 --- a/source/server/connection_handler_impl.h +++ b/source/server/connection_handler_impl.h @@ -105,6 +105,18 @@ class ConnectionHandlerImpl : public Network::ConnectionHandler, private: struct ActiveTcpConnection; using ActiveTcpConnectionPtr = std::unique_ptr; + class StreamListener { + public: + virtual ~StreamListener() = default; + // virtual ListenerStats& listenerStats() PURE; + // virtual PerHandlerListenerStats& per_worker_stats_() PURE; + virtual void onNewConnection() PURE; + virtual void onDestroyConnection() PURE; + virtual Stats::TimespanPtr newTimespan(TimeSource& time_source) PURE; + virtual Network::ListenerConfig& listenerConfig() PURE; + virtual void removeConnection(ActiveTcpConnection& conn) PURE; + }; + struct ActiveTcpSocket; using ActiveTcpSocketPtr = std::unique_ptr; class ActiveConnections; @@ -117,6 +129,7 @@ class ConnectionHandlerImpl : public Network::ConnectionHandler, */ class ActiveTcpListener : public Network::TcpListenerCallbacks, public ActiveListenerImplBase, + public StreamListener, public Network::BalancedConnectionHandler { public: ActiveTcpListener(ConnectionHandlerImpl& parent, Network::ListenerConfig& config); @@ -146,6 +159,30 @@ class ConnectionHandlerImpl : public Network::ConnectionHandler, void resumeListening() override { listener_->enable(); } void shutdownListener() override { listener_.reset(); } + // StreamListener + void onNewConnection() override { + stats_.downstream_cx_total_.inc(); + stats_.downstream_cx_active_.inc(); + per_worker_stats_.downstream_cx_total_.inc(); + per_worker_stats_.downstream_cx_active_.inc(); + // Active connections on the handler (not listener). The per listener connections have already + // been incremented at this point either via the connection balancer or in the socket accept + // path if there is no configured balancer. + ++parent_.num_handler_connections_; + } + void onDestroyConnection() override { + stats_.downstream_cx_active_.dec(); + stats_.downstream_cx_destroy_.inc(); + per_worker_stats_.downstream_cx_active_.dec(); + // Active listener connections (not handler). + decNumConnections(); + // Active handler connections (not listener). + parent_.decNumConnections(); + } + Network::ListenerConfig& listenerConfig() override { return *config_; } + + Stats::TimespanPtr newTimespan(TimeSource& time_source) override; + // Network::BalancedConnectionHandler uint64_t numConnections() const override { return num_listener_connections_; } void incNumConnections() override { @@ -158,7 +195,7 @@ class ConnectionHandlerImpl : public Network::ConnectionHandler, * Remove and destroy an active connection. * @param connection supplies the connection to remove. */ - void removeConnection(ActiveTcpConnection& connection); + void removeConnection(ActiveTcpConnection& connection) override; /** * Create a new connection from a socket accepted by the listener. @@ -201,7 +238,8 @@ class ConnectionHandlerImpl : public Network::ConnectionHandler, * Wrapper for an active internal listener owned by this handler. */ class ActiveInternalListener : public Network::InternalListenerCallbacks, - public ActiveListenerImplBase { + public ActiveListenerImplBase, + public StreamListener { public: ActiveInternalListener(ConnectionHandlerImpl& parent, Network::ListenerConfig& config); @@ -223,11 +261,29 @@ class ConnectionHandlerImpl : public Network::ConnectionHandler, void resumeListening() override { internal_listener_->enable(); } void shutdownListener() override; + // StreamListener + void onNewConnection() override { + stats_.downstream_cx_total_.inc(); + stats_.downstream_cx_active_.inc(); + per_worker_stats_.downstream_cx_total_.inc(); + per_worker_stats_.downstream_cx_active_.inc(); + ++parent_.num_handler_connections_; + } + void onDestroyConnection() override { + stats_.downstream_cx_active_.dec(); + stats_.downstream_cx_destroy_.inc(); + per_worker_stats_.downstream_cx_active_.dec(); + decNumConnections(); + parent_.decNumConnections(); + } + Network::ListenerConfig& listenerConfig() override { return *config_; } + Stats::TimespanPtr newTimespan(TimeSource& time_source) override; + /** * Remove and destroy an active connection. * @param connection supplies the connection to remove. */ - void removeConnection(ActiveTcpConnection& connection); + void removeConnection(ActiveTcpConnection& connection) override; /** * Create a new connection from a socket accepted by the listener. @@ -271,11 +327,11 @@ class ConnectionHandlerImpl : public Network::ConnectionHandler, */ class ActiveConnections : public Event::DeferredDeletable { public: - ActiveConnections(ActiveTcpListener& listener, const Network::FilterChain& filter_chain); + ActiveConnections(StreamListener& listener, const Network::FilterChain& filter_chain); ~ActiveConnections() override; - // listener filter chain pair is the owner of the connections - ActiveTcpListener& listener_; + // Listener filter chain pair is the owner of the connections. + StreamListener& listener_; const Network::FilterChain& filter_chain_; // Owned connections std::list connections_; @@ -457,18 +513,22 @@ class ConnectionHandlerImpl : public Network::ConnectionHandler, using ActiveTcpListenerOptRef = absl::optional>; using UdpListenerCallbacksOptRef = absl::optional>; + using ActiveInternalListenerOptRef = + absl::optional>; struct ActiveListenerDetails { // Strong pointer to the listener, whether TCP, UDP, QUIC, etc. Network::ConnectionHandler::ActiveListenerPtr listener_; absl::variant, - std::reference_wrapper> + std::reference_wrapper, + std::reference_wrapper> typed_listener_; // Helpers for accessing the data in the variant for cleaner code. ActiveTcpListenerOptRef tcpListener(); UdpListenerCallbacksOptRef udpListener(); + ActiveInternalListenerOptRef internalListener(); }; using ActiveListenerDetailsOptRef = absl::optional>; diff --git a/source/server/listener_impl.cc b/source/server/listener_impl.cc index 21cfbf3d38e0..450b578f56e5 100644 --- a/source/server/listener_impl.cc +++ b/source/server/listener_impl.cc @@ -238,6 +238,7 @@ ListenerImpl::ListenerImpl(const envoy::config::listener::v3::Listener& config, workers_started_(workers_started), hash_(hash), tcp_backlog_size_( PROTOBUF_GET_WRAPPED_OR_DEFAULT(config, tcp_backlog_size, ENVOY_TCP_BACKLOG_SIZE)), + is_internal_listener_(config.has_internal_listener()), validation_visitor_( added_via_api_ ? parent_.server_.messageValidationContext().dynamicValidationVisitor() : parent_.server_.messageValidationContext().staticValidationVisitor()), @@ -317,6 +318,7 @@ ListenerImpl::ListenerImpl(ListenerImpl& origin, workers_started_(workers_started), hash_(hash), tcp_backlog_size_( PROTOBUF_GET_WRAPPED_OR_DEFAULT(config, tcp_backlog_size, ENVOY_TCP_BACKLOG_SIZE)), + is_internal_listener_(config.has_internal_listener()), validation_visitor_( added_via_api_ ? parent_.server_.messageValidationContext().dynamicValidationVisitor() : parent_.server_.messageValidationContext().staticValidationVisitor()), diff --git a/source/server/listener_impl.h b/source/server/listener_impl.h index 888b622bf6ae..f1d29f591c46 100644 --- a/source/server/listener_impl.h +++ b/source/server/listener_impl.h @@ -309,6 +309,9 @@ class ListenerImpl final : public Network::ListenerConfig, Network::UdpPacketWriterFactoryOptRef udpPacketWriterFactory() override { return Network::UdpPacketWriterFactoryOptRef(std::ref(*udp_writer_factory_)); } + bool isInternalListener() override { + return is_internal_listener_; + } Network::UdpListenerWorkerRouterOptRef udpListenerWorkerRouter() override { return udp_listener_worker_router_ ? Network::UdpListenerWorkerRouterOptRef(*udp_listener_worker_router_) @@ -382,6 +385,7 @@ class ListenerImpl final : public Network::ListenerConfig, const bool workers_started_; const uint64_t hash_; const uint32_t tcp_backlog_size_; + const bool is_internal_listener_; ProtobufMessage::ValidationVisitor& validation_visitor_; // A target is added to Server's InitManager if workers_started_ is false. diff --git a/test/config/utility.cc b/test/config/utility.cc index b248c80d5600..bbdf1ba55ef2 100644 --- a/test/config/utility.cc +++ b/test/config/utility.cc @@ -529,6 +529,10 @@ ConfigHelper::ConfigHelper(const Network::Address::IpVersion version, Api::Api& auto* static_resources = bootstrap_.mutable_static_resources(); for (int i = 0; i < static_resources->listeners_size(); ++i) { auto* listener = static_resources->mutable_listeners(i); + // Not need to amend internal address and we need to skip the below implicit address mutation helper. + if (listener->mutable_address()->has_envoy_internal_address()) { + continue; + } auto* listener_socket_addr = listener->mutable_address()->mutable_socket_address(); if (listener_socket_addr->address() == "0.0.0.0" || listener_socket_addr->address() == "::") { listener_socket_addr->set_address(Network::Test::getAnyAddressString(version)); diff --git a/test/extensions/common/proxy_protocol/proxy_protocol_regression_test.cc b/test/extensions/common/proxy_protocol/proxy_protocol_regression_test.cc index 65f948f22011..1603f32f9ff8 100644 --- a/test/extensions/common/proxy_protocol/proxy_protocol_regression_test.cc +++ b/test/extensions/common/proxy_protocol/proxy_protocol_regression_test.cc @@ -72,6 +72,9 @@ class ProxyProtocolRegressionTest : public testing::TestWithParam, Network::UdpPacketWriterFactoryOptRef udpPacketWriterFactory() override { return Network::UdpPacketWriterFactoryOptRef(std::ref(*udp_writer_factory_)); } + bool isInternalListener() override { + return false; + } Network::UdpListenerWorkerRouterOptRef udpListenerWorkerRouter() override { return udp_listener_worker_router_; } diff --git a/test/server/connection_handler_test.cc b/test/server/connection_handler_test.cc index ee81e2d1cfaa..9b7254a42bd9 100644 --- a/test/server/connection_handler_test.cc +++ b/test/server/connection_handler_test.cc @@ -111,6 +111,9 @@ class ConnectionHandlerTest : public testing::Test, protected Logger::Loggable Date: Thu, 1 Oct 2020 06:55:18 +0000 Subject: [PATCH 037/100] adding back chain tcp proxy integration test Signed-off-by: Yuchen Dai --- source/common/event/file_event_impl.h | 15 +- source/common/event/schedulable_cb_impl.cc | 5 +- .../network/buffered_io_socket_handle_impl.cc | 6 +- .../network/buffered_io_socket_handle_impl.h | 6 +- source/common/network/connection_impl.cc | 2 +- source/common/network/listen_socket_impl.h | 14 +- source/server/connection_handler_impl.cc | 31 +- source/server/connection_handler_impl.h | 8 + .../internal_listener_integration_test.cc | 403 ++++++++++++++++++ 9 files changed, 473 insertions(+), 17 deletions(-) create mode 100644 test/integration/internal_listener_integration_test.cc diff --git a/source/common/event/file_event_impl.h b/source/common/event/file_event_impl.h index e7346a9eab8a..f9c55dd4b935 100644 --- a/source/common/event/file_event_impl.h +++ b/source/common/event/file_event_impl.h @@ -66,8 +66,13 @@ class EventListener { class DefaultEventListener : public EventListener { public: ~DefaultEventListener() override = default; - uint32_t triggeredEvents() override { return pending_events_ & (~Event::FileReadyType::Closed); } - void onEventEnabled(uint32_t enabled_events) override { pending_events_ = enabled_events; } + uint32_t triggeredEvents() override { + ENVOY_LOG_MISC(debug, "lambdai: user file event listener triggered events {} on {} and schedule next", pending_events_, static_cast(this)); + + return pending_events_ & (~Event::FileReadyType::Closed); } + void onEventEnabled(uint32_t enabled_events) override { + ENVOY_LOG_MISC(debug, "lambdai: user file event listener set enabled events {} on {} and schedule next", pending_events_, static_cast(this)); + pending_events_ = enabled_events; } void onEventActivated(uint32_t activated_events) override { ephermal_events_ |= activated_events; } @@ -97,7 +102,7 @@ class UserSpaceFileEventImpl : public FileEvent { // Event::FileEvent void activate(uint32_t events) override { - event_listener_.onEventEnabled(events); + event_listener_.onEventActivated(events); if (!schedulable_.enabled()) { schedulable_.scheduleCallbackNextIteration(); } @@ -107,7 +112,10 @@ class UserSpaceFileEventImpl : public FileEvent { event_listener_.onEventEnabled(events); if (!schedulable_.enabled()) { schedulable_.scheduleCallbackNextIteration(); + ENVOY_LOG_MISC(debug, "lambdai: user file event setEnabled {} on {} and schedule next", events, static_cast(this)); + return; } + ENVOY_LOG_MISC(debug, "lambdai: user file event setEnabled {} on {} and but not schedule next", events, static_cast(this)); } EventListener& getEventListener() { return event_listener_; } @@ -121,6 +129,7 @@ class UserSpaceFileEventImpl : public FileEvent { : schedulable_(schedulable_cb), cb_([this, cb]() { auto all_events = getEventListener().triggeredEvents(); auto ephemeral_events = getEventListener().getAndClearEpheralEvents(); + ENVOY_LOG_MISC(debug, "lambdai: us event {} cb allevents = {}, ephermal events = {}", static_cast(this), all_events, ephemeral_events); cb(all_events | ephemeral_events); }), event_counter_(event_counter) { diff --git a/source/common/event/schedulable_cb_impl.cc b/source/common/event/schedulable_cb_impl.cc index 2109af17972e..81f4efacb476 100644 --- a/source/common/event/schedulable_cb_impl.cc +++ b/source/common/event/schedulable_cb_impl.cc @@ -9,7 +9,8 @@ namespace Event { SchedulableCallbackImpl::SchedulableCallbackImpl(Libevent::BasePtr& libevent, std::function cb) - : cb_(cb) { + : cb_(cb) { + ENVOY_LOG_MISC(debug, "lambdai: construct SchedulableCallbackImpl {}", static_cast(this)); ASSERT(cb_); evtimer_assign( &raw_event_, libevent.get(), @@ -31,8 +32,10 @@ void SchedulableCallbackImpl::scheduleCallbackCurrentIteration() { void SchedulableCallbackImpl::scheduleCallbackNextIteration() { if (enabled()) { + ENVOY_LOG_MISC(debug, "lambdai: SchedulableCallbackImpl {} scheduleCallbackNextIteration is enabled. won't reschedule", static_cast(this)); return; } + ENVOY_LOG_MISC(debug, "lambdai: SchedulableCallbackImpl {} scheduleCallbackNextIteration is not schedule enabled. Will reschedule. ", static_cast(this)); // libevent computes the list of timers to move to the work list after polling for fd events, but // iteration through the work list starts. Zero delay timers added while iterating through the // work list execute on the next iteration of the event loop. diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc index 17202e09d0a8..1548779526bf 100644 --- a/source/common/network/buffered_io_socket_handle_impl.cc +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -55,6 +55,7 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::readv(uint64_t max_length, } ASSERT(num_bytes_to_read <= max_length); owned_buffer_.drain(num_bytes_to_read); + ENVOY_LOG_MISC(debug, "lambdai: readv {} on {}", num_bytes_to_read, static_cast(this)); return {num_bytes_to_read, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } } @@ -77,6 +78,7 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::writev(const Buffer::RawSlic } } writable_peer_->maybeSetNewData(); + ENVOY_LOG_MISC(debug, "lambdai: writev {} on {}", num_bytes_to_write, static_cast(this)); return {num_bytes_to_write, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } @@ -135,7 +137,9 @@ IoHandlePtr BufferedIoSocketHandleImpl::accept(struct sockaddr*, socklen_t*) { } Api::SysCallIntResult BufferedIoSocketHandleImpl::connect(Address::InstanceConstSharedPtr) { - return makeInvalidSyscall(); + // Buffered Io handle should always be considered as connected. Use write to determine if peer is + // closed. + return {0, 0}; } Api::SysCallIntResult BufferedIoSocketHandleImpl::setOption(int, int, const void*, socklen_t) { diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/common/network/buffered_io_socket_handle_impl.h index 9e1daa8f181e..ee9bbb1458f3 100644 --- a/source/common/network/buffered_io_socket_handle_impl.h +++ b/source/common/network/buffered_io_socket_handle_impl.h @@ -93,8 +93,11 @@ class BufferedIoSocketHandleImpl : public IoHandle, void scheduleNextEvent() { // It's possible there is no pending file event so as no io_callback. if (io_callback_) { + ENVOY_LOG_MISC(debug, "lambdai: has io_callback {} on {}", __FUNCTION__, static_cast(this)); io_callback_->scheduleCallbackNextIteration(); - } + return; + } + ENVOY_LOG_MISC(debug, "lambdai: no io_callback {} on {}", __FUNCTION__, static_cast(this)); } void setWritablePeer(WritablePeer* writable_peer) { @@ -108,6 +111,7 @@ class BufferedIoSocketHandleImpl : public IoHandle, void setWriteEnd() override { read_end_stream_ = true; } bool isWriteEndSet() override { return read_end_stream_; } void maybeSetNewData() override { + ENVOY_LOG_MISC(debug, "lambdai: {} on {}", __FUNCTION__, static_cast(this)); scheduleReadEvent(); scheduleNextEvent(); } diff --git a/source/common/network/connection_impl.cc b/source/common/network/connection_impl.cc index da201ea0ed91..33e365579194 100644 --- a/source/common/network/connection_impl.cc +++ b/source/common/network/connection_impl.cc @@ -70,7 +70,7 @@ ConnectionImpl::ConnectionImpl(Event::Dispatcher& dispatcher, ConnectionSocketPt file_event_ = socket_->ioHandle().createFileEvent( dispatcher_, [this](uint32_t events) -> void { onFileEvent(events); }, trigger, Event::FileReadyType::Read | Event::FileReadyType::Write); - + ENVOY_LOG_MISC(debug, "lambdai: create file event {} on connection {}", static_cast(file_event_.get()), id()); transport_socket_->setTransportSocketCallbacks(*this); } diff --git a/source/common/network/listen_socket_impl.h b/source/common/network/listen_socket_impl.h index 4501d86cb964..f71df9e57e13 100644 --- a/source/common/network/listen_socket_impl.h +++ b/source/common/network/listen_socket_impl.h @@ -210,8 +210,9 @@ class InternalConnectionSocketImpl : public ConnectionSocketImpl { : ConnectionSocketImpl(std::move(io_handle), local_address, remote_address) {} ~InternalConnectionSocketImpl() override = default; - // TODO(lambdai): succeed on limited options. - Api::SysCallIntResult getSocketOption(int level, int optname, void* ptr, socklen_t* len) const override { + // TODO(lambdai): sockopt: track and report on limited options. + Api::SysCallIntResult getSocketOption(int level, int optname, void* ptr, + socklen_t* len) const override { if (level == SOL_SOCKET && optname == SO_ERROR) { memset(ptr, 0, static_cast(*len)); *(reinterpret_cast(ptr)) = 0; @@ -220,7 +221,14 @@ class InternalConnectionSocketImpl : public ConnectionSocketImpl { ENVOY_LOG_MISC(warn, "unsupported socket option level={} optname={}", level, optname); return {0, EFAULT}; } - + } + Api::SysCallIntResult setSocketOption(int level, int optname, const void*, socklen_t) override { + if (level == IPPROTO_TCP && optname == TCP_NODELAY) { + return {0, 0}; + } else { + ENVOY_LOG_MISC(warn, "unsupported socket option level={} optname={}", level, optname); + return {0, EFAULT}; + } } }; diff --git a/source/server/connection_handler_impl.cc b/source/server/connection_handler_impl.cc index ac86ac4fb9d5..cb62864284de 100644 --- a/source/server/connection_handler_impl.cc +++ b/source/server/connection_handler_impl.cc @@ -788,7 +788,6 @@ void ConnectionHandlerImpl::ActiveInternalSocket::setDynamicMetadata( void ConnectionHandlerImpl::ActiveInternalSocket::newConnection() { connected_ = true; - // Set default transport protocol if none of the listener filters did it. if (!socket_->detectedTransportProtocol().empty() && socket_->detectedTransportProtocol() != @@ -853,6 +852,26 @@ ConnectionHandlerImpl::ActiveInternalListener::~ActiveInternalListener() { ASSERT(num_listener_connections_ == 0); } +void ConnectionHandlerImpl::ActiveInternalListener::removeConnection( + ActiveTcpConnection& connection) { + ENVOY_CONN_LOG(debug, "adding to cleanup list", *connection.connection_); + ActiveConnections& active_connections = connection.active_connections_; + ActiveTcpConnectionPtr removed = connection.removeFromList(active_connections.connections_); + parent_.dispatcher_.deferredDelete(std::move(removed)); + // Delete map entry only iff connections becomes empty. + if (active_connections.connections_.empty()) { + auto iter = connections_by_context_.find(&active_connections.filter_chain_); + ASSERT(iter != connections_by_context_.end()); + // To cover the lifetime of every single connection, Connections need to be deferred deleted + // because the previously contained connection is deferred deleted. + parent_.dispatcher_.deferredDelete(std::move(iter->second)); + // The erase will break the iteration over the connections_by_context_ during the deletion. + if (!is_deleting_) { + connections_by_context_.erase(iter); + } + } +} + void ConnectionHandlerImpl::ActiveInternalListener::shutdownListener() { internal_listener_->dispatcher_.registerInternalListener( internal_listener_->internal_listener_id_, @@ -889,7 +908,7 @@ ConnectionHandlerImpl::ActiveInternalListener::newTimespan(TimeSource& time_sour // Copied from newConnection(). Invoked by SetupPipeListener. void ConnectionHandlerImpl::ActiveInternalListener::setupNewConnection( Network::ConnectionPtr server_conn, Network::ConnectionSocketPtr socket) { - + incNumConnections(); auto stream_info = std::make_unique(parent_.dispatcher_.timeSource()); stream_info->setDownstreamLocalAddress(socket->localAddress()); stream_info->setDownstreamRemoteAddress(socket->remoteAddress()); @@ -992,12 +1011,10 @@ void ConnectionHandlerImpl::ActiveInternalListener::newConnection( ConnectionHandlerImpl::ActiveConnections& ConnectionHandlerImpl::ActiveInternalListener::getOrCreateActiveConnections( const Network::FilterChain& filter_chain) { - NOT_IMPLEMENTED_GCOVR_EXCL_LINE; ActiveConnectionsPtr& connections = connections_by_context_[&filter_chain]; - // if (connections == nullptr) { - // connections = std::make_unique(*this, - // filter_chain); - // } + if (connections == nullptr) { + connections = std::make_unique(*this, filter_chain); + } return *connections; } diff --git a/source/server/connection_handler_impl.h b/source/server/connection_handler_impl.h index 90803e39c25d..435406684c67 100644 --- a/source/server/connection_handler_impl.h +++ b/source/server/connection_handler_impl.h @@ -143,6 +143,7 @@ class ConnectionHandlerImpl : public Network::ConnectionHandler, } void onAcceptWorker(Network::ConnectionSocketPtr&& socket, bool hand_off_restored_destination_connections, bool rebalanced); + void decNumConnections() { ASSERT(num_listener_connections_ > 0); --num_listener_connections_; @@ -245,6 +246,11 @@ class ConnectionHandlerImpl : public Network::ConnectionHandler, ~ActiveInternalListener() override; + void incNumConnections() { + ++num_listener_connections_; + config_->openConnections().inc(); + } + void decNumConnections() { ASSERT(num_listener_connections_ > 0); --num_listener_connections_; @@ -263,6 +269,8 @@ class ConnectionHandlerImpl : public Network::ConnectionHandler, // StreamListener void onNewConnection() override { + // TODO(lambdai): FIX ME. + incNumConnections(); stats_.downstream_cx_total_.inc(); stats_.downstream_cx_active_.inc(); per_worker_stats_.downstream_cx_total_.inc(); diff --git a/test/integration/internal_listener_integration_test.cc b/test/integration/internal_listener_integration_test.cc new file mode 100644 index 000000000000..c0512e3235d5 --- /dev/null +++ b/test/integration/internal_listener_integration_test.cc @@ -0,0 +1,403 @@ +#include +#include + +#include "envoy/config/bootstrap/v3/bootstrap.pb.h" +#include "envoy/config/cluster/v3/cluster.pb.h" +#include "envoy/config/core/v3/base.pb.h" +#include "envoy/config/filter/network/tcp_proxy/v2/tcp_proxy.pb.h" +#include "envoy/extensions/access_loggers/file/v3/file.pb.h" +#include "envoy/extensions/filters/network/tcp_proxy/v3/tcp_proxy.pb.h" + +#include "test/integration/integration.h" +#include "test/mocks/secret/mocks.h" +#include "test/test_common/environment.h" + +#include "gtest/gtest.h" + +namespace Envoy { + +std::string tcpInternalConfig() { + return fmt::format(R"EOF( +admin: + access_log_path: {} + address: + socket_address: + address: 127.0.0.1 + port_value: 0 +dynamic_resources: + lds_config: + path: {} +static_resources: + secrets: + - name: "secret_static_0" + tls_certificate: + certificate_chain: + inline_string: "DUMMY_INLINE_BYTES" + private_key: + inline_string: "DUMMY_INLINE_BYTES" + password: + inline_string: "DUMMY_INLINE_BYTES" + clusters: + - name: cluster_internal + load_assignment: + cluster_name: cluster_internal + endpoints: + - lb_endpoints: + - endpoint: + address: + envoy_internal_address: + server_listener_name: listener_internal + - name: cluster_0 + load_assignment: + cluster_name: cluster_0 + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: 127.0.0.1 + port_value: 0 + listeners: + - name: tcp_proxy + address: + socket_address: + address: 127.0.0.1 + port_value: 0 + filter_chains: + filters: + name: tcp + typed_config: + "@type": type.googleapis.com/envoy.config.filter.network.tcp_proxy.v2.TcpProxy + stat_prefix: tcp_stats + cluster: cluster_internal + - name: listener_internal + address: + envoy_internal_address: + server_listener_name: listener_internal + internal_listener: + filter_chains: + filters: + name: tcp + typed_config: + "@type": type.googleapis.com/envoy.config.filter.network.tcp_proxy.v2.TcpProxy + stat_prefix: tcp_stats + cluster: cluster_0 +)EOF", + Platform::null_device_path, Platform::null_device_path); +} + +class InternalListenerIntegrationTest : public testing::TestWithParam, + public BaseIntegrationTest { +public: + InternalListenerIntegrationTest() : BaseIntegrationTest(GetParam(), tcpInternalConfig()) { + config_helper_.addConfigModifier( + [&](envoy::config::bootstrap::v3::Bootstrap& bootstrap) -> void { + auto* listener = bootstrap.mutable_static_resources()->mutable_listeners(1); + listener->mutable_internal_listener(); + }); + enable_half_close_ = true; + } + +public: + void initialize() override; +}; + +void InternalListenerIntegrationTest::initialize() { BaseIntegrationTest::initialize(); } + +TEST_P(InternalListenerIntegrationTest, TcpProxyUpstreamWritesFirst) { + initialize(); + IntegrationTcpClientPtr tcp_client = makeTcpConnection(lookupPort("tcp_proxy")); + FakeRawConnectionPtr fake_upstream_connection; + ASSERT_TRUE(fake_upstreams_[0]->waitForRawConnection(fake_upstream_connection)); + + ASSERT_TRUE(fake_upstream_connection->write("hell")); + tcp_client->waitForData("hell"); + // Make sure inexact matches work also on data already received. + tcp_client->waitForData("ell", false); + + // Make sure length based wait works for the data already received + ASSERT_TRUE(tcp_client->waitForData(4)); + ASSERT_TRUE(tcp_client->waitForData(3)); + + // Drain part of the received message + tcp_client->clearData(1); + tcp_client->waitForData("ell"); + ASSERT_TRUE(tcp_client->waitForData(3)); + + ASSERT_TRUE(tcp_client->write("world")); + ASSERT_TRUE(fake_upstream_connection->waitForData(5)); + + ASSERT_TRUE(fake_upstream_connection->write("", true)); + tcp_client->waitForHalfClose(); + ASSERT_TRUE(tcp_client->write("", true)); + ASSERT_TRUE(fake_upstream_connection->waitForHalfClose()); + ASSERT_TRUE(fake_upstream_connection->waitForDisconnect()); +} + +TEST_P(InternalListenerIntegrationTest, TcpProxyDownstreamWritesFirst) { + initialize(); + IntegrationTcpClientPtr tcp_client = makeTcpConnection(lookupPort("tcp_proxy")); + ASSERT_TRUE(tcp_client->write("hell")); + + FakeRawConnectionPtr fake_upstream_connection; + ASSERT_TRUE(fake_upstreams_[0]->waitForRawConnection(fake_upstream_connection)); + + ASSERT_TRUE(fake_upstream_connection->waitForData(4)); + ASSERT_TRUE(fake_upstream_connection->write("world")); + ASSERT_TRUE(fake_upstream_connection->close()); + + ASSERT_TRUE(fake_upstream_connection->waitForDisconnect()); + tcp_client->waitForHalfClose(); + tcp_client->close(); + EXPECT_EQ("world", tcp_client->data()); +} + +TEST_P(InternalListenerIntegrationTest, TcpProxyUpstreamDisconnect) { + initialize(); + IntegrationTcpClientPtr tcp_client = makeTcpConnection(lookupPort("tcp_proxy")); + ASSERT_TRUE(tcp_client->write("hello")); + FakeRawConnectionPtr fake_upstream_connection; + ASSERT_TRUE(fake_upstreams_[0]->waitForRawConnection(fake_upstream_connection)); + ASSERT_TRUE(fake_upstream_connection->waitForData(5)); + ASSERT_TRUE(fake_upstream_connection->write("world")); + ASSERT_TRUE(fake_upstream_connection->close()); + ASSERT_TRUE(fake_upstream_connection->waitForDisconnect()); + tcp_client->waitForHalfClose(); + tcp_client->close(); + + EXPECT_EQ("world", tcp_client->data()); +} + +TEST_P(InternalListenerIntegrationTest, TcpProxyDownstreamDisconnect) { + initialize(); + IntegrationTcpClientPtr tcp_client = makeTcpConnection(lookupPort("tcp_proxy")); + ASSERT_TRUE(tcp_client->write("hell")); + FakeRawConnectionPtr fake_upstream_connection; + ASSERT_TRUE(fake_upstreams_[0]->waitForRawConnection(fake_upstream_connection)); + ASSERT_TRUE(fake_upstream_connection->waitForData(4)); + ASSERT_TRUE(fake_upstream_connection->write("foobar")); + tcp_client->waitForData("foobar"); + ASSERT_TRUE(tcp_client->write("world", true)); + ASSERT_TRUE(fake_upstream_connection->waitForData(9)); + ASSERT_TRUE(fake_upstream_connection->waitForHalfClose()); + ASSERT_TRUE(fake_upstream_connection->write("", true)); + ASSERT_TRUE(fake_upstream_connection->waitForDisconnect()); + tcp_client->waitForDisconnect(); +} + +TEST_P(InternalListenerIntegrationTest, NoUpstream) { + // Set the first upstream to have an invalid port, so connection will fail, + // but it won't fail synchronously (as it would if there were simply no + // upstreams) + fake_upstreams_count_ = 0; + config_helper_.addConfigModifier([&](envoy::config::bootstrap::v3::Bootstrap& bootstrap) -> void { + auto* cluster = bootstrap.mutable_static_resources()->mutable_clusters(1); + auto* lb_endpoint = + cluster->mutable_load_assignment()->mutable_endpoints(0)->mutable_lb_endpoints(0); + lb_endpoint->mutable_endpoint()->mutable_address()->mutable_socket_address()->set_port_value(1); + }); + config_helper_.skipPortUsageValidation(); + enable_half_close_ = false; + initialize(); + + IntegrationTcpClientPtr tcp_client = makeTcpConnection(lookupPort("tcp_proxy")); + tcp_client->waitForDisconnect(); +} + +TEST_P(InternalListenerIntegrationTest, ShutdownWithOpenConnections) { + config_helper_.addConfigModifier([&](envoy::config::bootstrap::v3::Bootstrap& bootstrap) -> void { + auto* static_resources = bootstrap.mutable_static_resources(); + for (int i = 0; i < static_resources->clusters_size(); ++i) { + auto* cluster = static_resources->mutable_clusters(i); + cluster->set_close_connections_on_host_health_failure(true); + } + }); + initialize(); + IntegrationTcpClientPtr tcp_client = makeTcpConnection(lookupPort("tcp_proxy")); + ASSERT_TRUE(tcp_client->write("hello")); + FakeRawConnectionPtr fake_upstream_connection; + ASSERT_TRUE(fake_upstreams_[0]->waitForRawConnection(fake_upstream_connection)); + ASSERT_TRUE(fake_upstream_connection->waitForData(5)); + ASSERT_TRUE(fake_upstream_connection->write("world")); + tcp_client->waitForData("world"); + ASSERT_TRUE(tcp_client->write("hello", false)); + ASSERT_TRUE(fake_upstream_connection->waitForData(10)); + test_server_.reset(); + ASSERT_TRUE(fake_upstream_connection->waitForHalfClose()); + ASSERT_TRUE(fake_upstream_connection->close()); + ASSERT_TRUE(fake_upstream_connection->waitForDisconnect()); + tcp_client->waitForHalfClose(); + tcp_client->close(); + + // Success criteria is that no ASSERTs fire and there are no leaks. +} + +TEST_P(InternalListenerIntegrationTest, TestIdletimeoutWithNoData) { + autonomous_upstream_ = true; + + enable_half_close_ = false; + config_helper_.addConfigModifier([&](envoy::config::bootstrap::v3::Bootstrap& bootstrap) -> void { + // The first listener is connecting to internal cluster. Mutate the 2nd listener which connect + // to normal cluster. + auto* listener = bootstrap.mutable_static_resources()->mutable_listeners(1); + auto* filter_chain = listener->mutable_filter_chains(0); + auto* config_blob = filter_chain->mutable_filters(0)->mutable_typed_config(); + + ASSERT_TRUE( + config_blob->Is()); + auto tcp_proxy_config = MessageUtil::anyConvert(*config_blob); + tcp_proxy_config.mutable_idle_timeout()->set_nanos( + std::chrono::duration_cast(std::chrono::milliseconds(100)) + .count()); + config_blob->PackFrom(tcp_proxy_config); + }); + + initialize(); + IntegrationTcpClientPtr tcp_client = makeTcpConnection(lookupPort("tcp_proxy")); + tcp_client->waitForDisconnect(true); +} + +TEST_P(InternalListenerIntegrationTest, DISABLED_TcpProxyLargeWrite) { + config_helper_.setBufferLimits(1024, 1024); + initialize(); + + std::string data(1024 * 16, 'a'); + IntegrationTcpClientPtr tcp_client = makeTcpConnection(lookupPort("tcp_proxy")); + ASSERT_TRUE(tcp_client->write(data)); + FakeRawConnectionPtr fake_upstream_connection; + ASSERT_TRUE(fake_upstreams_[0]->waitForRawConnection(fake_upstream_connection)); + ASSERT_TRUE(fake_upstream_connection->waitForData(data.size())); + ASSERT_TRUE(fake_upstream_connection->write(data)); + tcp_client->waitForData(data); + tcp_client->close(); + ASSERT_TRUE(fake_upstream_connection->waitForHalfClose()); + ASSERT_TRUE(fake_upstream_connection->close()); + ASSERT_TRUE(fake_upstream_connection->waitForDisconnect()); + + uint32_t upstream_pauses = + test_server_->counter("cluster.cluster_0.upstream_flow_control_paused_reading_total") + ->value(); + uint32_t upstream_resumes = + test_server_->counter("cluster.cluster_0.upstream_flow_control_resumed_reading_total") + ->value(); + ENVOY_LOG_MISC(debug, "lambdai: cluster_0 pause reading = {} resume reading = {}", + upstream_pauses, upstream_resumes); + EXPECT_EQ(upstream_pauses, upstream_resumes); + + uint32_t downstream_pauses = + test_server_->counter("tcp.tcp_stats.downstream_flow_control_paused_reading_total")->value(); + uint32_t downstream_resumes = + test_server_->counter("tcp.tcp_stats.downstream_flow_control_resumed_reading_total")->value(); + ENVOY_LOG_MISC(debug, "lambdai: listener pause reading = {} resume reading = {}", + downstream_pauses, downstream_resumes); + + EXPECT_EQ(downstream_pauses, downstream_resumes); +} + +// Test that a downstream flush works correctly (all data is flushed) +TEST_P(InternalListenerIntegrationTest, DISABLED_TcpProxyDownstreamFlush) { + // Use a very large size to make sure it is larger than the kernel socket read buffer. + const uint32_t size = 50 * 1024 * 1024; + config_helper_.setBufferLimits(size / 4, size / 4); + initialize(); + + std::string data(size, 'a'); + IntegrationTcpClientPtr tcp_client = makeTcpConnection(lookupPort("tcp_proxy")); + FakeRawConnectionPtr fake_upstream_connection; + ASSERT_TRUE(fake_upstreams_[0]->waitForRawConnection(fake_upstream_connection)); + tcp_client->readDisable(true); + ASSERT_TRUE(tcp_client->write("", true)); + + // This ensures that readDisable(true) has been run on it's thread + // before tcp_client starts writing. + ASSERT_TRUE(fake_upstream_connection->waitForHalfClose()); + + ASSERT_TRUE(fake_upstream_connection->write(data, true)); + + test_server_->waitForCounterGe("cluster.cluster_0.upstream_flow_control_paused_reading_total", 1); + EXPECT_EQ(test_server_->counter("cluster.cluster_0.upstream_flow_control_resumed_reading_total") + ->value(), + 0); + tcp_client->readDisable(false); + tcp_client->waitForData(data); + tcp_client->waitForHalfClose(); + ASSERT_TRUE(fake_upstream_connection->waitForHalfClose()); + + uint32_t upstream_pauses = + test_server_->counter("cluster.cluster_0.upstream_flow_control_paused_reading_total") + ->value(); + uint32_t upstream_resumes = + test_server_->counter("cluster.cluster_0.upstream_flow_control_resumed_reading_total") + ->value(); + ENVOY_LOG_MISC(debug, "lambdai: cluster_0 pause reading = {} resume reading = {}", + upstream_pauses, upstream_resumes); + + EXPECT_GE(upstream_pauses, upstream_resumes); + + EXPECT_GT(upstream_resumes, 0); +} + +// Test that an upstream flush works correctly (all data is flushed) +TEST_P(InternalListenerIntegrationTest, DISABLED_TcpProxyUpstreamFlush) { + // Use a very large size to make sure it is larger than the kernel socket read buffer. + const uint32_t size = 50 * 1024 * 1024; + config_helper_.setBufferLimits(size, size); + initialize(); + + std::string data(size, 'a'); + IntegrationTcpClientPtr tcp_client = makeTcpConnection(lookupPort("tcp_proxy")); + FakeRawConnectionPtr fake_upstream_connection; + ASSERT_TRUE(fake_upstreams_[0]->waitForRawConnection(fake_upstream_connection)); + ASSERT_TRUE(fake_upstream_connection->readDisable(true)); + ASSERT_TRUE(fake_upstream_connection->write("", true)); + + // This ensures that fake_upstream_connection->readDisable has been run on it's thread + // before tcp_client starts writing. + tcp_client->waitForHalfClose(); + + ASSERT_TRUE(tcp_client->write(data, true)); + + test_server_->waitForGaugeEq("tcp.tcp_stats.upstream_flush_active", 1); + ASSERT_TRUE(fake_upstream_connection->readDisable(false)); + ASSERT_TRUE(fake_upstream_connection->waitForData(data.size())); + ASSERT_TRUE(fake_upstream_connection->waitForHalfClose()); + ASSERT_TRUE(fake_upstream_connection->waitForDisconnect()); + tcp_client->waitForHalfClose(); + + EXPECT_EQ(test_server_->counter("tcp.tcp_stats.upstream_flush_total")->value(), 1); + test_server_->waitForGaugeEq("tcp.tcp_stats.upstream_flush_active", 0); +} + +// Test that Envoy doesn't crash or assert when shutting down with an upstream flush active +TEST_P(InternalListenerIntegrationTest, DISABLED_TcpProxyUpstreamFlushEnvoyExit) { + // Use a very large size to make sure it is larger than the kernel socket read buffer. + const uint32_t size = 50 * 1024 * 1024; + config_helper_.setBufferLimits(size, size); + initialize(); + + std::string data(size, 'a'); + IntegrationTcpClientPtr tcp_client = makeTcpConnection(lookupPort("tcp_proxy")); + FakeRawConnectionPtr fake_upstream_connection; + ASSERT_TRUE(fake_upstreams_[0]->waitForRawConnection(fake_upstream_connection)); + ASSERT_TRUE(fake_upstream_connection->readDisable(true)); + ASSERT_TRUE(fake_upstream_connection->write("", true)); + + // This ensures that fake_upstream_connection->readDisable has been run on it's thread + // before tcp_client starts writing. + tcp_client->waitForHalfClose(); + + ASSERT_TRUE(tcp_client->write(data, true)); + + test_server_->waitForGaugeEq("tcp.tcp_stats.upstream_flush_active", 1); + test_server_.reset(); + ASSERT_TRUE(fake_upstream_connection->close()); + ASSERT_TRUE(fake_upstream_connection->waitForDisconnect()); + + // Success criteria is that no ASSERTs fire and there are no leaks. +} + +INSTANTIATE_TEST_SUITE_P(IpVersions, InternalListenerIntegrationTest, + testing::ValuesIn(TestEnvironment::getIpVersionsForTest()), + TestUtility::ipTestParamsToString); +} // namespace Envoy \ No newline at end of file From 95b5a5478eab012252dd169d9b89f36086fcd73b Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 1 Oct 2020 08:12:25 +0000 Subject: [PATCH 038/100] fix all internal listener integration test Signed-off-by: Yuchen Dai --- .../network/buffered_io_socket_handle_impl.cc | 2 +- test/config/utility.cc | 11 ++++++----- .../internal_listener_integration_test.cc | 16 +++++++--------- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc index 1548779526bf..0d4e740d35fa 100644 --- a/source/common/network/buffered_io_socket_handle_impl.cc +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -38,7 +38,7 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::readv(uint64_t max_length, uint64_t num_slice) { if (owned_buffer_.length() == 0) { if (read_end_stream_) { - return sysCallResultToIoCallResult(Api::SysCallSizeResult{-1, SOCKET_ERROR_INTR}); + return Api::ioCallUint64ResultNoError(); } else { return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), IoSocketError::deleteIoError)}; diff --git a/test/config/utility.cc b/test/config/utility.cc index bbdf1ba55ef2..594f81b82f69 100644 --- a/test/config/utility.cc +++ b/test/config/utility.cc @@ -529,7 +529,8 @@ ConfigHelper::ConfigHelper(const Network::Address::IpVersion version, Api::Api& auto* static_resources = bootstrap_.mutable_static_resources(); for (int i = 0; i < static_resources->listeners_size(); ++i) { auto* listener = static_resources->mutable_listeners(i); - // Not need to amend internal address and we need to skip the below implicit address mutation helper. + // Not need to amend internal address and we need to skip the below implicit address mutation + // helper. if (listener->mutable_address()->has_envoy_internal_address()) { continue; } @@ -784,10 +785,10 @@ void ConfigHelper::setDefaultHostAndRoute(const std::string& domains, const std: void ConfigHelper::setBufferLimits(uint32_t upstream_buffer_limit, uint32_t downstream_buffer_limit) { RELEASE_ASSERT(!finalized_, ""); - RELEASE_ASSERT(bootstrap_.mutable_static_resources()->listeners_size() == 1, ""); - auto* listener = bootstrap_.mutable_static_resources()->mutable_listeners(0); - listener->mutable_per_connection_buffer_limit_bytes()->set_value(downstream_buffer_limit); - + for (int i = 0; i < bootstrap_.mutable_static_resources()->listeners_size(); ++i) { + auto* listener = bootstrap_.mutable_static_resources()->mutable_listeners(0); + listener->mutable_per_connection_buffer_limit_bytes()->set_value(downstream_buffer_limit); + } auto* static_resources = bootstrap_.mutable_static_resources(); for (int i = 0; i < bootstrap_.mutable_static_resources()->clusters_size(); ++i) { auto* cluster = static_resources->mutable_clusters(i); diff --git a/test/integration/internal_listener_integration_test.cc b/test/integration/internal_listener_integration_test.cc index c0512e3235d5..37c0bebd41ff 100644 --- a/test/integration/internal_listener_integration_test.cc +++ b/test/integration/internal_listener_integration_test.cc @@ -258,7 +258,7 @@ TEST_P(InternalListenerIntegrationTest, TestIdletimeoutWithNoData) { tcp_client->waitForDisconnect(true); } -TEST_P(InternalListenerIntegrationTest, DISABLED_TcpProxyLargeWrite) { +TEST_P(InternalListenerIntegrationTest, TcpProxyLargeWrite) { config_helper_.setBufferLimits(1024, 1024); initialize(); @@ -296,7 +296,7 @@ TEST_P(InternalListenerIntegrationTest, DISABLED_TcpProxyLargeWrite) { } // Test that a downstream flush works correctly (all data is flushed) -TEST_P(InternalListenerIntegrationTest, DISABLED_TcpProxyDownstreamFlush) { +TEST_P(InternalListenerIntegrationTest, TcpProxyDownstreamFlush) { // Use a very large size to make sure it is larger than the kernel socket read buffer. const uint32_t size = 50 * 1024 * 1024; config_helper_.setBufferLimits(size / 4, size / 4); @@ -316,9 +316,7 @@ TEST_P(InternalListenerIntegrationTest, DISABLED_TcpProxyDownstreamFlush) { ASSERT_TRUE(fake_upstream_connection->write(data, true)); test_server_->waitForCounterGe("cluster.cluster_0.upstream_flow_control_paused_reading_total", 1); - EXPECT_EQ(test_server_->counter("cluster.cluster_0.upstream_flow_control_resumed_reading_total") - ->value(), - 0); + tcp_client->readDisable(false); tcp_client->waitForData(data); tcp_client->waitForHalfClose(); @@ -339,7 +337,7 @@ TEST_P(InternalListenerIntegrationTest, DISABLED_TcpProxyDownstreamFlush) { } // Test that an upstream flush works correctly (all data is flushed) -TEST_P(InternalListenerIntegrationTest, DISABLED_TcpProxyUpstreamFlush) { +TEST_P(InternalListenerIntegrationTest, TcpProxyUpstreamFlush) { // Use a very large size to make sure it is larger than the kernel socket read buffer. const uint32_t size = 50 * 1024 * 1024; config_helper_.setBufferLimits(size, size); @@ -364,13 +362,13 @@ TEST_P(InternalListenerIntegrationTest, DISABLED_TcpProxyUpstreamFlush) { ASSERT_TRUE(fake_upstream_connection->waitForHalfClose()); ASSERT_TRUE(fake_upstream_connection->waitForDisconnect()); tcp_client->waitForHalfClose(); - - EXPECT_EQ(test_server_->counter("tcp.tcp_stats.upstream_flush_total")->value(), 1); + // We have 2 tcp proxy. Each contribute 1. + EXPECT_EQ(test_server_->counter("tcp.tcp_stats.upstream_flush_total")->value(), 2); test_server_->waitForGaugeEq("tcp.tcp_stats.upstream_flush_active", 0); } // Test that Envoy doesn't crash or assert when shutting down with an upstream flush active -TEST_P(InternalListenerIntegrationTest, DISABLED_TcpProxyUpstreamFlushEnvoyExit) { +TEST_P(InternalListenerIntegrationTest, TcpProxyUpstreamFlushEnvoyExit) { // Use a very large size to make sure it is larger than the kernel socket read buffer. const uint32_t size = 50 * 1024 * 1024; config_helper_.setBufferLimits(size, size); From abbffa5b30e4c4a3aa886c73f311d0de8c15cc92 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 1 Oct 2020 09:19:32 +0000 Subject: [PATCH 039/100] fix test Signed-off-by: Yuchen Dai --- test/integration/socket_interface_integration_test.cc | 7 +++---- test/mocks/network/mocks.h | 1 + 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/integration/socket_interface_integration_test.cc b/test/integration/socket_interface_integration_test.cc index 6662ac6f0276..bec4b10ca3fe 100644 --- a/test/integration/socket_interface_integration_test.cc +++ b/test/integration/socket_interface_integration_test.cc @@ -89,8 +89,7 @@ TEST_P(SocketInterfaceIntegrationTest, AddressWithSocketInterface) { client_->close(Network::ConnectionCloseType::FlushWrite); } -// Test that connecting to internal address will crash. -// TODO(lambdai): Add internal connection implementation to enable the connection creation. +// Test that connection to internal address which is not bind by listener will be closed. TEST_P(SocketInterfaceIntegrationTest, InternalAddressWithSocketInterface) { BaseIntegrationTest::initialize(); @@ -101,8 +100,8 @@ TEST_P(SocketInterfaceIntegrationTest, InternalAddressWithSocketInterface) { Network::Address::InstanceConstSharedPtr address = std::make_shared("listener_0", sock_interface); - client_ = dispatcher_->createClientConnection(address, Network::Address::InstanceConstSharedPtr(), - Network::Test::createRawBufferSocket(), nullptr); + client_ = + dispatcher_->createInternalConnection(address, Network::Address::InstanceConstSharedPtr()); client_->addConnectionCallbacks(connect_callbacks_); client_->connect(); diff --git a/test/mocks/network/mocks.h b/test/mocks/network/mocks.h index 88e580effa69..3483d7ba8b66 100644 --- a/test/mocks/network/mocks.h +++ b/test/mocks/network/mocks.h @@ -359,6 +359,7 @@ class MockListenerConfig : public ListenerConfig { MOCK_METHOD(const std::string&, name, (), (const)); MOCK_METHOD(Network::ActiveUdpListenerFactory*, udpListenerFactory, ()); MOCK_METHOD(Network::UdpPacketWriterFactoryOptRef, udpPacketWriterFactory, ()); + MOCK_METHOD(bool, isInternalListener, ()); MOCK_METHOD(Network::UdpListenerWorkerRouterOptRef, udpListenerWorkerRouter, ()); MOCK_METHOD(ConnectionBalancer&, connectionBalancer, ()); MOCK_METHOD(ResourceLimit&, openConnections, ()); From c1e6f4cb17b73e4ef0966f294eea4638a3b64c9d Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Mon, 5 Oct 2020 22:24:40 +0000 Subject: [PATCH 040/100] small fixes and comments Signed-off-by: Yuchen Dai --- include/envoy/event/dispatcher.h | 4 +- include/envoy/network/listener.h | 7 ++- source/common/event/dispatcher_impl.cc | 4 +- source/common/event/file_event_impl.h | 44 ++++++++++----- .../common/network/internal_listener_impl.cc | 2 +- .../common/network/internal_listener_impl.h | 2 +- source/server/connection_handler_impl.cc | 53 +------------------ source/server/connection_handler_impl.h | 5 +- 8 files changed, 45 insertions(+), 76 deletions(-) diff --git a/include/envoy/event/dispatcher.h b/include/envoy/event/dispatcher.h index c73ff4603579..af6e976a1dae 100644 --- a/include/envoy/event/dispatcher.h +++ b/include/envoy/event/dispatcher.h @@ -117,7 +117,9 @@ class Dispatcher { * Creates an client internal connection. Does NOT initiate the connection; * the caller must then call connect() on the returned Network::ClientConnection. * @param internal_address supplies the internal address to connect to. - * @param local_address supplies an address to bind to or nullptr if no bind is necessary. + * @param local_address supplies an address to bind to or nullptr. If nullptr is provided, an + * internal local_address is automatically generated. This address is accessible by the server + * connection as source address. * @return Network::ClientConnectionPtr a client connection that is owned by the caller. */ virtual Network::ClientConnectionPtr diff --git a/include/envoy/network/listener.h b/include/envoy/network/listener.h index 8459797a7212..9353588757fe 100644 --- a/include/envoy/network/listener.h +++ b/include/envoy/network/listener.h @@ -215,8 +215,11 @@ class InternalListenerCallbacks { public: virtual ~InternalListenerCallbacks() = default; - virtual void setupNewConnection(Network::ConnectionPtr server_conn, - Network::ConnectionSocketPtr socket) PURE; + /** + * Called when a new internal connection is created. + * @param socket supplies the socket. Note that the underlying IoHandle has no file descriptor + * although the interface provides fd. + */ virtual void onNewSocket(Network::ConnectionSocketPtr socket) PURE; }; diff --git a/source/common/event/dispatcher_impl.cc b/source/common/event/dispatcher_impl.cc index 492a76bb3163..1e65e91b21ea 100644 --- a/source/common/event/dispatcher_impl.cc +++ b/source/common/event/dispatcher_impl.cc @@ -124,7 +124,7 @@ DispatcherImpl::createClientConnection(Network::Address::InstanceConstSharedPtr namespace { Network::Address::InstanceConstSharedPtr nextClientAddress(const Network::Address::InstanceConstSharedPtr& server_address) { - uint64_t id = 0; + static uint64_t id = 0; return std::make_shared(absl::StrCat(server_address->asStringView(), "_", ++id)); } } // namespace @@ -139,7 +139,7 @@ DispatcherImpl::createInternalConnection(Network::Address::InstanceConstSharedPt if (local_address == nullptr) { local_address = nextClientAddress(internal_address); } - // Find the internal listener callback. The listener will setup the server connection. + // Find the internal listener callback. The listener will set up the server connection. auto iter = internal_listeners_.find(internal_address->asString()); for (const auto& [name, _] : internal_listeners_) { ENVOY_LOG_MISC(debug, "lambdai: p listener {}", name); diff --git a/source/common/event/file_event_impl.h b/source/common/event/file_event_impl.h index f9c55dd4b935..7c723d7859fa 100644 --- a/source/common/event/file_event_impl.h +++ b/source/common/event/file_event_impl.h @@ -51,32 +51,45 @@ class FileEventImpl : public FileEvent, ImplBase { // Forward declare for friend class. class UserSpaceFileEventFactory; +// The interface of populating event watcher and obtaining the active events. The events includes +// Read, Write and Closed. class EventListener { public: virtual ~EventListener() = default; + + // Provide the activated events. virtual uint32_t triggeredEvents() PURE; + virtual uint32_t getAndClearEphemeralEvents() PURE; + + // Callbacks of the event operation. virtual void onEventEnabled(uint32_t enabled_events) PURE; - virtual void onEventActivated(uint32_t enabled_events) PURE; - virtual uint32_t getAndClearEpheralEvents() PURE; + virtual void onEventActivated(uint32_t activated_events) PURE; }; // Return the enabled events except EV_CLOSED. This implementation is generally good since only -// epoll supports EV_CLOSED. The event owner must assume EV_CLOSED is not reliable. Also event owner -// must assume OS could notify events which are not actually triggered. +// epoll supports EV_CLOSED but the entire envoy code base supports other pollers. The event owner +// must assume EV_CLOSED is never activated. Also event owner must tolerat that OS could notify events +// which are not actually triggered. class DefaultEventListener : public EventListener { public: ~DefaultEventListener() override = default; uint32_t triggeredEvents() override { - ENVOY_LOG_MISC(debug, "lambdai: user file event listener triggered events {} on {} and schedule next", pending_events_, static_cast(this)); + ENVOY_LOG_MISC(debug, + "lambdai: user file event listener triggered events {} on {} and schedule next", + pending_events_, static_cast(this)); - return pending_events_ & (~Event::FileReadyType::Closed); } - void onEventEnabled(uint32_t enabled_events) override { - ENVOY_LOG_MISC(debug, "lambdai: user file event listener set enabled events {} on {} and schedule next", pending_events_, static_cast(this)); - pending_events_ = enabled_events; } + return pending_events_ & (~Event::FileReadyType::Closed); + } + void onEventEnabled(uint32_t enabled_events) override { + ENVOY_LOG_MISC( + debug, "lambdai: user file event listener set enabled events {} on {} and schedule next", + pending_events_, static_cast(this)); + pending_events_ = enabled_events; + } void onEventActivated(uint32_t activated_events) override { ephermal_events_ |= activated_events; } - uint32_t getAndClearEpheralEvents() override { + uint32_t getAndClearEphemeralEvents() override { auto res = ephermal_events_; ephermal_events_ = 0; return res; @@ -112,10 +125,12 @@ class UserSpaceFileEventImpl : public FileEvent { event_listener_.onEventEnabled(events); if (!schedulable_.enabled()) { schedulable_.scheduleCallbackNextIteration(); - ENVOY_LOG_MISC(debug, "lambdai: user file event setEnabled {} on {} and schedule next", events, static_cast(this)); + ENVOY_LOG_MISC(debug, "lambdai: user file event setEnabled {} on {} and schedule next", + events, static_cast(this)); return; } - ENVOY_LOG_MISC(debug, "lambdai: user file event setEnabled {} on {} and but not schedule next", events, static_cast(this)); + ENVOY_LOG_MISC(debug, "lambdai: user file event setEnabled {} on {} and but not schedule next", + events, static_cast(this)); } EventListener& getEventListener() { return event_listener_; } @@ -128,8 +143,9 @@ class UserSpaceFileEventImpl : public FileEvent { SchedulableCallback& schedulable_cb, int& event_counter) : schedulable_(schedulable_cb), cb_([this, cb]() { auto all_events = getEventListener().triggeredEvents(); - auto ephemeral_events = getEventListener().getAndClearEpheralEvents(); - ENVOY_LOG_MISC(debug, "lambdai: us event {} cb allevents = {}, ephermal events = {}", static_cast(this), all_events, ephemeral_events); + auto ephemeral_events = getEventListener().getAndClearEphemeralEvents(); + ENVOY_LOG_MISC(debug, "lambdai: us event {} cb allevents = {}, ephermal events = {}", + static_cast(this), all_events, ephemeral_events); cb(all_events | ephemeral_events); }), event_counter_(event_counter) { diff --git a/source/common/network/internal_listener_impl.cc b/source/common/network/internal_listener_impl.cc index 86c5781da8ad..d9bdb5168d92 100644 --- a/source/common/network/internal_listener_impl.cc +++ b/source/common/network/internal_listener_impl.cc @@ -21,7 +21,7 @@ namespace Network { namespace { // uint64_t next_internal_connection_id = 0; } -void InternalListenerImpl::setupInternalListener() { +void InternalListenerImpl::setUpInternalListener() { dispatcher_.registerInternalListener( internal_listener_id_, [this](const Address::InstanceConstSharedPtr&, diff --git a/source/common/network/internal_listener_impl.h b/source/common/network/internal_listener_impl.h index 429268ed1379..80bf1d4fc878 100644 --- a/source/common/network/internal_listener_impl.h +++ b/source/common/network/internal_listener_impl.h @@ -18,7 +18,7 @@ class InternalListenerImpl : public BaseListenerImpl { void disable() override; void enable() override; - void setupInternalListener(); + void setUpInternalListener(); public: std::string internal_listener_id_; diff --git a/source/server/connection_handler_impl.cc b/source/server/connection_handler_impl.cc index cb62864284de..4660d31272cc 100644 --- a/source/server/connection_handler_impl.cc +++ b/source/server/connection_handler_impl.cc @@ -52,7 +52,7 @@ void ConnectionHandlerImpl::addListener(absl::optional overridden_list } } auto active_internal_listener = std::make_unique(*this, config); - active_internal_listener->internal_listener_->setupInternalListener(); + active_internal_listener->internal_listener_->setUpInternalListener(); details.typed_listener_ = *active_internal_listener; details.listener_ = std::move(active_internal_listener); } else if (config.listenSocketFactory().socketType() == Network::Socket::Type::Stream) { @@ -905,59 +905,10 @@ ConnectionHandlerImpl::ActiveInternalListener::newTimespan(TimeSource& time_sour time_source); } -// Copied from newConnection(). Invoked by SetupPipeListener. -void ConnectionHandlerImpl::ActiveInternalListener::setupNewConnection( - Network::ConnectionPtr server_conn, Network::ConnectionSocketPtr socket) { - incNumConnections(); - auto stream_info = std::make_unique(parent_.dispatcher_.timeSource()); - stream_info->setDownstreamLocalAddress(socket->localAddress()); - stream_info->setDownstreamRemoteAddress(socket->remoteAddress()); - stream_info->setDownstreamDirectRemoteAddress(socket->directRemoteAddress()); - - // TODO(lambdai): refactor - // auto p = dynamic_cast(server_conn.get()); - // ASSERT(p); - // p->setStreamInfo(stream_info.get()); - - // Find matching filter chain. - const auto filter_chain = config_->filterChainManager().findFilterChain(*socket); - if (filter_chain == nullptr) { - ENVOY_LOG(debug, "closing connection: no matching filter chain found"); - stats_.no_filter_chain_match_.inc(); - stream_info->setResponseFlag(StreamInfo::ResponseFlag::NoRouteFound); - stream_info->setResponseCodeDetails(StreamInfo::ResponseCodeDetails::get().FilterChainNotFound); - emitLogs(*config_, *stream_info); - socket->close(); - return; - } - - auto transport_socket = filter_chain->transportSocketFactory().createTransportSocket(nullptr); - stream_info->setDownstreamSslConnection(transport_socket->ssl()); - auto& active_connections = getOrCreateActiveConnections(*filter_chain); - // TODO(lambdai): set stream_info - ActiveTcpConnectionPtr active_connection( - new ActiveTcpConnection(active_connections, std::move(server_conn), - parent_.dispatcher_.timeSource(), std::move(stream_info))); - active_connection->connection_->setBufferLimits(config_->perConnectionBufferLimitBytes()); - - const bool empty_filter_chain = !config_->filterChainFactory().createNetworkFilterChain( - *active_connection->connection_, filter_chain->networkFilterFactories()); - if (empty_filter_chain) { - ENVOY_CONN_LOG(debug, "closing connection: no filters", *active_connection->connection_); - active_connection->connection_->close(Network::ConnectionCloseType::NoFlush); - } - - // If the connection is already closed, we can just let this connection immediately die. - if (active_connection->connection_->state() != Network::Connection::State::Closed) { - ENVOY_CONN_LOG(debug, "new connection", *active_connection->connection_); - active_connection->connection_->addConnectionCallbacks(*active_connection); - LinkedList::moveIntoList(std::move(active_connection), active_connections.connections_); - } -} - void ConnectionHandlerImpl::ActiveInternalListener::newConnection( Network::ConnectionSocketPtr&& socket, const envoy::config::core::v3::Metadata& dynamic_metadata) { + incNumConnections(); auto stream_info = std::make_unique( parent_.dispatcher_.timeSource(), StreamInfo::FilterState::LifeSpan::Connection); stream_info->setDownstreamLocalAddress(socket->localAddress()); diff --git a/source/server/connection_handler_impl.h b/source/server/connection_handler_impl.h index 435406684c67..4baa2527c865 100644 --- a/source/server/connection_handler_impl.h +++ b/source/server/connection_handler_impl.h @@ -258,9 +258,8 @@ class ConnectionHandlerImpl : public Network::ConnectionHandler, } // Network::InternalListenerCallbacks - void setupNewConnection(Network::ConnectionPtr server_conn, - Network::ConnectionSocketPtr socket) override; void onNewSocket(Network::ConnectionSocketPtr socket) override; + // ActiveListenerImplBase Network::Listener* listener() override { return internal_listener_.get(); } void pauseListening() override { internal_listener_->disable(); } @@ -269,8 +268,6 @@ class ConnectionHandlerImpl : public Network::ConnectionHandler, // StreamListener void onNewConnection() override { - // TODO(lambdai): FIX ME. - incNumConnections(); stats_.downstream_cx_total_.inc(); stats_.downstream_cx_active_.inc(); per_worker_stats_.downstream_cx_total_.inc(); From f8605943a1a66213d3f67112f81401b042918733 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Tue, 6 Oct 2020 20:53:20 +0000 Subject: [PATCH 041/100] format Signed-off-by: Yuchen Dai --- source/common/event/file_event_impl.h | 125 +++++ source/common/network/BUILD | 25 + .../network/buffered_io_socket_handle_impl.cc | 196 ++++++++ .../network/buffered_io_socket_handle_impl.h | 159 ++++++ source/common/network/io_socket_error_impl.h | 19 + source/common/network/peer_buffer.h | 77 +++ test/common/network/BUILD | 11 + .../buffered_io_socket_handle_impl_test.cc | 475 ++++++++++++++++++ tools/spelling/spelling_dictionary.txt | 1 + 9 files changed, 1088 insertions(+) create mode 100644 source/common/network/buffered_io_socket_handle_impl.cc create mode 100644 source/common/network/buffered_io_socket_handle_impl.h create mode 100644 source/common/network/peer_buffer.h create mode 100644 test/common/network/buffered_io_socket_handle_impl_test.cc diff --git a/source/common/event/file_event_impl.h b/source/common/event/file_event_impl.h index cc3e505d788b..ae8ace64d2f8 100644 --- a/source/common/event/file_event_impl.h +++ b/source/common/event/file_event_impl.h @@ -8,6 +8,10 @@ #include "common/event/event_impl_base.h" namespace Envoy { + +namespace Network { +class BufferedIoSocketHandleImpl; +} namespace Event { /** @@ -41,5 +45,126 @@ class FileEventImpl : public FileEvent, ImplBase { // polling and activating new fd events. const bool activate_fd_events_next_event_loop_; }; + +// Forward declare for friend class. +class UserSpaceFileEventFactory; + +// The interface of populating event watcher and obtaining the active events. The events includes +// Read, Write and Closed. +class EventListener { +public: + virtual ~EventListener() = default; + + // Provide the activated events. + virtual uint32_t triggeredEvents() PURE; + virtual uint32_t getAndClearEphemeralEvents() PURE; + + // Callbacks of the event operation. + virtual void onEventEnabled(uint32_t enabled_events) PURE; + virtual void onEventActivated(uint32_t activated_events) PURE; +}; + +// Return the enabled events except EV_CLOSED. This implementation is generally good since only +// epoll supports EV_CLOSED but the entire envoy code base supports another poller. The event owner +// must assume EV_CLOSED is never activated. Also event owner must tolerate that OS could notify +// events which are not actually triggered. +class DefaultEventListener : public EventListener { +public: + ~DefaultEventListener() override = default; + uint32_t triggeredEvents() override { + ENVOY_LOG_MISC(debug, + "lambdai: user file event listener triggered events {} on {} and schedule next", + pending_events_, static_cast(this)); + + return pending_events_ & (~Event::FileReadyType::Closed); + } + void onEventEnabled(uint32_t enabled_events) override { + ENVOY_LOG_MISC( + debug, "lambdai: user file event listener set enabled events {} on {} and schedule next", + pending_events_, static_cast(this)); + pending_events_ = enabled_events; + } + void onEventActivated(uint32_t activated_events) override { + ephermal_events_ |= activated_events; + } + uint32_t getAndClearEphemeralEvents() override { + auto res = ephermal_events_; + ephermal_events_ = 0; + return res; + } + +private: + // The persisted interested events and ready events. + uint32_t pending_events_{}; + // The events set by activate() and will be cleared after the io callback. + uint32_t ephermal_events_{}; +}; + +// A FileEvent implementation which is +class UserSpaceFileEventImpl : public FileEvent { +public: + ~UserSpaceFileEventImpl() override { + // if (schedulable_.enabled()) { + schedulable_.cancel(); + //} + ASSERT(event_counter_ == 1); + --event_counter_; + } + + // Event::FileEvent + void activate(uint32_t events) override { + event_listener_.onEventActivated(events); + if (!schedulable_.enabled()) { + schedulable_.scheduleCallbackNextIteration(); + } + } + + void setEnabled(uint32_t events) override { + event_listener_.onEventEnabled(events); + if (!schedulable_.enabled()) { + schedulable_.scheduleCallbackNextIteration(); + ENVOY_LOG_MISC(debug, "lambdai: user file event setEnabled {} on {} and schedule next", + events, static_cast(this)); + return; + } + ENVOY_LOG_MISC(debug, "lambdai: user file event setEnabled {} on {} and but not schedule next", + events, static_cast(this)); + } + + EventListener& getEventListener() { return event_listener_; } + void onEvents() { cb_(); } + friend class UserSpaceFileEventFactory; + friend class Network::BufferedIoSocketHandleImpl; + +private: + UserSpaceFileEventImpl(Event::FileReadyCb cb, uint32_t events, + SchedulableCallback& schedulable_cb, int& event_counter) + : schedulable_(schedulable_cb), cb_([this, cb]() { + auto all_events = getEventListener().triggeredEvents(); + auto ephemeral_events = getEventListener().getAndClearEphemeralEvents(); + ENVOY_LOG_MISC(debug, "lambdai: us event {} cb allevents = {}, ephermal events = {}", + static_cast(this), all_events, ephemeral_events); + cb(all_events | ephemeral_events); + }), + event_counter_(event_counter) { + event_listener_.onEventEnabled(events); + } + DefaultEventListener event_listener_; + SchedulableCallback& schedulable_; + std::function cb_; + int& event_counter_; +}; + +class UserSpaceFileEventFactory { +public: + static std::unique_ptr + createUserSpaceFileEventImpl(Event::Dispatcher&, Event::FileReadyCb cb, Event::FileTriggerType, + uint32_t events, SchedulableCallback& scheduable_cb, + int& event_counter) { + return std::unique_ptr( + new UserSpaceFileEventImpl(cb, events, scheduable_cb, event_counter)); + } +}; + } // namespace Event } // namespace Envoy diff --git a/source/common/network/BUILD b/source/common/network/BUILD index 6def5e024a4c..6f6634020d14 100644 --- a/source/common/network/BUILD +++ b/source/common/network/BUILD @@ -145,6 +145,7 @@ envoy_cc_library( hdrs = ["io_socket_error_impl.h"], deps = [ "//include/envoy/api:io_error_interface", + "//include/envoy/api:os_sys_calls_interface", "//source/common/common:assert_lib", "//source/common/common:utility_lib", ], @@ -448,3 +449,27 @@ envoy_cc_library( "//source/common/common:macros", ], ) + +envoy_cc_library( + name = "peer_buffer_lib", + hdrs = ["peer_buffer.h"], + deps = [ + ":utility_lib", + "//include/envoy/network:connection_interface", + "//include/envoy/network:transport_socket_interface", + "//source/common/buffer:buffer_lib", + "//source/common/buffer:watermark_buffer_lib", + "//source/common/common:empty_string", + "//source/common/http:headers_lib", + ], +) + +envoy_cc_library( + name = "buffered_io_socket_handle_lib", + srcs = ["buffered_io_socket_handle_impl.cc"], + hdrs = ["buffered_io_socket_handle_impl.h"], + deps = [ + "default_socket_interface_lib", + ":peer_buffer_lib", + ], +) diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc new file mode 100644 index 000000000000..f56b4ff27c55 --- /dev/null +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -0,0 +1,196 @@ +#include "common/network/buffered_io_socket_handle_impl.h" + +#include "envoy/buffer/buffer.h" +#include "envoy/common/platform.h" + +#include "common/api/os_sys_calls_impl.h" +#include "common/common/assert.h" +#include "common/common/utility.h" +#include "common/event/file_event_impl.h" +#include "common/network/address_impl.h" + +#include "absl/container/fixed_array.h" +#include "absl/types/optional.h" + +namespace Envoy { +namespace Network { + +Api::IoCallUint64Result BufferedIoSocketHandleImpl::close() { + ASSERT(!closed_); + if (!write_shutdown_) { + ASSERT(writable_peer_); + // Notify the peer we won't write more data. shutdown(WRITE). + writable_peer_->setWriteEnd(); + // Notify the peer that we no longer accept data. shutdown(RD). + writable_peer_->onPeerDestroy(); + writable_peer_->maybeSetNewData(); + writable_peer_ = nullptr; + write_shutdown_ = true; + } + closed_ = true; + return Api::ioCallUint64ResultNoError(); +} + +bool BufferedIoSocketHandleImpl::isOpen() const { return !closed_; } + +Api::IoCallUint64Result BufferedIoSocketHandleImpl::readv(uint64_t max_length, + Buffer::RawSlice* slices, + uint64_t num_slice) { + if (owned_buffer_.length() == 0) { + if (read_end_stream_) { + return Api::ioCallUint64ResultNoError(); + } else { + return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), + IoSocketError::deleteIoError)}; + } + } else { + absl::FixedArray iov(num_slice); + uint64_t num_slices_to_read = 0; + uint64_t num_bytes_to_read = 0; + for (; num_slices_to_read < num_slice && num_bytes_to_read < max_length; num_slices_to_read++) { + auto min_len = std::min(std::min(owned_buffer_.length(), max_length) - num_bytes_to_read, + uint64_t(slices[num_slices_to_read].len_)); + owned_buffer_.copyOut(num_bytes_to_read, min_len, slices[num_slices_to_read].mem_); + num_bytes_to_read += min_len; + } + ASSERT(num_bytes_to_read <= max_length); + owned_buffer_.drain(num_bytes_to_read); + ENVOY_LOG(trace, "socket {} readv {} bytes", static_cast(this), num_bytes_to_read); + return {num_bytes_to_read, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; + } +} + +Api::IoCallUint64Result BufferedIoSocketHandleImpl::writev(const Buffer::RawSlice* slices, + uint64_t num_slice) { + if (!writable_peer_) { + return sysCallResultToIoCallResult(Api::SysCallSizeResult{-1, SOCKET_ERROR_INTR}); + } + if (writable_peer_->isWriteEndSet() || !writable_peer_->isWritable()) { + return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), + IoSocketError::deleteIoError)}; + } + // Write along with iteration. Buffer guarantee the fragment is always append-able. + uint64_t num_bytes_to_write = 0; + for (uint64_t i = 0; i < num_slice; i++) { + if (slices[i].mem_ != nullptr && slices[i].len_ != 0) { + writable_peer_->getWriteBuffer()->add(slices[i].mem_, slices[i].len_); + num_bytes_to_write += slices[i].len_; + } + } + writable_peer_->maybeSetNewData(); + ENVOY_LOG(trace, "socket {} writev {} bytes", static_cast(this), num_bytes_to_write); + return {num_bytes_to_write, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; +} + +Api::IoCallUint64Result BufferedIoSocketHandleImpl::sendmsg(const Buffer::RawSlice*, uint64_t, int, + const Address::Ip*, + const Address::Instance&) { + return IoSocketError::ioResultSocketInvalidAddress(); +} + +Api::IoCallUint64Result BufferedIoSocketHandleImpl::recvmsg(Buffer::RawSlice*, const uint64_t, + uint32_t, RecvMsgOutput&) { + return IoSocketError::ioResultSocketInvalidAddress(); +} + +Api::IoCallUint64Result BufferedIoSocketHandleImpl::recvmmsg(RawSliceArrays&, uint32_t, + RecvMsgOutput&) { + return IoSocketError::ioResultSocketInvalidAddress(); +} + +Api::IoCallUint64Result BufferedIoSocketHandleImpl::recv(void* buffer, size_t length, int flags) { + // No data and the writer closed. + if (owned_buffer_.length() == 0) { + if (read_end_stream_) { + return sysCallResultToIoCallResult(Api::SysCallSizeResult{-1, SOCKET_ERROR_INTR}); + } else { + return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), + IoSocketError::deleteIoError)}; + } + } else { + auto min_len = std::min(owned_buffer_.length(), length); + owned_buffer_.copyOut(0, min_len, buffer); + if (!(flags & MSG_PEEK)) { + owned_buffer_.drain(min_len); + } + return {min_len, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; + } +} + +bool BufferedIoSocketHandleImpl::supportsMmsg() const { return false; } + +bool BufferedIoSocketHandleImpl::supportsUdpGro() const { return false; } + +Api::SysCallIntResult makeInvalidSyscall() { + return Api::SysCallIntResult{-1, SOCKET_ERROR_NOT_SUP /*SOCKET_ERROR_NOT_SUP*/}; +} + +Api::SysCallIntResult BufferedIoSocketHandleImpl::bind(Address::InstanceConstSharedPtr) { + return makeInvalidSyscall(); +} + +Api::SysCallIntResult BufferedIoSocketHandleImpl::listen(int) { return makeInvalidSyscall(); } + +IoHandlePtr BufferedIoSocketHandleImpl::accept(struct sockaddr*, socklen_t*) { + NOT_IMPLEMENTED_GCOVR_EXCL_LINE; +} + +Api::SysCallIntResult BufferedIoSocketHandleImpl::connect(Address::InstanceConstSharedPtr) { + // Buffered Io handle should always be considered as connected. Use write to determine if peer is + // closed. + return {0, 0}; +} + +Api::SysCallIntResult BufferedIoSocketHandleImpl::setOption(int, int, const void*, socklen_t) { + return makeInvalidSyscall(); +} + +Api::SysCallIntResult BufferedIoSocketHandleImpl::getOption(int, int, void*, socklen_t*) { + return makeInvalidSyscall(); +} + +Api::SysCallIntResult BufferedIoSocketHandleImpl::setBlocking(bool) { return makeInvalidSyscall(); } + +absl::optional BufferedIoSocketHandleImpl::domain() { return absl::nullopt; } + +Address::InstanceConstSharedPtr BufferedIoSocketHandleImpl::localAddress() { + throw EnvoyException(fmt::format("getsockname failed for BufferedIoSocketHandleImpl")); +} + +Address::InstanceConstSharedPtr BufferedIoSocketHandleImpl::peerAddress() { + + throw EnvoyException(fmt::format("getsockname failed for BufferedIoSocketHandleImpl")); +} + +Event::FileEventPtr BufferedIoSocketHandleImpl::createFileEvent(Event::Dispatcher& dispatcher, + Event::FileReadyCb cb, + Event::FileTriggerType trigger_type, + uint32_t events) { + ASSERT(event_counter_ == 0); + ++event_counter_; + io_callback_ = dispatcher.createSchedulableCallback([this]() { user_file_event_->onEvents(); }); + auto res = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( + dispatcher, cb, trigger_type, events, *io_callback_, event_counter_); + user_file_event_ = res.get(); + // Blindly activate the events. + io_callback_->scheduleCallbackNextIteration(); + return res; +} + +Api::SysCallIntResult BufferedIoSocketHandleImpl::shutdown(int how) { + // Support shutdown write. + if ((how == ENVOY_SHUT_WR) || (how == ENVOY_SHUT_RDWR)) { + ASSERT(!closed_); + if (!write_shutdown_) { + ASSERT(writable_peer_); + // Notify the peer we won't write more data. shutdown(WRITE). + writable_peer_->setWriteEnd(); + writable_peer_->maybeSetNewData(); + write_shutdown_ = true; + } + } + return {0, 0}; +} + +} // namespace Network +} // namespace Envoy \ No newline at end of file diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/common/network/buffered_io_socket_handle_impl.h new file mode 100644 index 000000000000..57c2380bc7e6 --- /dev/null +++ b/source/common/network/buffered_io_socket_handle_impl.h @@ -0,0 +1,159 @@ +#pragma once + +#include + +#include "envoy/api/io_error.h" +#include "envoy/api/os_sys_calls.h" +#include "envoy/common/platform.h" +#include "envoy/event/dispatcher.h" +#include "envoy/network/io_handle.h" + +#include "common/buffer/watermark_buffer.h" +#include "common/common/logger.h" +#include "common/event/file_event_impl.h" +#include "common/network/io_socket_error_impl.h" +#include "common/network/peer_buffer.h" + +namespace Envoy { +namespace Network { + +/** + * IoHandle implementation which provides a buffer as data source. It is designed to used by + * Network::ConnectionImpl. Some known limitations include + * 1. It doesn't not include a file descriptor. Do not use "fdDoNotUse". + * 2. It doesn't suppose socket options. Wrap this in ConnectionSocket and implement the socket + * getter/setter options. + * 3. It doesn't suppose UDP interface. + * 4. The peer BufferedIoSocket must be scheduled by the same scheduler to avoid data race. + */ +class BufferedIoSocketHandleImpl : public IoHandle, + public WritablePeer, + public ReadableSource, + protected Logger::Loggable { +public: + BufferedIoSocketHandleImpl() + : closed_{false}, + owned_buffer_( + [this]() -> void { + over_high_watermark_ = false; + if (writable_peer_) { + ENVOY_LOG(debug, "Socket {} switches to low watermark. Notify {}.", + static_cast(this), static_cast(writable_peer_)); + writable_peer_->onPeerBufferWritable(); + } + }, + [this]() -> void { + over_high_watermark_ = true; + // Low to high is checked by peer after peer writes data. + }, + []() -> void {}) {} + + ~BufferedIoSocketHandleImpl() override { ASSERT(closed_); } + + // IoHandle + os_fd_t fdDoNotUse() const override { return INVALID_SOCKET; } + + Api::IoCallUint64Result close() override; + + bool isOpen() const override; + + Api::IoCallUint64Result readv(uint64_t max_length, Buffer::RawSlice* slices, + uint64_t num_slice) override; + + Api::IoCallUint64Result writev(const Buffer::RawSlice* slices, uint64_t num_slice) override; + + Api::IoCallUint64Result sendmsg(const Buffer::RawSlice* slices, uint64_t num_slice, int flags, + const Address::Ip* self_ip, + const Address::Instance& peer_address) override; + + Api::IoCallUint64Result recvmsg(Buffer::RawSlice* slices, const uint64_t num_slice, + uint32_t self_port, RecvMsgOutput& output) override; + + Api::IoCallUint64Result recvmmsg(RawSliceArrays& slices, uint32_t self_port, + RecvMsgOutput& output) override; + Api::IoCallUint64Result recv(void* buffer, size_t length, int flags) override; + + bool supportsMmsg() const override; + bool supportsUdpGro() const override; + + Api::SysCallIntResult bind(Address::InstanceConstSharedPtr address) override; + Api::SysCallIntResult listen(int backlog) override; + IoHandlePtr accept(struct sockaddr* addr, socklen_t* addrlen) override; + Api::SysCallIntResult connect(Address::InstanceConstSharedPtr address) override; + Api::SysCallIntResult setOption(int level, int optname, const void* optval, + socklen_t optlen) override; + Api::SysCallIntResult getOption(int level, int optname, void* optval, socklen_t* optlen) override; + Api::SysCallIntResult setBlocking(bool blocking) override; + absl::optional domain() override; + Address::InstanceConstSharedPtr localAddress() override; + Address::InstanceConstSharedPtr peerAddress() override; + Event::FileEventPtr createFileEvent(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, + Event::FileTriggerType trigger, uint32_t events) override; + Api::SysCallIntResult shutdown(int how) override; + + Buffer::WatermarkBuffer& getBufferForTest() { return owned_buffer_; } + + void scheduleNextEvent() { + // It's possible there is no pending file event so as no io_callback. + if (io_callback_) { + ENVOY_LOG(trace, "Schedule IO callback on {}", static_cast(this)); + io_callback_->scheduleCallbackNextIteration(); + } + } + + void setWritablePeer(WritablePeer* writable_peer) { + // Swapping writable peer is undefined behavior. + ASSERT(!writable_peer_); + ASSERT(!write_shutdown_); + writable_peer_ = writable_peer; + } + + // WritablePeer + void setWriteEnd() override { read_end_stream_ = true; } + bool isWriteEndSet() override { return read_end_stream_; } + void maybeSetNewData() override { + ENVOY_LOG(trace, "{} on socket {}", __FUNCTION__, static_cast(this)); + scheduleNextEvent(); + } + void onPeerDestroy() override { + writable_peer_ = nullptr; + write_shutdown_ = true; + } + void onPeerBufferWritable() override { scheduleNextEvent(); } + bool isWritable() const override { return !isOverHighWatermark(); } + Buffer::Instance* getWriteBuffer() override { return &owned_buffer_; } + + // ReadableSource + bool isPeerShutDownWrite() const override { return read_end_stream_; } + bool isOverHighWatermark() const override { return over_high_watermark_; } + bool isReadable() const override { return isPeerShutDownWrite() || owned_buffer_.length() > 0; } + +private: + // Support isOpen() and close(). IoHandle owner must invoke close() to avoid potential resource + // leak. + bool closed_; + + // The attached file event with this socket. The event is not owned by the socket. + Event::UserSpaceFileEventImpl* user_file_event_; + + // Envoy never schedule two independent IO event on the same socket. Use this counter to verify. + int event_counter_{0}; + + // The schedulable handle of the above event. + Event::SchedulableCallbackPtr io_callback_; + + // True if owned_buffer_ is not addable. Note that owned_buffer_ may have pending data to drain. + bool read_end_stream_{false}; + Buffer::WatermarkBuffer owned_buffer_; + + // Destination of the write(). + WritablePeer* writable_peer_{nullptr}; + + // The flag whether the peer is valid. Any write attempt must check this flag. + bool write_shutdown_{false}; + + bool over_high_watermark_{false}; +}; + +} // namespace Network +} // namespace Envoy \ No newline at end of file diff --git a/source/common/network/io_socket_error_impl.h b/source/common/network/io_socket_error_impl.h index 50d08b55f26a..b98d51f1caf3 100644 --- a/source/common/network/io_socket_error_impl.h +++ b/source/common/network/io_socket_error_impl.h @@ -1,6 +1,7 @@ #pragma once #include "envoy/api/io_error.h" +#include "envoy/api/os_sys_calls_common.h" #include "common/common/assert.h" @@ -33,5 +34,23 @@ class IoSocketError : public Api::IoError { int errno_; }; +// Converts a SysCallSizeResult to IoCallUint64Result. +template +Api::IoCallUint64Result sysCallResultToIoCallResult(const Api::SysCallResult& result) { + if (result.rc_ >= 0) { + // Return nullptr as IoError upon success. + return Api::IoCallUint64Result(result.rc_, + Api::IoErrorPtr(nullptr, IoSocketError::deleteIoError)); + } + RELEASE_ASSERT(result.errno_ != SOCKET_ERROR_INVAL, "Invalid argument passed in."); + return Api::IoCallUint64Result( + /*rc=*/0, + (result.errno_ == SOCKET_ERROR_AGAIN + // EAGAIN is frequent enough that its memory allocation should be avoided. + ? Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), + IoSocketError::deleteIoError) + : Api::IoErrorPtr(new IoSocketError(result.errno_), IoSocketError::deleteIoError))); +} + } // namespace Network } // namespace Envoy diff --git a/source/common/network/peer_buffer.h b/source/common/network/peer_buffer.h new file mode 100644 index 000000000000..6e0da2dc022c --- /dev/null +++ b/source/common/network/peer_buffer.h @@ -0,0 +1,77 @@ +#include + +#include "envoy/buffer/buffer.h" +#include "envoy/common/pure.h" +#include "envoy/network/io_handle.h" +#include "envoy/network/proxy_protocol.h" +#include "envoy/ssl/connection.h" + +#include "common/common/assert.h" +#include "common/common/logger.h" + +#include "absl/types/optional.h" + +namespace Envoy { +namespace Network { + +/** + * The interface for the writer. + */ +class WritablePeer { +public: + virtual ~WritablePeer() = default; + + /** + * Set the flag to indicate no further write from peer. + */ + virtual void setWriteEnd() PURE; + virtual bool isWriteEndSet() PURE; + + /** + * Raised when peer is destroyed. No further write to peer is allowed. + */ + virtual void onPeerDestroy() PURE; + + /** + * Notify that consumable data arrives. The consumable data can be either data to read, or the end + * of stream event. + */ + virtual void maybeSetNewData() PURE; + + /** + * @return the buffer to be written. + */ + virtual Buffer::Instance* getWriteBuffer() PURE; + + /** + * @return false more data is acceptable. + */ + virtual bool isWritable() const PURE; + + /** + * Raised by the peer when the peer switch from high water mark to low. + */ + virtual void onPeerBufferWritable() PURE; + + // virtual bool triggeredHighToLowWatermark() const PURE; + // virtual void clearTriggeredHighToLowWatermark() PURE; + // virtual void setTriggeredHighToLowWatermark() PURE; +}; + +/** + * The interface for the buffer owner who want to consume the buffer. + */ +class ReadableSource { +public: + virtual ~ReadableSource() = default; + + /** + * Read the flag to indicate no further write. Used by early close detection. + */ + virtual bool isPeerShutDownWrite() const PURE; + + virtual bool isOverHighWatermark() const PURE; + virtual bool isReadable() const PURE; +}; +} // namespace Network +} // namespace Envoy \ No newline at end of file diff --git a/test/common/network/BUILD b/test/common/network/BUILD index 31b558b10c50..2fde212fa1b5 100644 --- a/test/common/network/BUILD +++ b/test/common/network/BUILD @@ -399,3 +399,14 @@ envoy_cc_test( "//test/mocks/network:network_mocks", ], ) + +envoy_cc_test( + name = "buffered_io_socket_handle_impl_test", + srcs = ["buffered_io_socket_handle_impl_test.cc"], + deps = [ + "//source/common/common:utility_lib", + "//source/common/network:address_lib", + "//source/common/network:buffered_io_socket_handle_lib", + "//test/mocks/event:event_mocks", + ], +) diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc new file mode 100644 index 000000000000..361edd675248 --- /dev/null +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -0,0 +1,475 @@ +#include + +#include "envoy/event/file_event.h" + +#include "common/buffer/buffer_impl.h" +#include "common/network/buffered_io_socket_handle_impl.h" + +#include "test/mocks/event/mocks.h" + +#include "absl/container/fixed_array.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using testing::_; +using testing::NiceMock; + +namespace Envoy { +namespace Network { +namespace { + +class MockFileEventCallback { +public: + MOCK_METHOD(void, called, (uint32_t arg)); +}; + +class BufferedIoSocketHandleTest : public testing::Test { +public: + BufferedIoSocketHandleTest() : buf_(1024) { + io_handle_ = std::make_unique(); + io_handle_peer_ = std::make_unique(); + io_handle_->setWritablePeer(io_handle_peer_.get()); + io_handle_peer_->setWritablePeer(io_handle_.get()); + } + ~BufferedIoSocketHandleTest() override { + if (io_handle_->isOpen()) { + io_handle_->close(); + } + if (io_handle_peer_->isOpen()) { + io_handle_peer_->close(); + } + } + void expectAgain() { + auto res = io_handle_->recv(buf_.data(), buf_.size(), MSG_PEEK); + EXPECT_FALSE(res.ok()); + EXPECT_EQ(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); + } + NiceMock dispatcher_{}; + + // Owned by BufferedIoSocketHandle. + NiceMock* scheduable_cb_; + MockFileEventCallback cb_; + std::unique_ptr io_handle_; + std::unique_ptr io_handle_peer_; + absl::FixedArray buf_; +}; + +// Test recv side effects. +TEST_F(BufferedIoSocketHandleTest, TestBasicRecv) { + auto res = io_handle_->recv(buf_.data(), buf_.size(), 0); + // EAGAIN. + EXPECT_FALSE(res.ok()); + EXPECT_EQ(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); + io_handle_->setWriteEnd(); + res = io_handle_->recv(buf_.data(), buf_.size(), 0); + EXPECT_FALSE(res.ok()); + EXPECT_NE(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); +} + +// Test recv side effects. +TEST_F(BufferedIoSocketHandleTest, TestBasicPeek) { + auto res = io_handle_->recv(buf_.data(), buf_.size(), MSG_PEEK); + // EAGAIN. + EXPECT_FALSE(res.ok()); + EXPECT_EQ(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); + io_handle_->setWriteEnd(); + res = io_handle_->recv(buf_.data(), buf_.size(), MSG_PEEK); + EXPECT_FALSE(res.ok()); + EXPECT_NE(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); +} + +TEST_F(BufferedIoSocketHandleTest, TestRecvDrain) { + auto& internal_buffer = io_handle_->getBufferForTest(); + internal_buffer.add("abcd"); + auto res = io_handle_->recv(buf_.data(), buf_.size(), 0); + EXPECT_TRUE(res.ok()); + EXPECT_EQ(4, res.rc_); + EXPECT_EQ(absl::string_view(buf_.data(), 4), "abcd"); + EXPECT_EQ(0, internal_buffer.length()); + expectAgain(); +} + +TEST_F(BufferedIoSocketHandleTest, FlowControl) { + auto& internal_buffer = io_handle_->getBufferForTest(); + WritablePeer* handle_as_peer = io_handle_.get(); + internal_buffer.setWatermarks(128); + EXPECT_FALSE(io_handle_->isReadable()); + EXPECT_TRUE(io_handle_peer_->isWritable()); + + std::string big_chunk(256, 'a'); + internal_buffer.add(big_chunk); + EXPECT_TRUE(io_handle_->isReadable()); + EXPECT_FALSE(handle_as_peer->isWritable()); + + bool writable_flipped = false; + // During the repeated recv, the writable flag must switch to true. + while (internal_buffer.length() > 0) { + SCOPED_TRACE(internal_buffer.length()); + EXPECT_TRUE(io_handle_->isReadable()); + bool writable = handle_as_peer->isWritable(); + if (writable) { + writable_flipped = true; + } else { + ASSERT_FALSE(writable_flipped); + } + auto res = io_handle_->recv(buf_.data(), 32, 0); + EXPECT_TRUE(res.ok()); + EXPECT_EQ(32, res.rc_); + } + ASSERT_EQ(0, internal_buffer.length()); + ASSERT_TRUE(writable_flipped); + + // Finally the buffer is empty. + EXPECT_FALSE(io_handle_->isReadable()); + EXPECT_TRUE(handle_as_peer->isWritable()); +} + +TEST_F(BufferedIoSocketHandleTest, EventScheduleBasic) { + scheduable_cb_ = new NiceMock(&dispatcher_); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + auto ev = io_handle_->createFileEvent( + dispatcher_, [this](uint32_t events) { cb_.called(events); }, + Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + + EXPECT_CALL(cb_, called(_)); + scheduable_cb_->invokeCallback(); + ev.reset(); +} + +TEST_F(BufferedIoSocketHandleTest, TestSetEnabledTriggerEventSchedule) { + scheduable_cb_ = new NiceMock(&dispatcher_); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + auto ev = io_handle_->createFileEvent( + dispatcher_, [this](uint32_t events) { cb_.called(events); }, + Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + + ASSERT_TRUE(scheduable_cb_->enabled()); + EXPECT_CALL(cb_, called(Event::FileReadyType::Read)); + scheduable_cb_->invokeCallback(); + ASSERT_FALSE(scheduable_cb_->enabled()); + + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + ev->setEnabled(Event::FileReadyType::Read); + ASSERT_TRUE(scheduable_cb_->enabled()); + EXPECT_CALL(cb_, called(_)); + scheduable_cb_->invokeCallback(); + ASSERT_FALSE(scheduable_cb_->enabled()); + + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + ev->setEnabled(Event::FileReadyType::Write); + ASSERT_TRUE(scheduable_cb_->enabled()); + EXPECT_CALL(cb_, called(Event::FileReadyType::Write)); + scheduable_cb_->invokeCallback(); + ASSERT_FALSE(scheduable_cb_->enabled()); + + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + ev->setEnabled(Event::FileReadyType::Write | Event::FileReadyType::Read); + ASSERT_TRUE(scheduable_cb_->enabled()); + EXPECT_CALL(cb_, called(Event::FileReadyType::Write | Event::FileReadyType::Read)); + scheduable_cb_->invokeCallback(); + ASSERT_FALSE(scheduable_cb_->enabled()); + ev.reset(); +} + +TEST_F(BufferedIoSocketHandleTest, TestReadAndWriteAreEdgeTriggered) { + scheduable_cb_ = new NiceMock(&dispatcher_); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + auto ev = io_handle_->createFileEvent( + dispatcher_, [this](uint32_t events) { cb_.called(events); }, + Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + + EXPECT_CALL(cb_, called(_)); + scheduable_cb_->invokeCallback(); + + // Neither read and write will trigger self readiness. + EXPECT_CALL(cb_, called(_)).Times(0); + + // Drain 1 bytes. + auto& internal_buffer = io_handle_->getBufferForTest(); + internal_buffer.add("abcd"); + auto res = io_handle_->recv(buf_.data(), 1, 0); + EXPECT_TRUE(res.ok()); + EXPECT_EQ(1, res.rc_); + + ASSERT_FALSE(scheduable_cb_->enabled()); + ev.reset(); +} + +TEST_F(BufferedIoSocketHandleTest, TestSetDisabledBlockEventSchedule) { + scheduable_cb_ = new NiceMock(&dispatcher_); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + auto ev = io_handle_->createFileEvent( + dispatcher_, [this](uint32_t events) { cb_.called(events); }, + Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + + ev->setEnabled(0); + + EXPECT_CALL(cb_, called(0)); + scheduable_cb_->invokeCallback(); + + ASSERT_FALSE(scheduable_cb_->enabled()); + ev.reset(); +} + +TEST_F(BufferedIoSocketHandleTest, TestEventResetClearCallback) { + scheduable_cb_ = new NiceMock(&dispatcher_); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + auto ev = io_handle_->createFileEvent( + dispatcher_, [this](uint32_t events) { cb_.called(events); }, + Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + ASSERT_TRUE(scheduable_cb_->enabled()); + + ev.reset(); + ASSERT_FALSE(scheduable_cb_->enabled()); +} + +TEST_F(BufferedIoSocketHandleTest, TestDrainToLowWaterMarkTriggerReadEvent) { + auto& internal_buffer = io_handle_->getBufferForTest(); + WritablePeer* handle_as_peer = io_handle_.get(); + internal_buffer.setWatermarks(128); + EXPECT_FALSE(io_handle_->isReadable()); + EXPECT_TRUE(io_handle_peer_->isWritable()); + + std::string big_chunk(256, 'a'); + internal_buffer.add(big_chunk); + EXPECT_TRUE(io_handle_->isReadable()); + EXPECT_FALSE(handle_as_peer->isWritable()); + + // Clear invoke callback on peer. + scheduable_cb_ = new NiceMock(&dispatcher_); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + auto ev = io_handle_peer_->createFileEvent( + dispatcher_, [this](uint32_t events) { cb_.called(events); }, + Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + ASSERT_TRUE(scheduable_cb_->enabled()); + EXPECT_CALL(cb_, called(_)); + scheduable_cb_->invokeCallback(); + ASSERT_FALSE(scheduable_cb_->enabled()); + + { + auto res = io_handle_->recv(buf_.data(), 1, 0); + EXPECT_FALSE(handle_as_peer->isWritable()); + } + { + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()).Times(1); + auto res = io_handle_->recv(buf_.data(), 232, 0); + EXPECT_TRUE(handle_as_peer->isWritable()); + } + + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()).Times(1); + io_handle_->close(); +} + +TEST_F(BufferedIoSocketHandleTest, TestClose) { + auto& internal_buffer = io_handle_->getBufferForTest(); + internal_buffer.add("abcd"); + std::string accumulator; + scheduable_cb_ = new NiceMock(&dispatcher_); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + bool should_close = false; + auto ev = io_handle_->createFileEvent( + dispatcher_, + [this, &should_close, handle = io_handle_.get(), &accumulator](uint32_t events) { + if (events & Event::FileReadyType::Read) { + auto res = io_handle_->recv(buf_.data(), buf_.size(), 0); + if (res.ok()) { + accumulator += absl::string_view(buf_.data(), res.rc_); + } else if (res.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { + ENVOY_LOG_MISC(debug, "read returns EAGAIN"); + } else { + ENVOY_LOG_MISC(debug, "will close"); + should_close = true; + } + } + }, + Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + scheduable_cb_->invokeCallback(); + + // Not closed yet. + ASSERT_FALSE(should_close); + + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + io_handle_peer_->close(); + + ASSERT_TRUE(scheduable_cb_->enabled()); + scheduable_cb_->invokeCallback(); + ASSERT_TRUE(should_close); + + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()).Times(0); + io_handle_->close(); + EXPECT_EQ(4, accumulator.size()); + ev.reset(); +} + +TEST_F(BufferedIoSocketHandleTest, TestShutdown) { + auto& internal_buffer = io_handle_->getBufferForTest(); + internal_buffer.add("abcd"); + + std::string accumulator; + scheduable_cb_ = new NiceMock(&dispatcher_); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + bool should_close = false; + auto ev = io_handle_->createFileEvent( + dispatcher_, + [this, &should_close, handle = io_handle_.get(), &accumulator](uint32_t events) { + if (events & Event::FileReadyType::Read) { + auto res = io_handle_->recv(buf_.data(), buf_.size(), 0); + if (res.ok()) { + accumulator += absl::string_view(buf_.data(), res.rc_); + } else if (res.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { + ENVOY_LOG_MISC(debug, "read returns EAGAIN"); + } else { + ENVOY_LOG_MISC(debug, "will close"); + should_close = true; + } + } + }, + Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + scheduable_cb_->invokeCallback(); + + // Not closed yet. + ASSERT_FALSE(should_close); + + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + io_handle_peer_->shutdown(ENVOY_SHUT_WR); + + ASSERT_TRUE(scheduable_cb_->enabled()); + scheduable_cb_->invokeCallback(); + ASSERT_TRUE(should_close); + EXPECT_EQ(4, accumulator.size()); + io_handle_->close(); + ev.reset(); +} + +TEST_F(BufferedIoSocketHandleTest, TestWriteToPeer) { + std::string raw_data("0123456789"); + absl::InlinedVector slices{ + // Contains 1 byte. + Buffer::RawSlice{static_cast(raw_data.data()), 1}, + // Contains 0 byte. + Buffer::RawSlice{nullptr, 1}, + // Contains 0 byte. + Buffer::RawSlice{raw_data.data() + 1, 0}, + // Contains 2 byte. + Buffer::RawSlice{raw_data.data() + 1, 2}, + }; + io_handle_peer_->writev(slices.data(), slices.size()); + auto& internal_buffer = io_handle_->getBufferForTest(); + EXPECT_EQ(3, internal_buffer.length()); + EXPECT_EQ("012", internal_buffer.toString()); +} + +TEST_F(BufferedIoSocketHandleTest, TestWriteScheduleWritableEvent) { + std::string accumulator; + scheduable_cb_ = new NiceMock(&dispatcher_); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + bool should_close = false; + auto ev = io_handle_->createFileEvent( + dispatcher_, + [&should_close, handle = io_handle_.get(), &accumulator](uint32_t events) { + if (events & Event::FileReadyType::Read) { + Buffer::OwnedImpl buf; + Buffer::RawSlice slice; + buf.reserve(1024, &slice, 1); + auto res = handle->readv(1024, &slice, 1); + if (res.ok()) { + accumulator += absl::string_view(static_cast(slice.mem_), res.rc_); + } else if (res.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { + ENVOY_LOG_MISC(debug, "read returns EAGAIN"); + } else { + ENVOY_LOG_MISC(debug, "will close"); + should_close = true; + } + } + }, + Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + scheduable_cb_->invokeCallback(); + EXPECT_FALSE(scheduable_cb_->enabled()); + + std::string raw_data("0123456789"); + Buffer::RawSlice slice{static_cast(raw_data.data()), raw_data.size()}; + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + io_handle_peer_->writev(&slice, 1); + + EXPECT_TRUE(scheduable_cb_->enabled()); + scheduable_cb_->invokeCallback(); + EXPECT_EQ("0123456789", accumulator); + EXPECT_FALSE(should_close); + + io_handle_->close(); +} + +TEST_F(BufferedIoSocketHandleTest, TestReadAfterShutdownWrite) { + io_handle_peer_->shutdown(ENVOY_SHUT_WR); + ENVOY_LOG_MISC(debug, "lambdai: after {} shutdown write ", + static_cast(io_handle_peer_.get())); + std::string accumulator; + scheduable_cb_ = new NiceMock(&dispatcher_); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + bool should_close = false; + auto ev = io_handle_peer_->createFileEvent( + dispatcher_, + [&should_close, handle = io_handle_peer_.get(), &accumulator](uint32_t events) { + if (events & Event::FileReadyType::Read) { + Buffer::OwnedImpl buf; + Buffer::RawSlice slice; + buf.reserve(1024, &slice, 1); + auto res = handle->readv(1024, &slice, 1); + if (res.ok()) { + accumulator += absl::string_view(static_cast(slice.mem_), res.rc_); + } else if (res.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { + ENVOY_LOG_MISC(debug, "read returns EAGAIN"); + } else { + ENVOY_LOG_MISC(debug, "will close"); + should_close = true; + } + } + }, + Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + scheduable_cb_->invokeCallback(); + + EXPECT_FALSE(scheduable_cb_->enabled()); + std::string raw_data("0123456789"); + Buffer::RawSlice slice{static_cast(raw_data.data()), raw_data.size()}; + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + io_handle_->writev(&slice, 1); + EXPECT_TRUE(scheduable_cb_->enabled()); + + scheduable_cb_->invokeCallback(); + EXPECT_FALSE(scheduable_cb_->enabled()); + EXPECT_EQ(raw_data, accumulator); + + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + io_handle_->close(); + ev.reset(); +} + +TEST_F(BufferedIoSocketHandleTest, TestNotififyWritableAfterShutdownWrite) { + auto& peer_internal_buffer = io_handle_peer_->getBufferForTest(); + peer_internal_buffer.setWatermarks(128); + std::string big_chunk(256, 'a'); + peer_internal_buffer.add(big_chunk); + EXPECT_FALSE(io_handle_peer_->isWritable()); + + io_handle_peer_->shutdown(ENVOY_SHUT_WR); + ENVOY_LOG_MISC(debug, "lambdai: after {} shutdown write ", + static_cast(io_handle_peer_.get())); + + scheduable_cb_ = new NiceMock(&dispatcher_); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + auto ev = io_handle_->createFileEvent( + dispatcher_, [&, handle = io_handle_.get()](uint32_t) {}, Event::PlatformDefaultTriggerType, + Event::FileReadyType::Read); + scheduable_cb_->invokeCallback(); + EXPECT_FALSE(scheduable_cb_->enabled()); + + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + peer_internal_buffer.drain(peer_internal_buffer.length()); + EXPECT_TRUE(scheduable_cb_->enabled()); + + io_handle_->close(); +} + +} // namespace +} // namespace Network +} // namespace Envoy diff --git a/tools/spelling/spelling_dictionary.txt b/tools/spelling/spelling_dictionary.txt index 12cf11d0bf2b..d544211aa449 100644 --- a/tools/spelling/spelling_dictionary.txt +++ b/tools/spelling/spelling_dictionary.txt @@ -876,6 +876,7 @@ pkey plaintext pluggable pointee +poller popen pos posix From d90cbea28ce7bcb812633e51a1a206d380a52db4 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Tue, 6 Oct 2020 22:23:05 +0000 Subject: [PATCH 042/100] amend Signed-off-by: Yuchen Dai --- source/common/network/BUILD | 4 ---- source/common/network/peer_buffer.h | 14 +------------- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/source/common/network/BUILD b/source/common/network/BUILD index 6f6634020d14..e2b11398130f 100644 --- a/source/common/network/BUILD +++ b/source/common/network/BUILD @@ -454,13 +454,9 @@ envoy_cc_library( name = "peer_buffer_lib", hdrs = ["peer_buffer.h"], deps = [ - ":utility_lib", - "//include/envoy/network:connection_interface", - "//include/envoy/network:transport_socket_interface", "//source/common/buffer:buffer_lib", "//source/common/buffer:watermark_buffer_lib", "//source/common/common:empty_string", - "//source/common/http:headers_lib", ], ) diff --git a/source/common/network/peer_buffer.h b/source/common/network/peer_buffer.h index 6e0da2dc022c..9c0db4ef9f7c 100644 --- a/source/common/network/peer_buffer.h +++ b/source/common/network/peer_buffer.h @@ -1,15 +1,7 @@ -#include +#pragma once #include "envoy/buffer/buffer.h" #include "envoy/common/pure.h" -#include "envoy/network/io_handle.h" -#include "envoy/network/proxy_protocol.h" -#include "envoy/ssl/connection.h" - -#include "common/common/assert.h" -#include "common/common/logger.h" - -#include "absl/types/optional.h" namespace Envoy { namespace Network { @@ -52,10 +44,6 @@ class WritablePeer { * Raised by the peer when the peer switch from high water mark to low. */ virtual void onPeerBufferWritable() PURE; - - // virtual bool triggeredHighToLowWatermark() const PURE; - // virtual void clearTriggeredHighToLowWatermark() PURE; - // virtual void setTriggeredHighToLowWatermark() PURE; }; /** From 622ab925c1a1dbaaa0940fdbc2b83aa39e4220b3 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Wed, 7 Oct 2020 01:04:15 +0000 Subject: [PATCH 043/100] clean up and add impl ::read() Signed-off-by: Yuchen Dai --- source/common/event/file_event_impl.h | 35 ++++++++----------- .../network/buffered_io_socket_handle_impl.cc | 19 +++++++++- .../network/buffered_io_socket_handle_impl.h | 3 ++ .../buffered_io_socket_handle_impl_test.cc | 35 ++++++++++++++++--- 4 files changed, 66 insertions(+), 26 deletions(-) diff --git a/source/common/event/file_event_impl.h b/source/common/event/file_event_impl.h index ae8ace64d2f8..005368cabf2c 100644 --- a/source/common/event/file_event_impl.h +++ b/source/common/event/file_event_impl.h @@ -71,22 +71,16 @@ class EventListener { class DefaultEventListener : public EventListener { public: ~DefaultEventListener() override = default; - uint32_t triggeredEvents() override { - ENVOY_LOG_MISC(debug, - "lambdai: user file event listener triggered events {} on {} and schedule next", - pending_events_, static_cast(this)); - return pending_events_ & (~Event::FileReadyType::Closed); - } - void onEventEnabled(uint32_t enabled_events) override { - ENVOY_LOG_MISC( - debug, "lambdai: user file event listener set enabled events {} on {} and schedule next", - pending_events_, static_cast(this)); - pending_events_ = enabled_events; - } + // Return both read and write. + uint32_t triggeredEvents() override { return pending_events_ & (~Event::FileReadyType::Closed); } + + void onEventEnabled(uint32_t enabled_events) override { pending_events_ = enabled_events; } + void onEventActivated(uint32_t activated_events) override { ephermal_events_ |= activated_events; } + uint32_t getAndClearEphemeralEvents() override { auto res = ephermal_events_; ephermal_events_ = 0; @@ -101,7 +95,7 @@ class DefaultEventListener : public EventListener { }; // A FileEvent implementation which is -class UserSpaceFileEventImpl : public FileEvent { +class UserSpaceFileEventImpl : public FileEvent, Logger::Loggable { public: ~UserSpaceFileEventImpl() override { // if (schedulable_.enabled()) { @@ -121,14 +115,12 @@ class UserSpaceFileEventImpl : public FileEvent { void setEnabled(uint32_t events) override { event_listener_.onEventEnabled(events); - if (!schedulable_.enabled()) { + bool was_enabled = schedulable_.enabled(); + if (!was_enabled) { schedulable_.scheduleCallbackNextIteration(); - ENVOY_LOG_MISC(debug, "lambdai: user file event setEnabled {} on {} and schedule next", - events, static_cast(this)); - return; } - ENVOY_LOG_MISC(debug, "lambdai: user file event setEnabled {} on {} and but not schedule next", - events, static_cast(this)); + ENVOY_LOG(trace, "User space file event {} setEnabled {} on {}. Will {} reschedule.", + static_cast(this), was_enabled ? "not " : ""); } EventListener& getEventListener() { return event_listener_; } @@ -142,8 +134,9 @@ class UserSpaceFileEventImpl : public FileEvent { : schedulable_(schedulable_cb), cb_([this, cb]() { auto all_events = getEventListener().triggeredEvents(); auto ephemeral_events = getEventListener().getAndClearEphemeralEvents(); - ENVOY_LOG_MISC(debug, "lambdai: us event {} cb allevents = {}, ephermal events = {}", - static_cast(this), all_events, ephemeral_events); + ENVOY_LOG(trace, + "User space event {} invokes callbacks on allevents = {}, ephermal events = {}", + static_cast(this), all_events, ephemeral_events); cb(all_events | ephemeral_events); }), event_counter_(event_counter) { diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc index f56b4ff27c55..8d5ad9655ebc 100644 --- a/source/common/network/buffered_io_socket_handle_impl.cc +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -38,7 +38,7 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::readv(uint64_t max_length, uint64_t num_slice) { if (owned_buffer_.length() == 0) { if (read_end_stream_) { - return Api::ioCallUint64ResultNoError(); + return sysCallResultToIoCallResult(Api::SysCallSizeResult{-1, SOCKET_ERROR_INTR}); } else { return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), IoSocketError::deleteIoError)}; @@ -60,6 +60,23 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::readv(uint64_t max_length, } } +Api::IoCallUint64Result BufferedIoSocketHandleImpl::read(Buffer::Instance& buffer, + uint64_t max_length) { + if (owned_buffer_.length() == 0) { + if (read_end_stream_) { + return sysCallResultToIoCallResult(Api::SysCallSizeResult{-1, SOCKET_ERROR_INTR}); + } else { + return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), + IoSocketError::deleteIoError)}; + } + } else { + // TODO(lambdai): Move at slice boundary to move to reduce the copy. + uint64_t min_len = std::min(max_length, owned_buffer_.length()); + buffer.move(owned_buffer_, min_len); + return {min_len, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; + } +} + Api::IoCallUint64Result BufferedIoSocketHandleImpl::writev(const Buffer::RawSlice* slices, uint64_t num_slice) { if (!writable_peer_) { diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/common/network/buffered_io_socket_handle_impl.h index 57c2380bc7e6..cc6405cb8724 100644 --- a/source/common/network/buffered_io_socket_handle_impl.h +++ b/source/common/network/buffered_io_socket_handle_impl.h @@ -60,6 +60,8 @@ class BufferedIoSocketHandleImpl : public IoHandle, Api::IoCallUint64Result readv(uint64_t max_length, Buffer::RawSlice* slices, uint64_t num_slice) override; + Api::IoCallUint64Result read(Buffer::Instance& buffer, uint64_t max_length) override; + Api::IoCallUint64Result writev(const Buffer::RawSlice* slices, uint64_t num_slice) override; Api::IoCallUint64Result sendmsg(const Buffer::RawSlice* slices, uint64_t num_slice, int flags, @@ -90,6 +92,7 @@ class BufferedIoSocketHandleImpl : public IoHandle, Event::FileEventPtr createFileEvent(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, Event::FileTriggerType trigger, uint32_t events) override; Api::SysCallIntResult shutdown(int how) override; + absl::optional lastRoundTripTime() override { return absl::nullopt; } Buffer::WatermarkBuffer& getBufferForTest() { return owned_buffer_; } diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index 361edd675248..4212c8bbbe79 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -66,6 +66,35 @@ TEST_F(BufferedIoSocketHandleTest, TestBasicRecv) { EXPECT_NE(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); } +// Test recv side effects. +TEST_F(BufferedIoSocketHandleTest, TestReadEmpty) { + Buffer::OwnedImpl buf; + auto res = io_handle_->read(buf, 10); + EXPECT_FALSE(res.ok()); + EXPECT_EQ(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); + io_handle_->setWriteEnd(); + res = io_handle_->read(buf, 10); + EXPECT_FALSE(res.ok()); + EXPECT_NE(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); +} + +// Test recv side effects. +TEST_F(BufferedIoSocketHandleTest, TestReadContent) { + Buffer::OwnedImpl buf; + auto& internal_buffer = io_handle_->getBufferForTest(); + internal_buffer.add("abcdefg"); + auto res = io_handle_->read(buf, 3); + EXPECT_TRUE(res.ok()); + EXPECT_EQ(3, res.rc_); + ASSERT_EQ(3, buf.length()); + ASSERT_EQ(4, internal_buffer.length()); + res = io_handle_->read(buf, 10); + EXPECT_TRUE(res.ok()); + EXPECT_EQ(4, res.rc_); + ASSERT_EQ(7, buf.length()); + ASSERT_EQ(0, internal_buffer.length()); +} + // Test recv side effects. TEST_F(BufferedIoSocketHandleTest, TestBasicPeek) { auto res = io_handle_->recv(buf_.data(), buf_.size(), MSG_PEEK); @@ -401,8 +430,7 @@ TEST_F(BufferedIoSocketHandleTest, TestWriteScheduleWritableEvent) { TEST_F(BufferedIoSocketHandleTest, TestReadAfterShutdownWrite) { io_handle_peer_->shutdown(ENVOY_SHUT_WR); - ENVOY_LOG_MISC(debug, "lambdai: after {} shutdown write ", - static_cast(io_handle_peer_.get())); + ENVOY_LOG_MISC(debug, "after {} shutdown write ", static_cast(io_handle_peer_.get())); std::string accumulator; scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); @@ -452,8 +480,7 @@ TEST_F(BufferedIoSocketHandleTest, TestNotififyWritableAfterShutdownWrite) { EXPECT_FALSE(io_handle_peer_->isWritable()); io_handle_peer_->shutdown(ENVOY_SHUT_WR); - ENVOY_LOG_MISC(debug, "lambdai: after {} shutdown write ", - static_cast(io_handle_peer_.get())); + ENVOY_LOG_MISC(debug, "after {} shutdown write", static_cast(io_handle_peer_.get())); scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); From 420e4984c963f218e3bf3c66352a6916066a9d96 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 8 Oct 2020 19:23:43 +0000 Subject: [PATCH 044/100] clang tidy Signed-off-by: Yuchen Dai --- source/common/network/buffered_io_socket_handle_impl.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/common/network/buffered_io_socket_handle_impl.h index cc6405cb8724..6a1257ffd940 100644 --- a/source/common/network/buffered_io_socket_handle_impl.h +++ b/source/common/network/buffered_io_socket_handle_impl.h @@ -32,8 +32,7 @@ class BufferedIoSocketHandleImpl : public IoHandle, protected Logger::Loggable { public: BufferedIoSocketHandleImpl() - : closed_{false}, - owned_buffer_( + : owned_buffer_( [this]() -> void { over_high_watermark_ = false; if (writable_peer_) { @@ -134,7 +133,7 @@ class BufferedIoSocketHandleImpl : public IoHandle, private: // Support isOpen() and close(). IoHandle owner must invoke close() to avoid potential resource // leak. - bool closed_; + bool closed_{false}; // The attached file event with this socket. The event is not owned by the socket. Event::UserSpaceFileEventImpl* user_file_event_; From 4c53d54718a8bbac3c5f5d54525d1c32e4effad5 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 8 Oct 2020 20:13:01 +0000 Subject: [PATCH 045/100] impl BufferedIoSocketHandleImpl:write Signed-off-by: Yuchen Dai --- .../network/buffered_io_socket_handle_impl.cc | 15 ++++++ .../network/buffered_io_socket_handle_impl.h | 2 + .../buffered_io_socket_handle_impl_test.cc | 50 ++++++++++++++++++- 3 files changed, 66 insertions(+), 1 deletion(-) diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc index 8d5ad9655ebc..5f283ce5c59d 100644 --- a/source/common/network/buffered_io_socket_handle_impl.cc +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -99,6 +99,21 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::writev(const Buffer::RawSlic return {num_bytes_to_write, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } +Api::IoCallUint64Result BufferedIoSocketHandleImpl::write(Buffer::Instance& buffer) { + if (!writable_peer_) { + return sysCallResultToIoCallResult(Api::SysCallSizeResult{-1, SOCKET_ERROR_INTR}); + } + if (writable_peer_->isWriteEndSet() || !writable_peer_->isWritable()) { + return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), + IoSocketError::deleteIoError)}; + } + uint64_t num_bytes_to_write = buffer.length(); + writable_peer_->getWriteBuffer()->move(buffer); + writable_peer_->maybeSetNewData(); + ENVOY_LOG(trace, "socket {} writev {} bytes", static_cast(this), num_bytes_to_write); + return {num_bytes_to_write, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; +} + Api::IoCallUint64Result BufferedIoSocketHandleImpl::sendmsg(const Buffer::RawSlice*, uint64_t, int, const Address::Ip*, const Address::Instance&) { diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/common/network/buffered_io_socket_handle_impl.h index 6a1257ffd940..c9fa910f757f 100644 --- a/source/common/network/buffered_io_socket_handle_impl.h +++ b/source/common/network/buffered_io_socket_handle_impl.h @@ -63,6 +63,8 @@ class BufferedIoSocketHandleImpl : public IoHandle, Api::IoCallUint64Result writev(const Buffer::RawSlice* slices, uint64_t num_slice) override; + Api::IoCallUint64Result write(Buffer::Instance& buffer) override; + Api::IoCallUint64Result sendmsg(const Buffer::RawSlice* slices, uint64_t num_slice, int flags, const Address::Ip* self_ip, const Address::Instance& peer_address) override; diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index 4212c8bbbe79..c9741059eec3 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -370,7 +370,15 @@ TEST_F(BufferedIoSocketHandleTest, TestShutdown) { ev.reset(); } -TEST_F(BufferedIoSocketHandleTest, TestWriteToPeer) { +TEST_F(BufferedIoSocketHandleTest, TestWriteByMove) { + Buffer::OwnedImpl buf("0123456789"); + io_handle_peer_->write(buf); + auto& internal_buffer = io_handle_->getBufferForTest(); + EXPECT_EQ("0123456789", internal_buffer.toString()); + EXPECT_EQ(0, buf.length()); +} + +TEST_F(BufferedIoSocketHandleTest, TestWritevToPeer) { std::string raw_data("0123456789"); absl::InlinedVector slices{ // Contains 1 byte. @@ -415,6 +423,46 @@ TEST_F(BufferedIoSocketHandleTest, TestWriteScheduleWritableEvent) { scheduable_cb_->invokeCallback(); EXPECT_FALSE(scheduable_cb_->enabled()); + Buffer::OwnedImpl data_to_write("0123456789"); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + io_handle_peer_->write(data_to_write); + EXPECT_EQ(0, data_to_write.length()); + + EXPECT_TRUE(scheduable_cb_->enabled()); + scheduable_cb_->invokeCallback(); + EXPECT_EQ("0123456789", accumulator); + EXPECT_FALSE(should_close); + + io_handle_->close(); +} + +TEST_F(BufferedIoSocketHandleTest, TestWritevScheduleWritableEvent) { + std::string accumulator; + scheduable_cb_ = new NiceMock(&dispatcher_); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + bool should_close = false; + auto ev = io_handle_->createFileEvent( + dispatcher_, + [&should_close, handle = io_handle_.get(), &accumulator](uint32_t events) { + if (events & Event::FileReadyType::Read) { + Buffer::OwnedImpl buf; + Buffer::RawSlice slice; + buf.reserve(1024, &slice, 1); + auto res = handle->readv(1024, &slice, 1); + if (res.ok()) { + accumulator += absl::string_view(static_cast(slice.mem_), res.rc_); + } else if (res.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { + ENVOY_LOG_MISC(debug, "read returns EAGAIN"); + } else { + ENVOY_LOG_MISC(debug, "will close"); + should_close = true; + } + } + }, + Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + scheduable_cb_->invokeCallback(); + EXPECT_FALSE(scheduable_cb_->enabled()); + std::string raw_data("0123456789"); Buffer::RawSlice slice{static_cast(raw_data.data()), raw_data.size()}; EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); From 812a288bde474cc3ddea4bb36097ebd38c524709 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 8 Oct 2020 21:32:32 +0000 Subject: [PATCH 046/100] comment Signed-off-by: Yuchen Dai --- source/common/event/file_event_impl.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/common/event/file_event_impl.h b/source/common/event/file_event_impl.h index 005368cabf2c..1c1b3058c2eb 100644 --- a/source/common/event/file_event_impl.h +++ b/source/common/event/file_event_impl.h @@ -98,9 +98,9 @@ class DefaultEventListener : public EventListener { class UserSpaceFileEventImpl : public FileEvent, Logger::Loggable { public: ~UserSpaceFileEventImpl() override { - // if (schedulable_.enabled()) { - schedulable_.cancel(); - //} + if (schedulable_.enabled()) { + schedulable_.cancel(); + } ASSERT(event_counter_ == 1); --event_counter_; } From 273447d2303fb67f896495a6e201cb7fc5e1e0d1 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 8 Oct 2020 22:55:36 +0000 Subject: [PATCH 047/100] remove posix header file Signed-off-by: Yuchen Dai --- test/common/network/buffered_io_socket_handle_impl_test.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index c9741059eec3..dca696aff79f 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -1,5 +1,3 @@ -#include - #include "envoy/event/file_event.h" #include "common/buffer/buffer_impl.h" From 1c82dad4da7539263922bbd87c204ada2376fa29 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Fri, 9 Oct 2020 00:38:45 +0000 Subject: [PATCH 048/100] fix Signed-off-by: Yuchen Dai --- source/common/event/BUILD | 1 - .../common/network/buffered_io_socket_handle_impl.h | 1 + source/common/network/connection_impl.h | 1 + test/common/network/BUILD | 11 ----------- test/mocks/event/wrapped_dispatcher.h | 6 ++++++ 5 files changed, 8 insertions(+), 12 deletions(-) diff --git a/source/common/event/BUILD b/source/common/event/BUILD index 185685798145..0202a23aa18a 100644 --- a/source/common/event/BUILD +++ b/source/common/event/BUILD @@ -33,7 +33,6 @@ envoy_cc_library( "//source/common/network:buffered_io_socket_handle_lib", "//source/common/network:connection_lib", "//source/common/network:dns_lib", - "//source/common/network:connection_lib", "//source/common/network:listener_lib", "//source/common/runtime:runtime_features_lib", ] + select({ diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/common/network/buffered_io_socket_handle_impl.h index 94e53eab4dd7..7024626f594c 100644 --- a/source/common/network/buffered_io_socket_handle_impl.h +++ b/source/common/network/buffered_io_socket_handle_impl.h @@ -93,6 +93,7 @@ class BufferedIoSocketHandleImpl : public IoHandle, Event::FileEventPtr createFileEvent(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, Event::FileTriggerType trigger, uint32_t events) override; Api::SysCallIntResult shutdown(int how) override; + absl::optional lastRoundTripTime() override { return {}; }; Buffer::WatermarkBuffer& getBufferForTest() { return owned_buffer_; } void scheduleWriteEvent() {} diff --git a/source/common/network/connection_impl.h b/source/common/network/connection_impl.h index facb7e283882..02c778173464 100644 --- a/source/common/network/connection_impl.h +++ b/source/common/network/connection_impl.h @@ -269,6 +269,7 @@ class ClosingClientConnectionImpl : virtual public ClientConnection { const StreamInfo::StreamInfo& streamInfo() const override; void setDelayedCloseTimeout(std::chrono::milliseconds timeout) override; absl::string_view transportFailureReason() const override; + absl::optional lastRoundTripTime() const override { return {}; } private: void closeSocket(); diff --git a/test/common/network/BUILD b/test/common/network/BUILD index 91750768460b..bb60a9c159de 100644 --- a/test/common/network/BUILD +++ b/test/common/network/BUILD @@ -446,17 +446,6 @@ envoy_cc_test( ], ) -envoy_cc_test( - name = "buffered_io_socket_handle_impl_test", - srcs = ["buffered_io_socket_handle_impl_test.cc"], - deps = [ - "//source/common/common:utility_lib", - "//source/common/network:address_lib", - "//source/common/network:buffered_io_socket_handle_lib", - "//test/mocks/event:event_mocks", - ], -) - envoy_cc_test( name = "transport_socket_options_impl_test", srcs = ["transport_socket_options_impl_test.cc"], diff --git a/test/mocks/event/wrapped_dispatcher.h b/test/mocks/event/wrapped_dispatcher.h index 172066506bf0..712530356007 100644 --- a/test/mocks/event/wrapped_dispatcher.h +++ b/test/mocks/event/wrapped_dispatcher.h @@ -44,6 +44,12 @@ class WrappedDispatcher : public Dispatcher { std::move(transport_socket), options); } + Network::ClientConnectionPtr + createInternalConnection(Network::Address::InstanceConstSharedPtr internal_address, + Network::Address::InstanceConstSharedPtr local_address) override { + return impl_.createInternalConnection(std::move(internal_address), std::move(local_address)); + } + Network::DnsResolverSharedPtr createDnsResolver(const std::vector& resolvers, const bool use_tcp_for_dns_lookups) override { From 8aaeee6c49be49eebf5e734587b68183aac038f6 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Fri, 9 Oct 2020 02:07:13 +0000 Subject: [PATCH 049/100] fix error code on read EOS Signed-off-by: Yuchen Dai --- source/common/network/buffered_io_socket_handle_impl.cc | 4 ++-- test/common/network/buffered_io_socket_handle_impl_test.cc | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc index 5f283ce5c59d..9fa72f22e4cc 100644 --- a/source/common/network/buffered_io_socket_handle_impl.cc +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -38,7 +38,7 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::readv(uint64_t max_length, uint64_t num_slice) { if (owned_buffer_.length() == 0) { if (read_end_stream_) { - return sysCallResultToIoCallResult(Api::SysCallSizeResult{-1, SOCKET_ERROR_INTR}); + return {0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } else { return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), IoSocketError::deleteIoError)}; @@ -64,7 +64,7 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::read(Buffer::Instance& buffe uint64_t max_length) { if (owned_buffer_.length() == 0) { if (read_end_stream_) { - return sysCallResultToIoCallResult(Api::SysCallSizeResult{-1, SOCKET_ERROR_INTR}); + return {0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } else { return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), IoSocketError::deleteIoError)}; diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index 1516f08a380c..6755011c2836 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -73,8 +73,7 @@ TEST_F(BufferedIoSocketHandleTest, TestReadEmpty) { EXPECT_EQ(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); io_handle_->setWriteEnd(); res = io_handle_->read(buf, 10); - EXPECT_FALSE(res.ok()); - EXPECT_NE(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); + EXPECT_TRUE(res.ok()); } // Test recv side effects. From 9f810f2733adc00c83f3cefbf2e810352d33e2fa Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Fri, 9 Oct 2020 02:07:13 +0000 Subject: [PATCH 050/100] fix error code on read EOS Signed-off-by: Yuchen Dai --- source/common/network/buffered_io_socket_handle_impl.cc | 4 ++-- test/common/network/buffered_io_socket_handle_impl_test.cc | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc index 5f283ce5c59d..9fa72f22e4cc 100644 --- a/source/common/network/buffered_io_socket_handle_impl.cc +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -38,7 +38,7 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::readv(uint64_t max_length, uint64_t num_slice) { if (owned_buffer_.length() == 0) { if (read_end_stream_) { - return sysCallResultToIoCallResult(Api::SysCallSizeResult{-1, SOCKET_ERROR_INTR}); + return {0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } else { return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), IoSocketError::deleteIoError)}; @@ -64,7 +64,7 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::read(Buffer::Instance& buffe uint64_t max_length) { if (owned_buffer_.length() == 0) { if (read_end_stream_) { - return sysCallResultToIoCallResult(Api::SysCallSizeResult{-1, SOCKET_ERROR_INTR}); + return {0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } else { return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), IoSocketError::deleteIoError)}; diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index dca696aff79f..a05f096a9767 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -72,8 +72,7 @@ TEST_F(BufferedIoSocketHandleTest, TestReadEmpty) { EXPECT_EQ(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); io_handle_->setWriteEnd(); res = io_handle_->read(buf, 10); - EXPECT_FALSE(res.ok()); - EXPECT_NE(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); + EXPECT_TRUE(res.ok()); } // Test recv side effects. From 6422a4f7d8d90c35f9618f551775193789c3c570 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Tue, 13 Oct 2020 09:01:20 +0000 Subject: [PATCH 051/100] address comments Signed-off-by: Yuchen Dai --- source/common/event/file_event_impl.h | 40 ++++++++++++----- .../network/buffered_io_socket_handle_impl.cc | 43 +++++++++++++------ .../network/buffered_io_socket_handle_impl.h | 33 +++----------- 3 files changed, 65 insertions(+), 51 deletions(-) diff --git a/source/common/event/file_event_impl.h b/source/common/event/file_event_impl.h index 1c1b3058c2eb..05ef260d9ea2 100644 --- a/source/common/event/file_event_impl.h +++ b/source/common/event/file_event_impl.h @@ -49,18 +49,30 @@ class FileEventImpl : public FileEvent, ImplBase { // Forward declare for friend class. class UserSpaceFileEventFactory; -// The interface of populating event watcher and obtaining the active events. The events includes -// Read, Write and Closed. +// The interface of populating event watcher and obtaining the active events. The events are the +// combination of FileReadyType values. The event listener is populated by user event registration +// and io events passively. Also the owner of this listener query the activated events by calling +// triggeredEvents and getAndClearEphemeralEvents. class EventListener { public: virtual ~EventListener() = default; - // Provide the activated events. + // Get the events which are enabled and triggered. virtual uint32_t triggeredEvents() PURE; + // Get the events which are ephemerally activated. Upon returning the ephemeral events are + // cleared. virtual uint32_t getAndClearEphemeralEvents() PURE; - // Callbacks of the event operation. + /** + * FileEvent::setEnabled is invoked. + * @param enabled_events supplied the event of setEnabled. + */ virtual void onEventEnabled(uint32_t enabled_events) PURE; + + /** + * FileEvent::activate is invoked. + * @param enabled_events supplied the event of activate(). + */ virtual void onEventActivated(uint32_t activated_events) PURE; }; @@ -68,6 +80,7 @@ class EventListener { // epoll supports EV_CLOSED but the entire envoy code base supports another poller. The event owner // must assume EV_CLOSED is never activated. Also event owner must tolerate that OS could notify // events which are not actually triggered. +// TODO(lambdai): Add support of delivering EV_CLOSED. class DefaultEventListener : public EventListener { public: ~DefaultEventListener() override = default; @@ -81,11 +94,7 @@ class DefaultEventListener : public EventListener { ephermal_events_ |= activated_events; } - uint32_t getAndClearEphemeralEvents() override { - auto res = ephermal_events_; - ephermal_events_ = 0; - return res; - } + uint32_t getAndClearEphemeralEvents() override { return std::exchange(ephermal_events_, 0); } private: // The persisted interested events and ready events. @@ -94,7 +103,7 @@ class DefaultEventListener : public EventListener { uint32_t ephermal_events_{}; }; -// A FileEvent implementation which is +// A FileEvent implementation which is used to drive BufferedIoSocketHandle. class UserSpaceFileEventImpl : public FileEvent, Logger::Loggable { public: ~UserSpaceFileEventImpl() override { @@ -142,9 +151,20 @@ class UserSpaceFileEventImpl : public FileEvent, Logger::Loggable cb_; + + // The counter owned by io handle. This counter is used to track if more than one file event is + // attached to the same io handle. + // TODO(lambdai): remove this when the full internal connection implementation is landed. int& event_counter_; }; diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc index 9fa72f22e4cc..08d5751e67da 100644 --- a/source/common/network/buffered_io_socket_handle_impl.cc +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -15,6 +15,22 @@ namespace Envoy { namespace Network { +BufferedIoSocketHandleImpl::BufferedIoSocketHandleImpl() + : owned_buffer_( + [this]() -> void { + over_high_watermark_ = false; + if (writable_peer_) { + ENVOY_LOG(debug, "Socket {} switches to low watermark. Notify {}.", + static_cast(this), static_cast(writable_peer_)); + writable_peer_->onPeerBufferWritable(); + } + }, + [this]() -> void { + over_high_watermark_ = true; + // Low to high is checked by peer after peer writes data. + }, + []() -> void {}) {} + Api::IoCallUint64Result BufferedIoSocketHandleImpl::close() { ASSERT(!closed_); if (!write_shutdown_) { @@ -46,17 +62,18 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::readv(uint64_t max_length, } else { absl::FixedArray iov(num_slice); uint64_t num_slices_to_read = 0; - uint64_t num_bytes_to_read = 0; - for (; num_slices_to_read < num_slice && num_bytes_to_read < max_length; num_slices_to_read++) { - auto min_len = std::min(std::min(owned_buffer_.length(), max_length) - num_bytes_to_read, - uint64_t(slices[num_slices_to_read].len_)); - owned_buffer_.copyOut(num_bytes_to_read, min_len, slices[num_slices_to_read].mem_); - num_bytes_to_read += min_len; + uint64_t bytes_to_read = 0; + for (; num_slices_to_read < num_slice && bytes_to_read < max_length; num_slices_to_read++) { + auto max_bytes_to_read = + std::min(std::min(owned_buffer_.length(), max_length) - bytes_to_read, + uint64_t(slices[num_slices_to_read].len_)); + owned_buffer_.copyOut(bytes_to_read, max_bytes_to_read, slices[num_slices_to_read].mem_); + bytes_to_read += max_bytes_to_read; } - ASSERT(num_bytes_to_read <= max_length); - owned_buffer_.drain(num_bytes_to_read); - ENVOY_LOG(trace, "socket {} readv {} bytes", static_cast(this), num_bytes_to_read); - return {num_bytes_to_read, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; + ASSERT(bytes_to_read <= max_length); + owned_buffer_.drain(bytes_to_read); + ENVOY_LOG(trace, "socket {} readv {} bytes", static_cast(this), bytes_to_read); + return {bytes_to_read, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } } @@ -71,9 +88,9 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::read(Buffer::Instance& buffe } } else { // TODO(lambdai): Move at slice boundary to move to reduce the copy. - uint64_t min_len = std::min(max_length, owned_buffer_.length()); - buffer.move(owned_buffer_, min_len); - return {min_len, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; + uint64_t max_bytes_to_read = std::min(max_length, owned_buffer_.length()); + buffer.move(owned_buffer_, max_bytes_to_read); + return {max_bytes_to_read, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } } diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/common/network/buffered_io_socket_handle_impl.h index c9fa910f757f..a78852c22c04 100644 --- a/source/common/network/buffered_io_socket_handle_impl.h +++ b/source/common/network/buffered_io_socket_handle_impl.h @@ -23,62 +23,38 @@ namespace Network { * 1. It doesn't not include a file descriptor. Do not use "fdDoNotUse". * 2. It doesn't suppose socket options. Wrap this in ConnectionSocket and implement the socket * getter/setter options. - * 3. It doesn't suppose UDP interface. - * 4. The peer BufferedIoSocket must be scheduled by the same scheduler to avoid data race. + * 3. It doesn't support UDP interface. + * 4. The peer BufferedIoSocket must be scheduled in the same thread to avoid data race because + * BufferedIoSocketHandle mutates the state of peer handle and no lock is introduced. */ class BufferedIoSocketHandleImpl : public IoHandle, public WritablePeer, public ReadableSource, protected Logger::Loggable { public: - BufferedIoSocketHandleImpl() - : owned_buffer_( - [this]() -> void { - over_high_watermark_ = false; - if (writable_peer_) { - ENVOY_LOG(debug, "Socket {} switches to low watermark. Notify {}.", - static_cast(this), static_cast(writable_peer_)); - writable_peer_->onPeerBufferWritable(); - } - }, - [this]() -> void { - over_high_watermark_ = true; - // Low to high is checked by peer after peer writes data. - }, - []() -> void {}) {} + BufferedIoSocketHandleImpl(); ~BufferedIoSocketHandleImpl() override { ASSERT(closed_); } // IoHandle os_fd_t fdDoNotUse() const override { return INVALID_SOCKET; } - Api::IoCallUint64Result close() override; - bool isOpen() const override; - Api::IoCallUint64Result readv(uint64_t max_length, Buffer::RawSlice* slices, uint64_t num_slice) override; - Api::IoCallUint64Result read(Buffer::Instance& buffer, uint64_t max_length) override; - Api::IoCallUint64Result writev(const Buffer::RawSlice* slices, uint64_t num_slice) override; - Api::IoCallUint64Result write(Buffer::Instance& buffer) override; - Api::IoCallUint64Result sendmsg(const Buffer::RawSlice* slices, uint64_t num_slice, int flags, const Address::Ip* self_ip, const Address::Instance& peer_address) override; - Api::IoCallUint64Result recvmsg(Buffer::RawSlice* slices, const uint64_t num_slice, uint32_t self_port, RecvMsgOutput& output) override; - Api::IoCallUint64Result recvmmsg(RawSliceArrays& slices, uint32_t self_port, RecvMsgOutput& output) override; Api::IoCallUint64Result recv(void* buffer, size_t length, int flags) override; - bool supportsMmsg() const override; bool supportsUdpGro() const override; - Api::SysCallIntResult bind(Address::InstanceConstSharedPtr address) override; Api::SysCallIntResult listen(int backlog) override; IoHandlePtr accept(struct sockaddr* addr, socklen_t* addrlen) override; @@ -141,6 +117,7 @@ class BufferedIoSocketHandleImpl : public IoHandle, Event::UserSpaceFileEventImpl* user_file_event_; // Envoy never schedule two independent IO event on the same socket. Use this counter to verify. + // TODO(lambdai): Remove this when the entire #13361 is done. int event_counter_{0}; // The schedulable handle of the above event. From a978ced52a25841c130ad03811f7905956a8a63a Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Tue, 13 Oct 2020 11:20:57 +0000 Subject: [PATCH 052/100] fix TestShutdown and close Signed-off-by: Yuchen Dai --- .../network/buffered_io_socket_handle_impl.cc | 47 ++++-- .../buffered_io_socket_handle_impl_test.cc | 155 +++++++++++------- 2 files changed, 129 insertions(+), 73 deletions(-) diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc index 08d5751e67da..cc97ab3561b3 100644 --- a/source/common/network/buffered_io_socket_handle_impl.cc +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -52,6 +52,10 @@ bool BufferedIoSocketHandleImpl::isOpen() const { return !closed_; } Api::IoCallUint64Result BufferedIoSocketHandleImpl::readv(uint64_t max_length, Buffer::RawSlice* slices, uint64_t num_slice) { + if (!isOpen()) { + return {0, + Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; + } if (owned_buffer_.length() == 0) { if (read_end_stream_) { return {0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; @@ -79,6 +83,10 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::readv(uint64_t max_length, Api::IoCallUint64Result BufferedIoSocketHandleImpl::read(Buffer::Instance& buffer, uint64_t max_length) { + if (!isOpen()) { + return {0, + Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; + } if (owned_buffer_.length() == 0) { if (read_end_stream_) { return {0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; @@ -96,39 +104,48 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::read(Buffer::Instance& buffe Api::IoCallUint64Result BufferedIoSocketHandleImpl::writev(const Buffer::RawSlice* slices, uint64_t num_slice) { + if (!isOpen()) { + return {0, + Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; + } if (!writable_peer_) { - return sysCallResultToIoCallResult(Api::SysCallSizeResult{-1, SOCKET_ERROR_INTR}); + return sysCallResultToIoCallResult(Api::SysCallSizeResult{-1, SOCKET_ERROR_INVAL}); } if (writable_peer_->isWriteEndSet() || !writable_peer_->isWritable()) { return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), IoSocketError::deleteIoError)}; } // Write along with iteration. Buffer guarantee the fragment is always append-able. - uint64_t num_bytes_to_write = 0; + uint64_t total_bytes_to_write = 0; for (uint64_t i = 0; i < num_slice; i++) { if (slices[i].mem_ != nullptr && slices[i].len_ != 0) { writable_peer_->getWriteBuffer()->add(slices[i].mem_, slices[i].len_); - num_bytes_to_write += slices[i].len_; + total_bytes_to_write += slices[i].len_; } } writable_peer_->maybeSetNewData(); ENVOY_LOG(trace, "socket {} writev {} bytes", static_cast(this), num_bytes_to_write); - return {num_bytes_to_write, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; + return {total_bytes_to_write, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } Api::IoCallUint64Result BufferedIoSocketHandleImpl::write(Buffer::Instance& buffer) { + if (!isOpen()) { + return {0, + Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; + } if (!writable_peer_) { - return sysCallResultToIoCallResult(Api::SysCallSizeResult{-1, SOCKET_ERROR_INTR}); + return {0, + Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; } if (writable_peer_->isWriteEndSet() || !writable_peer_->isWritable()) { return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), IoSocketError::deleteIoError)}; } - uint64_t num_bytes_to_write = buffer.length(); + uint64_t total_bytes_to_write = buffer.length(); writable_peer_->getWriteBuffer()->move(buffer); writable_peer_->maybeSetNewData(); - ENVOY_LOG(trace, "socket {} writev {} bytes", static_cast(this), num_bytes_to_write); - return {num_bytes_to_write, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; + ENVOY_LOG(trace, "socket {} writev {} bytes", static_cast(this), total_bytes_to_write); + return {total_bytes_to_write, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } Api::IoCallUint64Result BufferedIoSocketHandleImpl::sendmsg(const Buffer::RawSlice*, uint64_t, int, @@ -148,21 +165,25 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::recvmmsg(RawSliceArrays&, ui } Api::IoCallUint64Result BufferedIoSocketHandleImpl::recv(void* buffer, size_t length, int flags) { + if (!isOpen()) { + return {0, + Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; + } // No data and the writer closed. if (owned_buffer_.length() == 0) { if (read_end_stream_) { - return sysCallResultToIoCallResult(Api::SysCallSizeResult{-1, SOCKET_ERROR_INTR}); + return {0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } else { return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), IoSocketError::deleteIoError)}; } } else { - auto min_len = std::min(owned_buffer_.length(), length); - owned_buffer_.copyOut(0, min_len, buffer); + auto max_bytes_to_read = std::min(owned_buffer_.length(), length); + owned_buffer_.copyOut(0, max_bytes_to_read, buffer); if (!(flags & MSG_PEEK)) { - owned_buffer_.drain(min_len); + owned_buffer_.drain(max_bytes_to_read); } - return {min_len, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; + return {max_bytes_to_read, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } } diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index a05f096a9767..03e318618278 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -38,9 +38,9 @@ class BufferedIoSocketHandleTest : public testing::Test { } } void expectAgain() { - auto res = io_handle_->recv(buf_.data(), buf_.size(), MSG_PEEK); - EXPECT_FALSE(res.ok()); - EXPECT_EQ(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); + auto result = io_handle_->recv(buf_.data(), buf_.size(), MSG_PEEK); + EXPECT_FALSE(result.ok()); + EXPECT_EQ(Api::IoError::IoErrorCode::Again, result.err_->getErrorCode()); } NiceMock dispatcher_{}; @@ -52,27 +52,54 @@ class BufferedIoSocketHandleTest : public testing::Test { absl::FixedArray buf_; }; +TEST_F(BufferedIoSocketHandleTest, TestErrorOnClosedIoHandle) { + io_handle_->close(); + Api::IoCallUint64Result result{0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; + result = io_handle_->recv(buf_.data(), buf_.size(), 0); + ASSERT(!result.ok()); + ASSERT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); + + Buffer::OwnedImpl buf("0123456789"); + + result = io_handle_->read(buf, 10); + ASSERT(!result.ok()); + ASSERT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); + + Buffer::RawSlice slice; + buf.reserve(1024, &slice, 1); + result = io_handle_->readv(1024, &slice, 1); + ASSERT(!result.ok()); + ASSERT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); + + result = io_handle_->write(buf); + ASSERT(!result.ok()); + ASSERT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); + + result = io_handle_->writev(&slice, 1); + ASSERT(!result.ok()); + ASSERT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); +} + // Test recv side effects. TEST_F(BufferedIoSocketHandleTest, TestBasicRecv) { - auto res = io_handle_->recv(buf_.data(), buf_.size(), 0); + auto result = io_handle_->recv(buf_.data(), buf_.size(), 0); // EAGAIN. - EXPECT_FALSE(res.ok()); - EXPECT_EQ(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); + EXPECT_FALSE(result.ok()); + EXPECT_EQ(Api::IoError::IoErrorCode::Again, result.err_->getErrorCode()); io_handle_->setWriteEnd(); - res = io_handle_->recv(buf_.data(), buf_.size(), 0); - EXPECT_FALSE(res.ok()); - EXPECT_NE(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); + result = io_handle_->recv(buf_.data(), buf_.size(), 0); + EXPECT_TRUE(result.ok()); } // Test recv side effects. TEST_F(BufferedIoSocketHandleTest, TestReadEmpty) { Buffer::OwnedImpl buf; - auto res = io_handle_->read(buf, 10); - EXPECT_FALSE(res.ok()); - EXPECT_EQ(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); + auto result = io_handle_->read(buf, 10); + EXPECT_FALSE(result.ok()); + EXPECT_EQ(Api::IoError::IoErrorCode::Again, result.err_->getErrorCode()); io_handle_->setWriteEnd(); - res = io_handle_->read(buf, 10); - EXPECT_TRUE(res.ok()); + result = io_handle_->read(buf, 10); + EXPECT_TRUE(result.ok()); } // Test recv side effects. @@ -80,36 +107,35 @@ TEST_F(BufferedIoSocketHandleTest, TestReadContent) { Buffer::OwnedImpl buf; auto& internal_buffer = io_handle_->getBufferForTest(); internal_buffer.add("abcdefg"); - auto res = io_handle_->read(buf, 3); - EXPECT_TRUE(res.ok()); - EXPECT_EQ(3, res.rc_); + auto result = io_handle_->read(buf, 3); + EXPECT_TRUE(result.ok()); + EXPECT_EQ(3, result.rc_); ASSERT_EQ(3, buf.length()); ASSERT_EQ(4, internal_buffer.length()); - res = io_handle_->read(buf, 10); - EXPECT_TRUE(res.ok()); - EXPECT_EQ(4, res.rc_); + result = io_handle_->read(buf, 10); + EXPECT_TRUE(result.ok()); + EXPECT_EQ(4, result.rc_); ASSERT_EQ(7, buf.length()); ASSERT_EQ(0, internal_buffer.length()); } // Test recv side effects. TEST_F(BufferedIoSocketHandleTest, TestBasicPeek) { - auto res = io_handle_->recv(buf_.data(), buf_.size(), MSG_PEEK); + auto result = io_handle_->recv(buf_.data(), buf_.size(), MSG_PEEK); // EAGAIN. - EXPECT_FALSE(res.ok()); - EXPECT_EQ(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); + EXPECT_FALSE(result.ok()); + EXPECT_EQ(Api::IoError::IoErrorCode::Again, result.err_->getErrorCode()); io_handle_->setWriteEnd(); - res = io_handle_->recv(buf_.data(), buf_.size(), MSG_PEEK); - EXPECT_FALSE(res.ok()); - EXPECT_NE(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); + result = io_handle_->recv(buf_.data(), buf_.size(), MSG_PEEK); + EXPECT_TRUE(result.ok()); } TEST_F(BufferedIoSocketHandleTest, TestRecvDrain) { auto& internal_buffer = io_handle_->getBufferForTest(); internal_buffer.add("abcd"); - auto res = io_handle_->recv(buf_.data(), buf_.size(), 0); - EXPECT_TRUE(res.ok()); - EXPECT_EQ(4, res.rc_); + auto result = io_handle_->recv(buf_.data(), buf_.size(), 0); + EXPECT_TRUE(result.ok()); + EXPECT_EQ(4, result.rc_); EXPECT_EQ(absl::string_view(buf_.data(), 4), "abcd"); EXPECT_EQ(0, internal_buffer.length()); expectAgain(); @@ -138,9 +164,9 @@ TEST_F(BufferedIoSocketHandleTest, FlowControl) { } else { ASSERT_FALSE(writable_flipped); } - auto res = io_handle_->recv(buf_.data(), 32, 0); - EXPECT_TRUE(res.ok()); - EXPECT_EQ(32, res.rc_); + auto result = io_handle_->recv(buf_.data(), 32, 0); + EXPECT_TRUE(result.ok()); + EXPECT_EQ(32, result.rc_); } ASSERT_EQ(0, internal_buffer.length()); ASSERT_TRUE(writable_flipped); @@ -213,9 +239,9 @@ TEST_F(BufferedIoSocketHandleTest, TestReadAndWriteAreEdgeTriggered) { // Drain 1 bytes. auto& internal_buffer = io_handle_->getBufferForTest(); internal_buffer.add("abcd"); - auto res = io_handle_->recv(buf_.data(), 1, 0); - EXPECT_TRUE(res.ok()); - EXPECT_EQ(1, res.rc_); + auto result = io_handle_->recv(buf_.data(), 1, 0); + EXPECT_TRUE(result.ok()); + EXPECT_EQ(1, result.rc_); ASSERT_FALSE(scheduable_cb_->enabled()); ev.reset(); @@ -273,12 +299,12 @@ TEST_F(BufferedIoSocketHandleTest, TestDrainToLowWaterMarkTriggerReadEvent) { ASSERT_FALSE(scheduable_cb_->enabled()); { - auto res = io_handle_->recv(buf_.data(), 1, 0); + auto result = io_handle_->recv(buf_.data(), 1, 0); EXPECT_FALSE(handle_as_peer->isWritable()); } { EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()).Times(1); - auto res = io_handle_->recv(buf_.data(), 232, 0); + auto result = io_handle_->recv(buf_.data(), 232, 0); EXPECT_TRUE(handle_as_peer->isWritable()); } @@ -297,18 +323,25 @@ TEST_F(BufferedIoSocketHandleTest, TestClose) { dispatcher_, [this, &should_close, handle = io_handle_.get(), &accumulator](uint32_t events) { if (events & Event::FileReadyType::Read) { - auto res = io_handle_->recv(buf_.data(), buf_.size(), 0); - if (res.ok()) { - accumulator += absl::string_view(buf_.data(), res.rc_); - } else if (res.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { + auto result = io_handle_->recv(buf_.data(), buf_.size(), 0); + if (result.ok()) { + accumulator += absl::string_view(buf_.data(), result.rc_); + } else if (result.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { ENVOY_LOG_MISC(debug, "read returns EAGAIN"); } else { ENVOY_LOG_MISC(debug, "will close"); should_close = true; } } + if (events & Event::FileReadyType::Write) { + Buffer::OwnedImpl buf(""); + auto result = io_handle_->write(buf); + if (!result.ok() && result.err_->getErrorCode() != Api::IoError::IoErrorCode::Again) { + should_close = true; + } + } }, - Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + Event::PlatformDefaultTriggerType, Event::FileReadyType::Read | Event::FileReadyType::Write); scheduable_cb_->invokeCallback(); // Not closed yet. @@ -327,7 +360,9 @@ TEST_F(BufferedIoSocketHandleTest, TestClose) { ev.reset(); } -TEST_F(BufferedIoSocketHandleTest, TestShutdown) { +// Test that a readable event is raised when peer shutdown write. Also confirm read will return +// EAGAIN. +TEST_F(BufferedIoSocketHandleTest, TestShutDownRaiseEvent) { auto& internal_buffer = io_handle_->getBufferForTest(); internal_buffer.add("abcd"); @@ -339,10 +374,10 @@ TEST_F(BufferedIoSocketHandleTest, TestShutdown) { dispatcher_, [this, &should_close, handle = io_handle_.get(), &accumulator](uint32_t events) { if (events & Event::FileReadyType::Read) { - auto res = io_handle_->recv(buf_.data(), buf_.size(), 0); - if (res.ok()) { - accumulator += absl::string_view(buf_.data(), res.rc_); - } else if (res.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { + auto result = io_handle_->recv(buf_.data(), buf_.size(), 0); + if (result.ok()) { + accumulator += absl::string_view(buf_.data(), result.rc_); + } else if (result.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { ENVOY_LOG_MISC(debug, "read returns EAGAIN"); } else { ENVOY_LOG_MISC(debug, "will close"); @@ -361,7 +396,7 @@ TEST_F(BufferedIoSocketHandleTest, TestShutdown) { ASSERT_TRUE(scheduable_cb_->enabled()); scheduable_cb_->invokeCallback(); - ASSERT_TRUE(should_close); + ASSERT_FALSE(should_close); EXPECT_EQ(4, accumulator.size()); io_handle_->close(); ev.reset(); @@ -405,10 +440,10 @@ TEST_F(BufferedIoSocketHandleTest, TestWriteScheduleWritableEvent) { Buffer::OwnedImpl buf; Buffer::RawSlice slice; buf.reserve(1024, &slice, 1); - auto res = handle->readv(1024, &slice, 1); - if (res.ok()) { - accumulator += absl::string_view(static_cast(slice.mem_), res.rc_); - } else if (res.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { + auto result = handle->readv(1024, &slice, 1); + if (result.ok()) { + accumulator += absl::string_view(static_cast(slice.mem_), result.rc_); + } else if (result.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { ENVOY_LOG_MISC(debug, "read returns EAGAIN"); } else { ENVOY_LOG_MISC(debug, "will close"); @@ -445,10 +480,10 @@ TEST_F(BufferedIoSocketHandleTest, TestWritevScheduleWritableEvent) { Buffer::OwnedImpl buf; Buffer::RawSlice slice; buf.reserve(1024, &slice, 1); - auto res = handle->readv(1024, &slice, 1); - if (res.ok()) { - accumulator += absl::string_view(static_cast(slice.mem_), res.rc_); - } else if (res.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { + auto result = handle->readv(1024, &slice, 1); + if (result.ok()) { + accumulator += absl::string_view(static_cast(slice.mem_), result.rc_); + } else if (result.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { ENVOY_LOG_MISC(debug, "read returns EAGAIN"); } else { ENVOY_LOG_MISC(debug, "will close"); @@ -487,10 +522,10 @@ TEST_F(BufferedIoSocketHandleTest, TestReadAfterShutdownWrite) { Buffer::OwnedImpl buf; Buffer::RawSlice slice; buf.reserve(1024, &slice, 1); - auto res = handle->readv(1024, &slice, 1); - if (res.ok()) { - accumulator += absl::string_view(static_cast(slice.mem_), res.rc_); - } else if (res.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { + auto result = handle->readv(1024, &slice, 1); + if (result.ok()) { + accumulator += absl::string_view(static_cast(slice.mem_), result.rc_); + } else if (result.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { ENVOY_LOG_MISC(debug, "read returns EAGAIN"); } else { ENVOY_LOG_MISC(debug, "will close"); From 0cf62b4b8d8434ce492c11f2b2dab6d3e2b95ebc Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Tue, 13 Oct 2020 16:01:28 +0000 Subject: [PATCH 053/100] fix Signed-off-by: Yuchen Dai --- source/common/event/file_event_impl.h | 6 ++++++ source/common/network/buffered_io_socket_handle_impl.cc | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/source/common/event/file_event_impl.h b/source/common/event/file_event_impl.h index 05ef260d9ea2..5f0615feb02d 100644 --- a/source/common/event/file_event_impl.h +++ b/source/common/event/file_event_impl.h @@ -116,6 +116,9 @@ class UserSpaceFileEventImpl : public FileEvent, Logger::LoggablemaybeSetNewData(); - ENVOY_LOG(trace, "socket {} writev {} bytes", static_cast(this), num_bytes_to_write); + ENVOY_LOG(trace, "socket {} writev {} bytes", static_cast(this), total_bytes_to_write); return {total_bytes_to_write, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } From 09c1adfe2782190c69fa94d2c3ef18a15d3fbd8b Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Wed, 14 Oct 2020 06:54:35 +0000 Subject: [PATCH 054/100] fix log and comments Signed-off-by: Yuchen Dai --- source/common/event/file_event_impl.h | 4 ++-- source/common/network/buffered_io_socket_handle_impl.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/source/common/event/file_event_impl.h b/source/common/event/file_event_impl.h index 5f0615feb02d..8ef95f1a3d8e 100644 --- a/source/common/event/file_event_impl.h +++ b/source/common/event/file_event_impl.h @@ -134,8 +134,8 @@ class UserSpaceFileEventImpl : public FileEvent, Logger::Loggable(this), was_enabled ? "not " : ""); + ENVOY_LOG(trace, "User space file event {} set events {}. Will {} reschedule.", + static_cast(this), events, was_enabled ? "not " : ""); } EventListener& getEventListener() { return event_listener_; } diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/common/network/buffered_io_socket_handle_impl.h index a78852c22c04..38d82d129fab 100644 --- a/source/common/network/buffered_io_socket_handle_impl.h +++ b/source/common/network/buffered_io_socket_handle_impl.h @@ -21,7 +21,7 @@ namespace Network { * IoHandle implementation which provides a buffer as data source. It is designed to used by * Network::ConnectionImpl. Some known limitations include * 1. It doesn't not include a file descriptor. Do not use "fdDoNotUse". - * 2. It doesn't suppose socket options. Wrap this in ConnectionSocket and implement the socket + * 2. It doesn't support socket options. Wrap this in ConnectionSocket and implement the socket * getter/setter options. * 3. It doesn't support UDP interface. * 4. The peer BufferedIoSocket must be scheduled in the same thread to avoid data race because From b73ced39e8894d03cbdc96e03a01e826993f85de Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Wed, 14 Oct 2020 22:08:19 +0000 Subject: [PATCH 055/100] addressing comment Signed-off-by: Yuchen Dai --- .../network/buffered_io_socket_handle_impl.cc | 95 ++++++++++--------- .../network/buffered_io_socket_handle_impl.h | 4 - .../buffered_io_socket_handle_impl_test.cc | 70 ++++++++++++++ 3 files changed, 119 insertions(+), 50 deletions(-) diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc index e4533f6701df..efeb9793cd96 100644 --- a/source/common/network/buffered_io_socket_handle_impl.cc +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -15,6 +15,11 @@ namespace Envoy { namespace Network { +namespace { +Api::SysCallIntResult makeInvalidSyscall() { + return Api::SysCallIntResult{-1, SOCKET_ERROR_NOT_SUP}; +} +} // namespace BufferedIoSocketHandleImpl::BufferedIoSocketHandleImpl() : owned_buffer_( [this]() -> void { @@ -63,22 +68,20 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::readv(uint64_t max_length, return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), IoSocketError::deleteIoError)}; } - } else { - absl::FixedArray iov(num_slice); - uint64_t num_slices_to_read = 0; - uint64_t bytes_to_read = 0; - for (; num_slices_to_read < num_slice && bytes_to_read < max_length; num_slices_to_read++) { - auto max_bytes_to_read = - std::min(std::min(owned_buffer_.length(), max_length) - bytes_to_read, - uint64_t(slices[num_slices_to_read].len_)); - owned_buffer_.copyOut(bytes_to_read, max_bytes_to_read, slices[num_slices_to_read].mem_); - bytes_to_read += max_bytes_to_read; - } - ASSERT(bytes_to_read <= max_length); - owned_buffer_.drain(bytes_to_read); - ENVOY_LOG(trace, "socket {} readv {} bytes", static_cast(this), bytes_to_read); - return {bytes_to_read, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } + absl::FixedArray iov(num_slice); + uint64_t num_slices_to_read = 0; + uint64_t bytes_to_read = 0; + for (; num_slices_to_read < num_slice && bytes_to_read < max_length; num_slices_to_read++) { + auto max_bytes_to_read = std::min(std::min(owned_buffer_.length(), max_length) - bytes_to_read, + uint64_t(slices[num_slices_to_read].len_)); + owned_buffer_.copyOut(bytes_to_read, max_bytes_to_read, slices[num_slices_to_read].mem_); + bytes_to_read += max_bytes_to_read; + } + ASSERT(bytes_to_read <= max_length); + owned_buffer_.drain(bytes_to_read); + ENVOY_LOG(trace, "socket {} readv {} bytes", static_cast(this), bytes_to_read); + return {bytes_to_read, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } Api::IoCallUint64Result BufferedIoSocketHandleImpl::read(Buffer::Instance& buffer, @@ -94,12 +97,11 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::read(Buffer::Instance& buffe return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), IoSocketError::deleteIoError)}; } - } else { - // TODO(lambdai): Move at slice boundary to move to reduce the copy. - uint64_t max_bytes_to_read = std::min(max_length, owned_buffer_.length()); - buffer.move(owned_buffer_, max_bytes_to_read); - return {max_bytes_to_read, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } + // TODO(lambdai): Move at slice boundary to move to reduce the copy. + uint64_t max_bytes_to_read = std::min(max_length, owned_buffer_.length()); + buffer.move(owned_buffer_, max_bytes_to_read); + return {max_bytes_to_read, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } Api::IoCallUint64Result BufferedIoSocketHandleImpl::writev(const Buffer::RawSlice* slices, @@ -111,7 +113,11 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::writev(const Buffer::RawSlic if (!writable_peer_) { return sysCallResultToIoCallResult(Api::SysCallSizeResult{-1, SOCKET_ERROR_INVAL}); } - if (writable_peer_->isWriteEndSet() || !writable_peer_->isWritable()) { + if (writable_peer_->isWriteEndSet()) { + // EPIPE or ENOTCONN + return {0, Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; + } + if (!writable_peer_->isWritable()) { return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), IoSocketError::deleteIoError)}; } @@ -137,7 +143,11 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::write(Buffer::Instance& buff return {0, Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; } - if (writable_peer_->isWriteEndSet() || !writable_peer_->isWritable()) { + if (writable_peer_->isWriteEndSet()) { + // EPIPE or ENOTCONN + return {0, Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; + } + if (!writable_peer_->isWritable()) { return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), IoSocketError::deleteIoError)}; } @@ -177,24 +187,19 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::recv(void* buffer, size_t le return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), IoSocketError::deleteIoError)}; } - } else { - auto max_bytes_to_read = std::min(owned_buffer_.length(), length); - owned_buffer_.copyOut(0, max_bytes_to_read, buffer); - if (!(flags & MSG_PEEK)) { - owned_buffer_.drain(max_bytes_to_read); - } - return {max_bytes_to_read, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } + auto max_bytes_to_read = std::min(owned_buffer_.length(), length); + owned_buffer_.copyOut(0, max_bytes_to_read, buffer); + if (!(flags & MSG_PEEK)) { + owned_buffer_.drain(max_bytes_to_read); + } + return {max_bytes_to_read, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } bool BufferedIoSocketHandleImpl::supportsMmsg() const { return false; } bool BufferedIoSocketHandleImpl::supportsUdpGro() const { return false; } -Api::SysCallIntResult makeInvalidSyscall() { - return Api::SysCallIntResult{-1, SOCKET_ERROR_NOT_SUP /*SOCKET_ERROR_NOT_SUP*/}; -} - Api::SysCallIntResult BufferedIoSocketHandleImpl::bind(Address::InstanceConstSharedPtr) { return makeInvalidSyscall(); } @@ -206,8 +211,8 @@ IoHandlePtr BufferedIoSocketHandleImpl::accept(struct sockaddr*, socklen_t*) { } Api::SysCallIntResult BufferedIoSocketHandleImpl::connect(Address::InstanceConstSharedPtr) { - // Buffered Io handle should always be considered as connected. Use write to determine if peer is - // closed. + // Buffered Io handle should always be considered as connected. + // Use write or read to determine if peer is closed. return {0, 0}; } @@ -228,7 +233,6 @@ Address::InstanceConstSharedPtr BufferedIoSocketHandleImpl::localAddress() { } Address::InstanceConstSharedPtr BufferedIoSocketHandleImpl::peerAddress() { - throw EnvoyException(fmt::format("getsockname failed for BufferedIoSocketHandleImpl")); } @@ -249,18 +253,17 @@ Event::FileEventPtr BufferedIoSocketHandleImpl::createFileEvent(Event::Dispatche Api::SysCallIntResult BufferedIoSocketHandleImpl::shutdown(int how) { // Support shutdown write. - if ((how == ENVOY_SHUT_WR) || (how == ENVOY_SHUT_RDWR)) { - ASSERT(!closed_); - if (!write_shutdown_) { - ASSERT(writable_peer_); - // Notify the peer we won't write more data. shutdown(WRITE). - writable_peer_->setWriteEnd(); - writable_peer_->maybeSetNewData(); - write_shutdown_ = true; - } + ASSERT(how == ENVOY_SHUT_WR); + ASSERT(!closed_); + if (!write_shutdown_) { + ASSERT(writable_peer_); + // Notify the peer we won't write more data. + writable_peer_->setWriteEnd(); + writable_peer_->maybeSetNewData(); + write_shutdown_ = true; } return {0, 0}; -} +} // namespace Network } // namespace Network } // namespace Envoy \ No newline at end of file diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/common/network/buffered_io_socket_handle_impl.h index a78852c22c04..0789232aa260 100644 --- a/source/common/network/buffered_io_socket_handle_impl.h +++ b/source/common/network/buffered_io_socket_handle_impl.h @@ -116,10 +116,6 @@ class BufferedIoSocketHandleImpl : public IoHandle, // The attached file event with this socket. The event is not owned by the socket. Event::UserSpaceFileEventImpl* user_file_event_; - // Envoy never schedule two independent IO event on the same socket. Use this counter to verify. - // TODO(lambdai): Remove this when the entire #13361 is done. - int event_counter_{0}; - // The schedulable handle of the above event. Event::SchedulableCallbackPtr io_callback_; diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index 03e318618278..d6a970cea9f6 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -2,6 +2,7 @@ #include "common/buffer/buffer_impl.h" #include "common/network/buffered_io_socket_handle_impl.h" +#include "common/network/address_impl.h" #include "test/mocks/event/mocks.h" @@ -16,6 +17,11 @@ namespace Envoy { namespace Network { namespace { +MATCHER(IsInvalidateAddress, "") { + return arg.err_->getErrorCode() == Api::IoError::IoErrorCode::NoSupport; +} + +MATCHER(IsNotSupportedResult, "") { return arg.errno_ == SOCKET_ERROR_NOT_SUP; } class MockFileEventCallback { public: MOCK_METHOD(void, called, (uint32_t arg)); @@ -402,6 +408,16 @@ TEST_F(BufferedIoSocketHandleTest, TestShutDownRaiseEvent) { ev.reset(); } +TEST_F(BufferedIoSocketHandleTest, TestRepeatedShutdownWR) { + EXPECT_EQ(io_handle_peer_->shutdown(ENVOY_SHUT_WR).rc_, 0); + EXPECT_EQ(io_handle_peer_->shutdown(ENVOY_SHUT_WR).rc_, 0); +} + +TEST_F(BufferedIoSocketHandleTest, TestShutDownOptionsNotSupported) { + ASSERT_DEATH(io_handle_peer_->shutdown(ENVOY_SHUT_RD), ""); + ASSERT_DEATH(io_handle_peer_->shutdown(ENVOY_SHUT_RDWR), ""); +} + TEST_F(BufferedIoSocketHandleTest, TestWriteByMove) { Buffer::OwnedImpl buf("0123456789"); io_handle_peer_->write(buf); @@ -577,6 +593,60 @@ TEST_F(BufferedIoSocketHandleTest, TestNotififyWritableAfterShutdownWrite) { io_handle_->close(); } +TEST_F(BufferedIoSocketHandleTest, TestNotSupportingMmsg) { + EXPECT_FALSE(io_handle_->supportsMmsg()); +} + +TEST_F(BufferedIoSocketHandleTest, TestNotSupportsUdpGro) { + EXPECT_FALSE(io_handle_->supportsUdpGro()); +} + +class BufferedIoSocketHandleNotImplementedTest : public testing::Test { +public: + BufferedIoSocketHandleNotImplementedTest() { + io_handle_ = std::make_unique(); + io_handle_peer_ = std::make_unique(); + io_handle_->setWritablePeer(io_handle_peer_.get()); + io_handle_peer_->setWritablePeer(io_handle_.get()); + } + ~BufferedIoSocketHandleNotImplementedTest() override { + if (io_handle_->isOpen()) { + io_handle_->close(); + } + if (io_handle_peer_->isOpen()) { + io_handle_peer_->close(); + } + } + + std::unique_ptr io_handle_; + std::unique_ptr io_handle_peer_; + Buffer::RawSlice slice_; +}; + +TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnSendmsg) { + EXPECT_THAT(io_handle_->sendmsg(&slice_, 0, 0, nullptr, + Network::Address::EnvoyInternalInstance("listener_id")), + IsInvalidateAddress()); +} +TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnRecvmsg) { + Network::IoHandle::RecvMsgOutput output_is_ignored(1, nullptr); + EXPECT_THAT(io_handle_->recvmsg(&slice_, 0, 0, output_is_ignored), IsInvalidateAddress()); +} +TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnRecvmmsg) { + RawSliceArrays slices_is_ignored(1, absl::FixedArray({slice_})); + Network::IoHandle::RecvMsgOutput output_is_ignored(1, nullptr); + EXPECT_THAT(io_handle_->recvmmsg(slices_is_ignored, 0, output_is_ignored), IsInvalidateAddress()); +} +TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnBind) { + auto address_is_ignored = + std::make_shared("listener_id"); + EXPECT_THAT(io_handle_->bind(address_is_ignored), IsNotSupportedResult()); +} + +TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnListen) { + int back_log_is_ignored = 0; + EXPECT_THAT(io_handle_->listen(back_log_is_ignored), IsNotSupportedResult()); +} } // namespace } // namespace Network } // namespace Envoy From 49bd8d6406b961f5b0eb6a724c4c5b680f861dea Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Wed, 14 Oct 2020 22:08:31 +0000 Subject: [PATCH 056/100] remove event counter Signed-off-by: Yuchen Dai --- source/common/event/file_event_impl.h | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/source/common/event/file_event_impl.h b/source/common/event/file_event_impl.h index 5f0615feb02d..c0dd4b77d898 100644 --- a/source/common/event/file_event_impl.h +++ b/source/common/event/file_event_impl.h @@ -110,8 +110,6 @@ class UserSpaceFileEventImpl : public FileEvent, Logger::Loggable(this), all_events, ephemeral_events); cb(all_events | ephemeral_events); - }), - event_counter_(event_counter) { + }) { event_listener_.onEventEnabled(events); } @@ -167,11 +164,6 @@ class UserSpaceFileEventImpl : public FileEvent, Logger::Loggable cb_; - - // The counter owned by io handle. This counter is used to track if more than one file event is - // attached to the same io handle. - // TODO(lambdai): remove this when the full internal connection implementation is landed. - int& event_counter_; }; class UserSpaceFileEventFactory { From 55b9acca7478385293d6d2983264739270b70965 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Wed, 14 Oct 2020 22:32:45 +0000 Subject: [PATCH 057/100] more test and event counter fix Signed-off-by: Yuchen Dai --- source/common/event/file_event_impl.h | 5 ++--- .../network/buffered_io_socket_handle_impl.cc | 7 ++++--- .../buffered_io_socket_handle_impl_test.cc | 21 +++++++++++++++++++ 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/source/common/event/file_event_impl.h b/source/common/event/file_event_impl.h index c0dd4b77d898..ac2d56ecbc10 100644 --- a/source/common/event/file_event_impl.h +++ b/source/common/event/file_event_impl.h @@ -170,10 +170,9 @@ class UserSpaceFileEventFactory { public: static std::unique_ptr createUserSpaceFileEventImpl(Event::Dispatcher&, Event::FileReadyCb cb, Event::FileTriggerType, - uint32_t events, SchedulableCallback& scheduable_cb, - int& event_counter) { + uint32_t events, SchedulableCallback& scheduable_cb) { return std::unique_ptr( - new UserSpaceFileEventImpl(cb, events, scheduable_cb, event_counter)); + new UserSpaceFileEventImpl(cb, events, scheduable_cb)); } }; diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc index efeb9793cd96..dc34bfa369ab 100644 --- a/source/common/network/buffered_io_socket_handle_impl.cc +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -139,14 +139,17 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::write(Buffer::Instance& buff return {0, Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; } + // Closed peer. if (!writable_peer_) { return {0, Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; } + // Write to a shutdown peer. if (writable_peer_->isWriteEndSet()) { // EPIPE or ENOTCONN return {0, Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; } + // Buffer is full. Cannot write anymore. if (!writable_peer_->isWritable()) { return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), IoSocketError::deleteIoError)}; @@ -240,11 +243,9 @@ Event::FileEventPtr BufferedIoSocketHandleImpl::createFileEvent(Event::Dispatche Event::FileReadyCb cb, Event::FileTriggerType trigger_type, uint32_t events) { - ASSERT(event_counter_ == 0); - ++event_counter_; io_callback_ = dispatcher.createSchedulableCallback([this]() { user_file_event_->onEvents(); }); auto res = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( - dispatcher, cb, trigger_type, events, *io_callback_, event_counter_); + dispatcher, cb, trigger_type, events, *io_callback_); user_file_event_ = res.get(); // Blindly activate the events. io_callback_->scheduleCallbackNextIteration(); diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index d6a970cea9f6..f8dfc343e071 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -444,6 +444,27 @@ TEST_F(BufferedIoSocketHandleTest, TestWritevToPeer) { EXPECT_EQ("012", internal_buffer.toString()); } +TEST_F(BufferedIoSocketHandleTest, TestWriteAfteShutdown) { + Buffer::OwnedImpl data_to_write("0123456789"); + Api::IoCallUint64Result result{0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; + result = io_handle_->write(data_to_write); + EXPECT_TRUE(result.ok()); + io_handle_->shutdown(ENVOY_SHUT_WR); + result = io_handle_->write(data_to_write); + EXPECT_FALSE(result.ok()); +} + +TEST_F(BufferedIoSocketHandleTest, TestWritevAfteShutdown) { + std::string raw_data("0123456789"); + Buffer::RawSlice slice{static_cast(raw_data.data()), raw_data.size()}; + Api::IoCallUint64Result result{0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; + result = io_handle_peer_->writev(&slice, 1); + EXPECT_TRUE(result.ok()); + io_handle_->shutdown(ENVOY_SHUT_WR); + result = io_handle_->writev(&slice, 1); + EXPECT_FALSE(result.ok()); +} + TEST_F(BufferedIoSocketHandleTest, TestWriteScheduleWritableEvent) { std::string accumulator; scheduable_cb_ = new NiceMock(&dispatcher_); From fb32d3037109fc9f7f58e2c4a0b1e02a8318ed0c Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Wed, 14 Oct 2020 23:59:53 +0000 Subject: [PATCH 058/100] format Signed-off-by: Yuchen Dai --- .../common/network/buffered_io_socket_handle_impl.cc | 12 +++++++----- .../network/buffered_io_socket_handle_impl_test.cc | 2 +- tools/spelling/spelling_dictionary.txt | 2 ++ 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc index dc34bfa369ab..64e8481da7eb 100644 --- a/source/common/network/buffered_io_socket_handle_impl.cc +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -115,7 +115,8 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::writev(const Buffer::RawSlic } if (writable_peer_->isWriteEndSet()) { // EPIPE or ENOTCONN - return {0, Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; + return {0, + Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; } if (!writable_peer_->isWritable()) { return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), @@ -144,10 +145,11 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::write(Buffer::Instance& buff return {0, Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; } - // Write to a shutdown peer. + // Write to a shutdown peer. if (writable_peer_->isWriteEndSet()) { // EPIPE or ENOTCONN - return {0, Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; + return {0, + Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; } // Buffer is full. Cannot write anymore. if (!writable_peer_->isWritable()) { @@ -214,8 +216,8 @@ IoHandlePtr BufferedIoSocketHandleImpl::accept(struct sockaddr*, socklen_t*) { } Api::SysCallIntResult BufferedIoSocketHandleImpl::connect(Address::InstanceConstSharedPtr) { - // Buffered Io handle should always be considered as connected. - // Use write or read to determine if peer is closed. + // Buffered Io handle should always be considered as connected. + // Use write or read to determine if peer is closed. return {0, 0}; } diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index f8dfc343e071..1463cd6000d8 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -1,8 +1,8 @@ #include "envoy/event/file_event.h" #include "common/buffer/buffer_impl.h" -#include "common/network/buffered_io_socket_handle_impl.h" #include "common/network/address_impl.h" +#include "common/network/buffered_io_socket_handle_impl.h" #include "test/mocks/event/mocks.h" diff --git a/tools/spelling/spelling_dictionary.txt b/tools/spelling/spelling_dictionary.txt index 1b99501fec10..c7207ecb5d4c 100644 --- a/tools/spelling/spelling_dictionary.txt +++ b/tools/spelling/spelling_dictionary.txt @@ -28,6 +28,8 @@ CDN CDS CEL DSR +ENOTCONN +EPIPE HEXDIG HEXDIGIT LTT From 9361c49289cde4bddb35b7f819e5119a70feecbc Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 15 Oct 2020 05:16:53 +0000 Subject: [PATCH 059/100] add missing Signed-off-by: Yuchen Dai --- .../common/network/buffered_io_socket_handle_impl.cc | 11 +++++------ .../common/network/buffered_io_socket_handle_impl.h | 3 ++- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc index 64e8481da7eb..a5726e01fba4 100644 --- a/source/common/network/buffered_io_socket_handle_impl.cc +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -246,16 +246,16 @@ Event::FileEventPtr BufferedIoSocketHandleImpl::createFileEvent(Event::Dispatche Event::FileTriggerType trigger_type, uint32_t events) { io_callback_ = dispatcher.createSchedulableCallback([this]() { user_file_event_->onEvents(); }); - auto res = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( + auto event = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( dispatcher, cb, trigger_type, events, *io_callback_); - user_file_event_ = res.get(); + user_file_event_ = event.get(); // Blindly activate the events. io_callback_->scheduleCallbackNextIteration(); - return res; + return event; } Api::SysCallIntResult BufferedIoSocketHandleImpl::shutdown(int how) { - // Support shutdown write. + // Support only shutdown write. ASSERT(how == ENVOY_SHUT_WR); ASSERT(!closed_); if (!write_shutdown_) { @@ -266,7 +266,6 @@ Api::SysCallIntResult BufferedIoSocketHandleImpl::shutdown(int how) { write_shutdown_ = true; } return {0, 0}; -} // namespace Network - +} } // namespace Network } // namespace Envoy \ No newline at end of file diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/common/network/buffered_io_socket_handle_impl.h index 97d2186b4c41..b12582488e47 100644 --- a/source/common/network/buffered_io_socket_handle_impl.h +++ b/source/common/network/buffered_io_socket_handle_impl.h @@ -113,7 +113,8 @@ class BufferedIoSocketHandleImpl : public IoHandle, // leak. bool closed_{false}; - // The attached file event with this socket. The event is not owned by the socket. + // The attached file event with this socket. The event is not owned by the socket in the current + // Envoy model. Event::UserSpaceFileEventImpl* user_file_event_; // The schedulable handle of the above event. From baf755a606d84bbb0250e5d0791ad2a39b37a51c Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 15 Oct 2020 16:36:18 +0000 Subject: [PATCH 060/100] ASSERT_DEBUG_DEATH Signed-off-by: Yuchen Dai --- test/common/network/buffered_io_socket_handle_impl_test.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index 1463cd6000d8..d1f514a1b775 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -414,8 +414,8 @@ TEST_F(BufferedIoSocketHandleTest, TestRepeatedShutdownWR) { } TEST_F(BufferedIoSocketHandleTest, TestShutDownOptionsNotSupported) { - ASSERT_DEATH(io_handle_peer_->shutdown(ENVOY_SHUT_RD), ""); - ASSERT_DEATH(io_handle_peer_->shutdown(ENVOY_SHUT_RDWR), ""); + ASSERT_DEBUG_DEATH(io_handle_peer_->shutdown(ENVOY_SHUT_RD), ""); + ASSERT_DEBUG_DEATH(io_handle_peer_->shutdown(ENVOY_SHUT_RDWR), ""); } TEST_F(BufferedIoSocketHandleTest, TestWriteByMove) { From a6686b499a2edefd1fb13ffa23e3f81652503e9f Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 15 Oct 2020 19:33:13 +0000 Subject: [PATCH 061/100] coverage Signed-off-by: Yuchen Dai --- .../network/buffered_io_socket_handle_impl.cc | 3 ++- source/common/network/io_socket_error_impl.h | 19 ------------------- 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc index a5726e01fba4..be1409f1bc29 100644 --- a/source/common/network/buffered_io_socket_handle_impl.cc +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -111,7 +111,8 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::writev(const Buffer::RawSlic Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; } if (!writable_peer_) { - return sysCallResultToIoCallResult(Api::SysCallSizeResult{-1, SOCKET_ERROR_INVAL}); + return {0, + Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; } if (writable_peer_->isWriteEndSet()) { // EPIPE or ENOTCONN diff --git a/source/common/network/io_socket_error_impl.h b/source/common/network/io_socket_error_impl.h index b98d51f1caf3..e101ee4ee499 100644 --- a/source/common/network/io_socket_error_impl.h +++ b/source/common/network/io_socket_error_impl.h @@ -33,24 +33,5 @@ class IoSocketError : public Api::IoError { private: int errno_; }; - -// Converts a SysCallSizeResult to IoCallUint64Result. -template -Api::IoCallUint64Result sysCallResultToIoCallResult(const Api::SysCallResult& result) { - if (result.rc_ >= 0) { - // Return nullptr as IoError upon success. - return Api::IoCallUint64Result(result.rc_, - Api::IoErrorPtr(nullptr, IoSocketError::deleteIoError)); - } - RELEASE_ASSERT(result.errno_ != SOCKET_ERROR_INVAL, "Invalid argument passed in."); - return Api::IoCallUint64Result( - /*rc=*/0, - (result.errno_ == SOCKET_ERROR_AGAIN - // EAGAIN is frequent enough that its memory allocation should be avoided. - ? Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), - IoSocketError::deleteIoError) - : Api::IoErrorPtr(new IoSocketError(result.errno_), IoSocketError::deleteIoError))); -} - } // namespace Network } // namespace Envoy From 2d93b61988ae84ae7397b45a92d0a21d7b19fafe Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 15 Oct 2020 21:15:19 +0000 Subject: [PATCH 062/100] coverage, cont Signed-off-by: Yuchen Dai --- .../buffered_io_socket_handle_impl_test.cc | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index d1f514a1b775..90079a6d4f41 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -1,3 +1,4 @@ +#include "envoy/common/platform.h" #include "envoy/event/file_event.h" #include "common/buffer/buffer_impl.h" @@ -426,6 +427,31 @@ TEST_F(BufferedIoSocketHandleTest, TestWriteByMove) { EXPECT_EQ(0, buf.length()); } +// Test write return error code without event +TEST_F(BufferedIoSocketHandleTest, TestWriteErrorCode) { + Buffer::OwnedImpl buf("0123456789"); + Api::IoCallUint64Result result{0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; + + { + // Populate write destiniation with massive data so as to not writable. + auto& internal_buffer = io_handle_peer_->getBufferForTest(); + internal_buffer.setWatermarks(1024); + internal_buffer.add(std::string(2048, ' ')); + + result = io_handle_->write(buf); + ASSERT_EQ(result.err_->getErrorCode(), Api::IoError::IoErrorCode::Again); + EXPECT_EQ(10, buf.length()); + } + + { + // Write after shutdown. + io_handle_->shutdown(ENVOY_SHUT_WR); + result = io_handle_->write(buf); + ASSERT_EQ(result.err_->getErrorCode(), Api::IoError::IoErrorCode::UnknownError); + EXPECT_EQ(10, buf.length()); + } +} + TEST_F(BufferedIoSocketHandleTest, TestWritevToPeer) { std::string raw_data("0123456789"); absl::InlinedVector slices{ @@ -622,6 +648,10 @@ TEST_F(BufferedIoSocketHandleTest, TestNotSupportsUdpGro) { EXPECT_FALSE(io_handle_->supportsUdpGro()); } +TEST_F(BufferedIoSocketHandleTest, TestDomainNullOpt) { + EXPECT_FALSE(io_handle_->domain().has_value()); +} + class BufferedIoSocketHandleNotImplementedTest : public testing::Test { public: BufferedIoSocketHandleNotImplementedTest() { @@ -644,20 +674,28 @@ class BufferedIoSocketHandleNotImplementedTest : public testing::Test { Buffer::RawSlice slice_; }; +TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnSetBlocking) { + EXPECT_THAT(io_handle_->setBlocking(false), IsNotSupportedResult()); + EXPECT_THAT(io_handle_->setBlocking(true), IsNotSupportedResult()); +} + TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnSendmsg) { EXPECT_THAT(io_handle_->sendmsg(&slice_, 0, 0, nullptr, Network::Address::EnvoyInternalInstance("listener_id")), IsInvalidateAddress()); } + TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnRecvmsg) { Network::IoHandle::RecvMsgOutput output_is_ignored(1, nullptr); EXPECT_THAT(io_handle_->recvmsg(&slice_, 0, 0, output_is_ignored), IsInvalidateAddress()); } + TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnRecvmmsg) { RawSliceArrays slices_is_ignored(1, absl::FixedArray({slice_})); Network::IoHandle::RecvMsgOutput output_is_ignored(1, nullptr); EXPECT_THAT(io_handle_->recvmmsg(slices_is_ignored, 0, output_is_ignored), IsInvalidateAddress()); } + TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnBind) { auto address_is_ignored = std::make_shared("listener_id"); @@ -668,6 +706,19 @@ TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnListen) { int back_log_is_ignored = 0; EXPECT_THAT(io_handle_->listen(back_log_is_ignored), IsNotSupportedResult()); } + +TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnAddress) { + ASSERT_THROW(io_handle_->peerAddress(), EnvoyException); + ASSERT_THROW(io_handle_->localAddress(), EnvoyException); +} + +TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnSetOption) { + EXPECT_THAT(io_handle_->setOption(0, 0, nullptr, 0), IsNotSupportedResult()); +} + +TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnGetOption) { + EXPECT_THAT(io_handle_->getOption(0, 0, nullptr, nullptr), IsNotSupportedResult()); +} } // namespace } // namespace Network } // namespace Envoy From 992c37723099c8db1d3d96c07e73eb7f72ae1eb8 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 15 Oct 2020 21:15:59 +0000 Subject: [PATCH 063/100] coverage, cont Signed-off-by: Yuchen Dai --- test/common/network/buffered_io_socket_handle_impl_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index 90079a6d4f41..8e73140b3d9f 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -433,7 +433,7 @@ TEST_F(BufferedIoSocketHandleTest, TestWriteErrorCode) { Api::IoCallUint64Result result{0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; { - // Populate write destiniation with massive data so as to not writable. + // Populate write destination with massive data so as to not writable. auto& internal_buffer = io_handle_peer_->getBufferForTest(); internal_buffer.setWatermarks(1024); internal_buffer.add(std::string(2048, ' ')); From d1a695dd0adad5f44cdcf54d10d7c7eafab096b1 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 15 Oct 2020 21:52:04 +0000 Subject: [PATCH 064/100] more Signed-off-by: Yuchen Dai --- .../buffered_io_socket_handle_impl_test.cc | 71 +++++++++++++------ 1 file changed, 49 insertions(+), 22 deletions(-) diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index 8e73140b3d9f..52f8b6bc9205 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -36,6 +36,7 @@ class BufferedIoSocketHandleTest : public testing::Test { io_handle_->setWritablePeer(io_handle_peer_.get()); io_handle_peer_->setWritablePeer(io_handle_.get()); } + ~BufferedIoSocketHandleTest() override { if (io_handle_->isOpen()) { io_handle_->close(); @@ -44,11 +45,13 @@ class BufferedIoSocketHandleTest : public testing::Test { io_handle_peer_->close(); } } + void expectAgain() { auto result = io_handle_->recv(buf_.data(), buf_.size(), MSG_PEEK); EXPECT_FALSE(result.ok()); EXPECT_EQ(Api::IoError::IoErrorCode::Again, result.err_->getErrorCode()); } + NiceMock dispatcher_{}; // Owned by BufferedIoSocketHandle. @@ -427,7 +430,7 @@ TEST_F(BufferedIoSocketHandleTest, TestWriteByMove) { EXPECT_EQ(0, buf.length()); } -// Test write return error code without event +// Test write return error code. Ignoring the side effect of event scheduling. TEST_F(BufferedIoSocketHandleTest, TestWriteErrorCode) { Buffer::OwnedImpl buf("0123456789"); Api::IoCallUint64Result result{0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; @@ -450,6 +453,44 @@ TEST_F(BufferedIoSocketHandleTest, TestWriteErrorCode) { ASSERT_EQ(result.err_->getErrorCode(), Api::IoError::IoErrorCode::UnknownError); EXPECT_EQ(10, buf.length()); } + + { + io_handle_peer_->close(); + EXPECT_TRUE(io_handle_->isOpen()); + result = io_handle_->write(buf); + ASSERT_EQ(result.err_->getErrorCode(), Api::IoError::IoErrorCode::UnknownError); + } +} + +// Test writev return error code. Ignoring the side effect of event scheduling. +TEST_F(BufferedIoSocketHandleTest, TestWritevErrorCode) { + std::string buf(10, 'a'); + Buffer::RawSlice slice{static_cast(buf.data()), 10}; + Api::IoCallUint64Result result{0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; + + { + // Populate write destination with massive data so as to not writable. + auto& internal_buffer = io_handle_peer_->getBufferForTest(); + internal_buffer.setWatermarks(1024); + internal_buffer.add(std::string(2048, ' ')); + result = io_handle_->writev(&slice, 1); + ASSERT_EQ(result.err_->getErrorCode(), Api::IoError::IoErrorCode::Again); + } + + { + // Writev after shutdown. + io_handle_->shutdown(ENVOY_SHUT_WR); + result = io_handle_->writev(&slice, 1); + ASSERT_EQ(result.err_->getErrorCode(), Api::IoError::IoErrorCode::UnknownError); + } + + { + // Close the peer. + io_handle_peer_->close(); + EXPECT_TRUE(io_handle_->isOpen()); + result = io_handle_->writev(&slice, 1); + ASSERT_EQ(result.err_->getErrorCode(), Api::IoError::IoErrorCode::UnknownError); + } } TEST_F(BufferedIoSocketHandleTest, TestWritevToPeer) { @@ -470,27 +511,6 @@ TEST_F(BufferedIoSocketHandleTest, TestWritevToPeer) { EXPECT_EQ("012", internal_buffer.toString()); } -TEST_F(BufferedIoSocketHandleTest, TestWriteAfteShutdown) { - Buffer::OwnedImpl data_to_write("0123456789"); - Api::IoCallUint64Result result{0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; - result = io_handle_->write(data_to_write); - EXPECT_TRUE(result.ok()); - io_handle_->shutdown(ENVOY_SHUT_WR); - result = io_handle_->write(data_to_write); - EXPECT_FALSE(result.ok()); -} - -TEST_F(BufferedIoSocketHandleTest, TestWritevAfteShutdown) { - std::string raw_data("0123456789"); - Buffer::RawSlice slice{static_cast(raw_data.data()), raw_data.size()}; - Api::IoCallUint64Result result{0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; - result = io_handle_peer_->writev(&slice, 1); - EXPECT_TRUE(result.ok()); - io_handle_->shutdown(ENVOY_SHUT_WR); - result = io_handle_->writev(&slice, 1); - EXPECT_FALSE(result.ok()); -} - TEST_F(BufferedIoSocketHandleTest, TestWriteScheduleWritableEvent) { std::string accumulator; scheduable_cb_ = new NiceMock(&dispatcher_); @@ -652,6 +672,12 @@ TEST_F(BufferedIoSocketHandleTest, TestDomainNullOpt) { EXPECT_FALSE(io_handle_->domain().has_value()); } +TEST_F(BufferedIoSocketHandleTest, TestConnect) { + auto address_is_ignored = + std::make_shared("listener_id"); + EXPECT_EQ(0, io_handle_->connect(address_is_ignored).rc_); +} + class BufferedIoSocketHandleNotImplementedTest : public testing::Test { public: BufferedIoSocketHandleNotImplementedTest() { @@ -660,6 +686,7 @@ class BufferedIoSocketHandleNotImplementedTest : public testing::Test { io_handle_->setWritablePeer(io_handle_peer_.get()); io_handle_peer_->setWritablePeer(io_handle_.get()); } + ~BufferedIoSocketHandleNotImplementedTest() override { if (io_handle_->isOpen()) { io_handle_->close(); From 683ad7f5ee6ad75681d02585deb2d66e26f06bcd Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Wed, 21 Oct 2020 18:30:35 +0000 Subject: [PATCH 065/100] split userspacefileeventimpl Signed-off-by: Yuchen Dai --- source/common/event/BUILD | 2 + source/common/event/file_event_impl.h | 137 +----------------- .../network/buffered_io_socket_handle_impl.cc | 2 +- .../network/buffered_io_socket_handle_impl.h | 2 +- 4 files changed, 5 insertions(+), 138 deletions(-) diff --git a/source/common/event/BUILD b/source/common/event/BUILD index e84aeb0cde04..56b55676b5a2 100644 --- a/source/common/event/BUILD +++ b/source/common/event/BUILD @@ -13,6 +13,7 @@ envoy_cc_library( srcs = [ "dispatcher_impl.cc", "file_event_impl.cc", + "user_space_file_event_impl.cc", "signal_impl.cc", ], hdrs = [ @@ -68,6 +69,7 @@ envoy_cc_library( "dispatcher_impl.h", "event_impl_base.h", "file_event_impl.h", + "user_space_file_event_impl.h", "schedulable_cb_impl.h", ], deps = [ diff --git a/source/common/event/file_event_impl.h b/source/common/event/file_event_impl.h index 395bbbda52d7..cb5521483183 100644 --- a/source/common/event/file_event_impl.h +++ b/source/common/event/file_event_impl.h @@ -8,10 +8,6 @@ #include "common/event/event_impl_base.h" namespace Envoy { - -namespace Network { -class BufferedIoSocketHandleImpl; -} namespace Event { /** @@ -45,136 +41,5 @@ class FileEventImpl : public FileEvent, ImplBase { // polling and activating new fd events. const bool activate_fd_events_next_event_loop_; }; - -// Forward declare for friend class. -class UserSpaceFileEventFactory; - -// The interface of populating event watcher and obtaining the active events. The events are the -// combination of FileReadyType values. The event listener is populated by user event registration -// and io events passively. Also the owner of this listener query the activated events by calling -// triggeredEvents and getAndClearEphemeralEvents. -class EventListener { -public: - virtual ~EventListener() = default; - - // Get the events which are enabled and triggered. - virtual uint32_t triggeredEvents() PURE; - // Get the events which are ephemerally activated. Upon returning the ephemeral events are - // cleared. - virtual uint32_t getAndClearEphemeralEvents() PURE; - - /** - * FileEvent::setEnabled is invoked. - * @param enabled_events supplied the event of setEnabled. - */ - virtual void onEventEnabled(uint32_t enabled_events) PURE; - - /** - * FileEvent::activate is invoked. - * @param enabled_events supplied the event of activate(). - */ - virtual void onEventActivated(uint32_t activated_events) PURE; -}; - -// Return the enabled events except EV_CLOSED. This implementation is generally good since only -// epoll supports EV_CLOSED but the entire envoy code base supports another poller. The event owner -// must assume EV_CLOSED is never activated. Also event owner must tolerate that OS could notify -// events which are not actually triggered. -// TODO(lambdai): Add support of delivering EV_CLOSED. -class DefaultEventListener : public EventListener { -public: - ~DefaultEventListener() override = default; - - // Return both read and write. - uint32_t triggeredEvents() override { return pending_events_ & (~Event::FileReadyType::Closed); } - - void onEventEnabled(uint32_t enabled_events) override { pending_events_ = enabled_events; } - - void onEventActivated(uint32_t activated_events) override { - ephermal_events_ |= activated_events; - } - - uint32_t getAndClearEphemeralEvents() override { return std::exchange(ephermal_events_, 0); } - -private: - // The persisted interested events and ready events. - uint32_t pending_events_{}; - // The events set by activate() and will be cleared after the io callback. - uint32_t ephermal_events_{}; -}; - -// A FileEvent implementation which is used to drive BufferedIoSocketHandle. -class UserSpaceFileEventImpl : public FileEvent, Logger::Loggable { -public: - ~UserSpaceFileEventImpl() override { - if (schedulable_.enabled()) { - schedulable_.cancel(); - } - } - - // Event::FileEvent - void activate(uint32_t events) override { - // Only supported event types are set. - ASSERT((events & (FileReadyType::Read | FileReadyType::Write | FileReadyType::Closed)) == - events); - event_listener_.onEventActivated(events); - if (!schedulable_.enabled()) { - schedulable_.scheduleCallbackNextIteration(); - } - } - - void setEnabled(uint32_t events) override { - // Only supported event types are set. - ASSERT((events & (FileReadyType::Read | FileReadyType::Write | FileReadyType::Closed)) == - events); - event_listener_.onEventEnabled(events); - bool was_enabled = schedulable_.enabled(); - if (!was_enabled) { - schedulable_.scheduleCallbackNextIteration(); - } - ENVOY_LOG(trace, "User space file event {} set events {}. Will {} reschedule.", - static_cast(this), events, was_enabled ? "not " : ""); - } - - EventListener& getEventListener() { return event_listener_; } - void onEvents() { cb_(); } - friend class UserSpaceFileEventFactory; - friend class Network::BufferedIoSocketHandleImpl; - -private: - UserSpaceFileEventImpl(Event::FileReadyCb cb, uint32_t events, - SchedulableCallback& schedulable_cb) - : schedulable_(schedulable_cb), cb_([this, cb]() { - auto all_events = getEventListener().triggeredEvents(); - auto ephemeral_events = getEventListener().getAndClearEphemeralEvents(); - ENVOY_LOG(trace, - "User space event {} invokes callbacks on allevents = {}, ephermal events = {}", - static_cast(this), all_events, ephemeral_events); - cb(all_events | ephemeral_events); - }) { - event_listener_.onEventEnabled(events); - } - - // Used to populate the event operations of enable and activate. - DefaultEventListener event_listener_; - - // The handle to registered async callback from dispatcher. - SchedulableCallback& schedulable_; - - // The registered callback of this event. This callback is usually on top of the frame of - // Dispatcher::run(). - std::function cb_; -}; - -class UserSpaceFileEventFactory { -public: - static std::unique_ptr - createUserSpaceFileEventImpl(Event::Dispatcher&, Event::FileReadyCb cb, Event::FileTriggerType, - uint32_t events, SchedulableCallback& scheduable_cb) { - return std::unique_ptr( - new UserSpaceFileEventImpl(cb, events, scheduable_cb)); - } -}; - } // namespace Event -} // namespace Envoy +} // namespace Envoy \ No newline at end of file diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc index be1409f1bc29..069f0ce86118 100644 --- a/source/common/network/buffered_io_socket_handle_impl.cc +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -6,7 +6,7 @@ #include "common/api/os_sys_calls_impl.h" #include "common/common/assert.h" #include "common/common/utility.h" -#include "common/event/file_event_impl.h" +#include "common/event/user_space_file_event_impl.h" #include "common/network/address_impl.h" #include "absl/container/fixed_array.h" diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/common/network/buffered_io_socket_handle_impl.h index b12582488e47..5df9d3129f4c 100644 --- a/source/common/network/buffered_io_socket_handle_impl.h +++ b/source/common/network/buffered_io_socket_handle_impl.h @@ -10,7 +10,7 @@ #include "common/buffer/watermark_buffer.h" #include "common/common/logger.h" -#include "common/event/file_event_impl.h" +#include "common/event/user_space_file_event_impl.h" #include "common/network/io_socket_error_impl.h" #include "common/network/peer_buffer.h" From 673bca0c9fd2a009424ef1e1e51cd1d478ba4f4a Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Wed, 21 Oct 2020 21:02:10 +0000 Subject: [PATCH 066/100] add missing files forgot to add to git Signed-off-by: Yuchen Dai --- .../event/user_space_file_event_impl.cc | 52 ++++++++ .../common/event/user_space_file_event_impl.h | 116 ++++++++++++++++++ .../network/buffered_io_socket_handle_impl.h | 3 +- 3 files changed, 170 insertions(+), 1 deletion(-) create mode 100644 source/common/event/user_space_file_event_impl.cc create mode 100644 source/common/event/user_space_file_event_impl.h diff --git a/source/common/event/user_space_file_event_impl.cc b/source/common/event/user_space_file_event_impl.cc new file mode 100644 index 000000000000..b246d4870b43 --- /dev/null +++ b/source/common/event/user_space_file_event_impl.cc @@ -0,0 +1,52 @@ +#include "common/event/user_space_file_event_impl.h" + +#include + +#include "common/common/assert.h" +namespace Envoy { +namespace Event { + +void UserSpaceFileEventImpl::activate(uint32_t events) { + // Only supported event types are set. + ASSERT((events & (FileReadyType::Read | FileReadyType::Write | FileReadyType::Closed)) == events); + event_listener_.onEventActivated(events); + if (!schedulable_.enabled()) { + schedulable_.scheduleCallbackNextIteration(); + } +} + +void UserSpaceFileEventImpl::setEnabled(uint32_t events) { + // Only supported event types are set. + ASSERT((events & (FileReadyType::Read | FileReadyType::Write | FileReadyType::Closed)) == events); + event_listener_.onEventEnabled(events); + bool was_enabled = schedulable_.enabled(); + if (!was_enabled) { + schedulable_.scheduleCallbackNextIteration(); + } + ENVOY_LOG(trace, "User space file event {} set events {}. Will {} reschedule.", + static_cast(this), events, was_enabled ? "not " : ""); +} + +UserSpaceFileEventImpl::UserSpaceFileEventImpl(Event::FileReadyCb cb, uint32_t events, + SchedulableCallback& schedulable_cb) + : schedulable_(schedulable_cb), cb_([this, cb]() { + auto all_events = getEventListener().triggeredEvents(); + auto ephemeral_events = getEventListener().getAndClearEphemeralEvents(); + ENVOY_LOG(trace, + "User space event {} invokes callbacks on allevents = {}, ephermal events = {}", + static_cast(this), all_events, ephemeral_events); + cb(all_events | ephemeral_events); + }) { + event_listener_.onEventEnabled(events); +} + +std::unique_ptr +UserSpaceFileEventFactory::createUserSpaceFileEventImpl(Event::Dispatcher&, Event::FileReadyCb cb, + Event::FileTriggerType, uint32_t events, + SchedulableCallback& scheduable_cb) { + return std::unique_ptr( + new UserSpaceFileEventImpl(cb, events, scheduable_cb)); +} + +} // namespace Event +} // namespace Envoy \ No newline at end of file diff --git a/source/common/event/user_space_file_event_impl.h b/source/common/event/user_space_file_event_impl.h new file mode 100644 index 000000000000..7fd3a2b1f675 --- /dev/null +++ b/source/common/event/user_space_file_event_impl.h @@ -0,0 +1,116 @@ +#pragma once + +#include + +#include "envoy/event/file_event.h" + +#include "common/event/dispatcher_impl.h" +#include "common/event/event_impl_base.h" + +namespace Envoy { + +namespace Network { +class BufferedIoSocketHandleImpl; +} +namespace Event { + +// Forward declare for friend class. +class UserSpaceFileEventFactory; + +// The interface of populating event watcher and obtaining the active events. The events are the +// combination of FileReadyType values. The event listener is populated by user event registration +// and io events passively. Also the owner of this listener query the activated events by calling +// triggeredEvents and getAndClearEphemeralEvents. +class EventListener { +public: + virtual ~EventListener() = default; + + // Get the events which are enabled and triggered. + virtual uint32_t triggeredEvents() PURE; + // Get the events which are ephemerally activated. Upon returning the ephemeral events are + // cleared. + virtual uint32_t getAndClearEphemeralEvents() PURE; + + /** + * FileEvent::setEnabled is invoked. + * @param enabled_events supplied the event of setEnabled. + */ + virtual void onEventEnabled(uint32_t enabled_events) PURE; + + /** + * FileEvent::activate is invoked. + * @param enabled_events supplied the event of activate(). + */ + virtual void onEventActivated(uint32_t activated_events) PURE; +}; + +// Return the enabled events except EV_CLOSED. This implementation is generally good since only +// epoll supports EV_CLOSED but the entire envoy code base supports another poller. The event owner +// must assume EV_CLOSED is never activated. Also event owner must tolerate that OS could notify +// events which are not actually triggered. +// TODO(lambdai): Add support of delivering EV_CLOSED. +class DefaultEventListener : public EventListener { +public: + ~DefaultEventListener() override = default; + + // Return both read and write if enabled. Note that this implmenetation is inefficient. Read and + // write events are supposed to be independent. + uint32_t triggeredEvents() override { return enabled_events_ & (~Event::FileReadyType::Closed); } + + void onEventEnabled(uint32_t enabled_events) override { enabled_events_ = enabled_events; } + + void onEventActivated(uint32_t activated_events) override { + ephermal_events_ |= activated_events; + } + + uint32_t getAndClearEphemeralEvents() override { return std::exchange(ephermal_events_, 0); } + +private: + // The persisted interested events. The name on libevent document is pending event. + uint32_t enabled_events_{}; + // The events set by activate() and will be cleared after the io callback. + uint32_t ephermal_events_{}; +}; + +// A FileEvent implementation which is used to drive BufferedIoSocketHandle. +class UserSpaceFileEventImpl : public FileEvent, Logger::Loggable { +public: + ~UserSpaceFileEventImpl() override { + if (schedulable_.enabled()) { + schedulable_.cancel(); + } + } + + // Event::FileEvent + void activate(uint32_t events) override; + void setEnabled(uint32_t events) override; + + EventListener& getEventListener() { return event_listener_; } + void onEvents() { cb_(); } + friend class UserSpaceFileEventFactory; + friend class Network::BufferedIoSocketHandleImpl; + +private: + UserSpaceFileEventImpl(Event::FileReadyCb cb, uint32_t events, + SchedulableCallback& schedulable_cb); + + // Used to populate the event operations of enable and activate. + DefaultEventListener event_listener_; + + // The handle to registered async callback from dispatcher. + SchedulableCallback& schedulable_; + + // The registered callback of this event. This callback is usually on top of the frame of + // Dispatcher::run(). + std::function cb_; +}; + +class UserSpaceFileEventFactory { +public: + static std::unique_ptr + createUserSpaceFileEventImpl(Event::Dispatcher&, Event::FileReadyCb cb, Event::FileTriggerType, + uint32_t events, SchedulableCallback& scheduable_cb); +}; + +} // namespace Event +} // namespace Envoy diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/common/network/buffered_io_socket_handle_impl.h index 5df9d3129f4c..dc56967aec73 100644 --- a/source/common/network/buffered_io_socket_handle_impl.h +++ b/source/common/network/buffered_io_socket_handle_impl.h @@ -114,7 +114,8 @@ class BufferedIoSocketHandleImpl : public IoHandle, bool closed_{false}; // The attached file event with this socket. The event is not owned by the socket in the current - // Envoy model. + // Envoy model. Multiple events can be created during the life time of this IO handle but at any + // moment at most 1 event is attached. Event::UserSpaceFileEventImpl* user_file_event_; // The schedulable handle of the above event. From e59fa57acf731e77ff5d6c980090bd4d9f4ab3ed Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 22 Oct 2020 00:25:40 +0000 Subject: [PATCH 067/100] add scaffold of user space event test Signed-off-by: Yuchen Dai --- .../event/user_space_file_event_impl.cc | 14 +++++++++ .../common/event/user_space_file_event_impl.h | 9 ++---- .../network/buffered_io_socket_handle_impl.cc | 27 ++++++++++------ test/common/event/BUILD | 16 ++++++++++ .../event/user_space_file_event_impl_test.cc | 31 +++++++++++++++++++ 5 files changed, 81 insertions(+), 16 deletions(-) create mode 100644 test/common/event/user_space_file_event_impl_test.cc diff --git a/source/common/event/user_space_file_event_impl.cc b/source/common/event/user_space_file_event_impl.cc index b246d4870b43..3c2fcfb97f6e 100644 --- a/source/common/event/user_space_file_event_impl.cc +++ b/source/common/event/user_space_file_event_impl.cc @@ -6,6 +6,20 @@ namespace Envoy { namespace Event { +void DefaultEventListener::onEventEnabled(uint32_t enabled_events) { + enabled_events_ = enabled_events; + // Clear ephermal events to align with FileEventImpl::setEnable(). + ephermal_events_ = 0; +} + +void DefaultEventListener::onEventActivated(uint32_t activated_events) { + // Event owner should not activate any event which is disabled. + // Also see onEventEnabled which clears ephermal events. + // The overall prevents callback on disabled events. + ASSERT((ephermal_events_ & ~enabled_events_) == 0); + ephermal_events_ |= activated_events; +} + void UserSpaceFileEventImpl::activate(uint32_t events) { // Only supported event types are set. ASSERT((events & (FileReadyType::Read | FileReadyType::Write | FileReadyType::Closed)) == events); diff --git a/source/common/event/user_space_file_event_impl.h b/source/common/event/user_space_file_event_impl.h index 7fd3a2b1f675..89ce5d73f595 100644 --- a/source/common/event/user_space_file_event_impl.h +++ b/source/common/event/user_space_file_event_impl.h @@ -54,14 +54,11 @@ class DefaultEventListener : public EventListener { ~DefaultEventListener() override = default; // Return both read and write if enabled. Note that this implmenetation is inefficient. Read and - // write events are supposed to be independent. + // write events are supposed to be independent. uint32_t triggeredEvents() override { return enabled_events_ & (~Event::FileReadyType::Closed); } - void onEventEnabled(uint32_t enabled_events) override { enabled_events_ = enabled_events; } - - void onEventActivated(uint32_t activated_events) override { - ephermal_events_ |= activated_events; - } + void onEventEnabled(uint32_t enabled_events) override; + void onEventActivated(uint32_t activated_events) override; uint32_t getAndClearEphemeralEvents() override { return std::exchange(ephermal_events_, 0); } diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc index 069f0ce86118..3051c2b0a99a 100644 --- a/source/common/network/buffered_io_socket_handle_impl.cc +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -20,6 +20,7 @@ Api::SysCallIntResult makeInvalidSyscall() { return Api::SysCallIntResult{-1, SOCKET_ERROR_NOT_SUP}; } } // namespace + BufferedIoSocketHandleImpl::BufferedIoSocketHandleImpl() : owned_buffer_( [this]() -> void { @@ -59,6 +60,7 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::readv(uint64_t max_length, uint64_t num_slice) { if (!isOpen()) { return {0, + // TODO(lambdai): Add EBADF in IoSocketError and adopt it here. Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; } if (owned_buffer_.length() == 0) { @@ -70,13 +72,15 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::readv(uint64_t max_length, } } absl::FixedArray iov(num_slice); - uint64_t num_slices_to_read = 0; uint64_t bytes_to_read = 0; - for (; num_slices_to_read < num_slice && bytes_to_read < max_length; num_slices_to_read++) { - auto max_bytes_to_read = std::min(std::min(owned_buffer_.length(), max_length) - bytes_to_read, - uint64_t(slices[num_slices_to_read].len_)); - owned_buffer_.copyOut(bytes_to_read, max_bytes_to_read, slices[num_slices_to_read].mem_); - bytes_to_read += max_bytes_to_read; + for (uint64_t num_slices_to_read = 0; + num_slices_to_read < num_slice && bytes_to_read < max_length; num_slices_to_read++) { + auto bytes_to_write_in_this_slice = + std::min(std::min(owned_buffer_.length(), max_length) - bytes_to_read, + uint64_t(slices[num_slices_to_read].len_)); + owned_buffer_.copyOut(bytes_to_read, bytes_to_write_in_this_slice, + slices[num_slices_to_read].mem_); + bytes_to_read += bytes_to_write_in_this_slice; } ASSERT(bytes_to_read <= max_length); owned_buffer_.drain(bytes_to_read); @@ -110,15 +114,18 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::writev(const Buffer::RawSlic return {0, Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; } + // Closed peer. if (!writable_peer_) { return {0, Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; } + // Error: write after close. if (writable_peer_->isWriteEndSet()) { - // EPIPE or ENOTCONN + // TODO(lambdai): EPIPE or ENOTCONN return {0, Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; } + // The peer is valid but temporary not accepts new data. Likely due to flow control. if (!writable_peer_->isWritable()) { return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), IoSocketError::deleteIoError)}; @@ -146,13 +153,13 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::write(Buffer::Instance& buff return {0, Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; } - // Write to a shutdown peer. + // Error: write after close. if (writable_peer_->isWriteEndSet()) { - // EPIPE or ENOTCONN + // TODO(lambdai): EPIPE or ENOTCONN return {0, Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; } - // Buffer is full. Cannot write anymore. + // The peer is valid but temporary not accepts new data. Likely due to flow control. if (!writable_peer_->isWritable()) { return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), IoSocketError::deleteIoError)}; diff --git a/test/common/event/BUILD b/test/common/event/BUILD index 036d0f424359..f53d41216e19 100644 --- a/test/common/event/BUILD +++ b/test/common/event/BUILD @@ -42,6 +42,22 @@ envoy_cc_test( ], ) +envoy_cc_test( + name = "user_space_file_event_impl_test", + srcs = ["user_space_file_event_impl_test.cc"], + #tags = ["fails_on_windows"], + deps = [ + "//include/envoy/event:file_event_interface", + "//source/common/event:dispatcher_includes", + "//source/common/event:dispatcher_lib", + "//source/common/stats:isolated_store_lib", + "//test/mocks:common_lib", + "//test/test_common:environment_lib", + "//test/test_common:test_runtime_lib", + "//test/test_common:utility_lib", + ], +) + envoy_cc_test( name = "scaled_range_timer_manager_test", srcs = ["scaled_range_timer_manager_test.cc"], diff --git a/test/common/event/user_space_file_event_impl_test.cc b/test/common/event/user_space_file_event_impl_test.cc new file mode 100644 index 000000000000..5b2471e0b1fa --- /dev/null +++ b/test/common/event/user_space_file_event_impl_test.cc @@ -0,0 +1,31 @@ +#include + +#include "envoy/event/file_event.h" + +#include "common/api/os_sys_calls_impl.h" +#include "common/event/dispatcher_impl.h" +#include "common/stats/isolated_store_impl.h" + +#include "test/mocks/common.h" +#include "test/test_common/environment.h" +#include "test/test_common/test_runtime.h" +#include "test/test_common/utility.h" + +#include "gtest/gtest.h" + +namespace Envoy { +namespace Event { +namespace { + +class UserSpaceFileEventImplTest : public testing::Test { +public: + UserSpaceFileEventImplTest() + : api_(Api::createApiForTest()), dispatcher_(api_->allocateDispatcher("test_thread")) {} + +protected: + Api::ApiPtr api_; + DispatcherPtr dispatcher_; +}; +} // namespace +} // namespace Event +} // namespace Envoy \ No newline at end of file From b65e5409deced727654383c21675a7073ba4b952 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 22 Oct 2020 02:00:34 +0000 Subject: [PATCH 068/100] various fix: file event test not ready yet Signed-off-by: Yuchen Dai --- source/common/event/BUILD | 4 +- .../event/user_space_file_event_impl.cc | 13 ++-- .../common/event/user_space_file_event_impl.h | 2 +- .../network/buffered_io_socket_handle_impl.cc | 73 ++++++++++--------- .../network/buffered_io_socket_handle_impl.h | 13 ++-- tools/spelling/spelling_dictionary.txt | 1 + 6 files changed, 57 insertions(+), 49 deletions(-) diff --git a/source/common/event/BUILD b/source/common/event/BUILD index 56b55676b5a2..5ada7848b0a3 100644 --- a/source/common/event/BUILD +++ b/source/common/event/BUILD @@ -13,8 +13,8 @@ envoy_cc_library( srcs = [ "dispatcher_impl.cc", "file_event_impl.cc", - "user_space_file_event_impl.cc", "signal_impl.cc", + "user_space_file_event_impl.cc", ], hdrs = [ "signal_impl.h", @@ -69,8 +69,8 @@ envoy_cc_library( "dispatcher_impl.h", "event_impl_base.h", "file_event_impl.h", - "user_space_file_event_impl.h", "schedulable_cb_impl.h", + "user_space_file_event_impl.h", ], deps = [ ":libevent_lib", diff --git a/source/common/event/user_space_file_event_impl.cc b/source/common/event/user_space_file_event_impl.cc index 3c2fcfb97f6e..5e7164c5d3f7 100644 --- a/source/common/event/user_space_file_event_impl.cc +++ b/source/common/event/user_space_file_event_impl.cc @@ -3,18 +3,19 @@ #include #include "common/common/assert.h" + namespace Envoy { namespace Event { void DefaultEventListener::onEventEnabled(uint32_t enabled_events) { enabled_events_ = enabled_events; - // Clear ephermal events to align with FileEventImpl::setEnable(). + // Clear ephemeral events to align with FileEventImpl::setEnable(). ephermal_events_ = 0; } void DefaultEventListener::onEventActivated(uint32_t activated_events) { // Event owner should not activate any event which is disabled. - // Also see onEventEnabled which clears ephermal events. + // Also see onEventEnabled which clears ephemeral events. // The overall prevents callback on disabled events. ASSERT((ephermal_events_ & ~enabled_events_) == 0); ephermal_events_ |= activated_events; @@ -54,10 +55,10 @@ UserSpaceFileEventImpl::UserSpaceFileEventImpl(Event::FileReadyCb cb, uint32_t e event_listener_.onEventEnabled(events); } -std::unique_ptr -UserSpaceFileEventFactory::createUserSpaceFileEventImpl(Event::Dispatcher&, Event::FileReadyCb cb, - Event::FileTriggerType, uint32_t events, - SchedulableCallback& scheduable_cb) { +std::unique_ptr UserSpaceFileEventFactory::createUserSpaceFileEventImpl( + Event::Dispatcher&, Event::FileReadyCb cb, Event::FileTriggerType trigger_type, uint32_t events, + SchedulableCallback& scheduable_cb) { + ASSERT(trigger_type == Event::FileTriggerType::Edge); return std::unique_ptr( new UserSpaceFileEventImpl(cb, events, scheduable_cb)); } diff --git a/source/common/event/user_space_file_event_impl.h b/source/common/event/user_space_file_event_impl.h index 89ce5d73f595..7579b2a1fff0 100644 --- a/source/common/event/user_space_file_event_impl.h +++ b/source/common/event/user_space_file_event_impl.h @@ -53,7 +53,7 @@ class DefaultEventListener : public EventListener { public: ~DefaultEventListener() override = default; - // Return both read and write if enabled. Note that this implmenetation is inefficient. Read and + // Return both read and write if enabled. Note that this implementation is inefficient. Read and // write events are supposed to be independent. uint32_t triggeredEvents() override { return enabled_events_ & (~Event::FileReadyType::Closed); } diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc index 3051c2b0a99a..b2a68deb59c0 100644 --- a/source/common/network/buffered_io_socket_handle_impl.cc +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -22,7 +22,7 @@ Api::SysCallIntResult makeInvalidSyscall() { } // namespace BufferedIoSocketHandleImpl::BufferedIoSocketHandleImpl() - : owned_buffer_( + : pending_received_data_( [this]() -> void { over_high_watermark_ = false; if (writable_peer_) { @@ -39,15 +39,19 @@ BufferedIoSocketHandleImpl::BufferedIoSocketHandleImpl() Api::IoCallUint64Result BufferedIoSocketHandleImpl::close() { ASSERT(!closed_); - if (!write_shutdown_) { - ASSERT(writable_peer_); - // Notify the peer we won't write more data. shutdown(WRITE). - writable_peer_->setWriteEnd(); - // Notify the peer that we no longer accept data. shutdown(RD). - writable_peer_->onPeerDestroy(); - writable_peer_->maybeSetNewData(); - writable_peer_ = nullptr; - write_shutdown_ = true; + if (!closed_) { + if (writable_peer_) { + ENVOY_LOG(trace, "socket {} close before peer {} closes.", static_cast(this), + static_cast(writable_peer_)); + // Notify the peer we won't write more data. shutdown(WRITE). + writable_peer_->setWriteEnd(); + // Notify the peer that we no longer accept data. shutdown(RD). + writable_peer_->onPeerDestroy(); + writable_peer_->maybeSetNewData(); + writable_peer_ = nullptr; + } else { + ENVOY_LOG(trace, "socket {} close after peer closed.", static_cast(this)); + } } closed_ = true; return Api::ioCallUint64ResultNoError(); @@ -63,7 +67,7 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::readv(uint64_t max_length, // TODO(lambdai): Add EBADF in IoSocketError and adopt it here. Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; } - if (owned_buffer_.length() == 0) { + if (pending_received_data_.length() == 0) { if (read_end_stream_) { return {0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } else { @@ -72,20 +76,19 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::readv(uint64_t max_length, } } absl::FixedArray iov(num_slice); - uint64_t bytes_to_read = 0; - for (uint64_t num_slices_to_read = 0; - num_slices_to_read < num_slice && bytes_to_read < max_length; num_slices_to_read++) { - auto bytes_to_write_in_this_slice = - std::min(std::min(owned_buffer_.length(), max_length) - bytes_to_read, - uint64_t(slices[num_slices_to_read].len_)); - owned_buffer_.copyOut(bytes_to_read, bytes_to_write_in_this_slice, - slices[num_slices_to_read].mem_); - bytes_to_read += bytes_to_write_in_this_slice; + uint64_t bytes_offset = 0; + for (uint64_t i = 0; i < num_slice && bytes_offset < max_length; i++) { + auto bytes_to_read_in_this_slice = + std::min(std::min(pending_received_data_.length(), max_length) - bytes_offset, + uint64_t(slices[i].len_)); + pending_received_data_.copyOut(bytes_offset, bytes_to_read_in_this_slice, slices[i].mem_); + bytes_offset += bytes_to_read_in_this_slice; } - ASSERT(bytes_to_read <= max_length); - owned_buffer_.drain(bytes_to_read); - ENVOY_LOG(trace, "socket {} readv {} bytes", static_cast(this), bytes_to_read); - return {bytes_to_read, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; + auto bytes_read = bytes_offset; + ASSERT(bytes_read <= max_length); + pending_received_data_.drain(bytes_read); + ENVOY_LOG(trace, "socket {} readv {} bytes", static_cast(this), bytes_read); + return {bytes_read, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } Api::IoCallUint64Result BufferedIoSocketHandleImpl::read(Buffer::Instance& buffer, @@ -94,7 +97,7 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::read(Buffer::Instance& buffe return {0, Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; } - if (owned_buffer_.length() == 0) { + if (pending_received_data_.length() == 0) { if (read_end_stream_) { return {0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } else { @@ -103,8 +106,8 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::read(Buffer::Instance& buffe } } // TODO(lambdai): Move at slice boundary to move to reduce the copy. - uint64_t max_bytes_to_read = std::min(max_length, owned_buffer_.length()); - buffer.move(owned_buffer_, max_bytes_to_read); + uint64_t max_bytes_to_read = std::min(max_length, pending_received_data_.length()); + buffer.move(pending_received_data_, max_bytes_to_read); return {max_bytes_to_read, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } @@ -131,16 +134,16 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::writev(const Buffer::RawSlic IoSocketError::deleteIoError)}; } // Write along with iteration. Buffer guarantee the fragment is always append-able. - uint64_t total_bytes_to_write = 0; + uint64_t bytes_written = 0; for (uint64_t i = 0; i < num_slice; i++) { if (slices[i].mem_ != nullptr && slices[i].len_ != 0) { writable_peer_->getWriteBuffer()->add(slices[i].mem_, slices[i].len_); - total_bytes_to_write += slices[i].len_; + bytes_written += slices[i].len_; } } writable_peer_->maybeSetNewData(); - ENVOY_LOG(trace, "socket {} writev {} bytes", static_cast(this), total_bytes_to_write); - return {total_bytes_to_write, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; + ENVOY_LOG(trace, "socket {} writev {} bytes", static_cast(this), bytes_written); + return {bytes_written, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } Api::IoCallUint64Result BufferedIoSocketHandleImpl::write(Buffer::Instance& buffer) { @@ -193,7 +196,7 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::recv(void* buffer, size_t le Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; } // No data and the writer closed. - if (owned_buffer_.length() == 0) { + if (pending_received_data_.length() == 0) { if (read_end_stream_) { return {0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } else { @@ -201,10 +204,10 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::recv(void* buffer, size_t le IoSocketError::deleteIoError)}; } } - auto max_bytes_to_read = std::min(owned_buffer_.length(), length); - owned_buffer_.copyOut(0, max_bytes_to_read, buffer); + auto max_bytes_to_read = std::min(pending_received_data_.length(), length); + pending_received_data_.copyOut(0, max_bytes_to_read, buffer); if (!(flags & MSG_PEEK)) { - owned_buffer_.drain(max_bytes_to_read); + pending_received_data_.drain(max_bytes_to_read); } return {max_bytes_to_read, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/common/network/buffered_io_socket_handle_impl.h index dc56967aec73..aaba6167784a 100644 --- a/source/common/network/buffered_io_socket_handle_impl.h +++ b/source/common/network/buffered_io_socket_handle_impl.h @@ -71,7 +71,7 @@ class BufferedIoSocketHandleImpl : public IoHandle, Api::SysCallIntResult shutdown(int how) override; absl::optional lastRoundTripTime() override { return absl::nullopt; } - Buffer::WatermarkBuffer& getBufferForTest() { return owned_buffer_; } + Buffer::WatermarkBuffer& getBufferForTest() { return pending_received_data_; } void scheduleNextEvent() { // It's possible there is no pending file event so as no io_callback. @@ -101,12 +101,14 @@ class BufferedIoSocketHandleImpl : public IoHandle, } void onPeerBufferWritable() override { scheduleNextEvent(); } bool isWritable() const override { return !isOverHighWatermark(); } - Buffer::Instance* getWriteBuffer() override { return &owned_buffer_; } + Buffer::Instance* getWriteBuffer() override { return &pending_received_data_; } // ReadableSource bool isPeerShutDownWrite() const override { return read_end_stream_; } bool isOverHighWatermark() const override { return over_high_watermark_; } - bool isReadable() const override { return isPeerShutDownWrite() || owned_buffer_.length() > 0; } + bool isReadable() const override { + return isPeerShutDownWrite() || pending_received_data_.length() > 0; + } private: // Support isOpen() and close(). IoHandle owner must invoke close() to avoid potential resource @@ -121,9 +123,10 @@ class BufferedIoSocketHandleImpl : public IoHandle, // The schedulable handle of the above event. Event::SchedulableCallbackPtr io_callback_; - // True if owned_buffer_ is not addable. Note that owned_buffer_ may have pending data to drain. + // True if pending_received_data_ is not addable. Note that pending_received_data_ may have + // pending data to drain. bool read_end_stream_{false}; - Buffer::WatermarkBuffer owned_buffer_; + Buffer::WatermarkBuffer pending_received_data_; // Destination of the write(). WritablePeer* writable_peer_{nullptr}; diff --git a/tools/spelling/spelling_dictionary.txt b/tools/spelling/spelling_dictionary.txt index c7207ecb5d4c..733c6d425264 100644 --- a/tools/spelling/spelling_dictionary.txt +++ b/tools/spelling/spelling_dictionary.txt @@ -28,6 +28,7 @@ CDN CDS CEL DSR +EBADF ENOTCONN EPIPE HEXDIG From 437eb9bde2de704e0392f4e58cbfc4c8bc859a4c Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 22 Oct 2020 09:39:47 +0000 Subject: [PATCH 069/100] complete user space file event test Signed-off-by: Yuchen Dai --- .../event/user_space_file_event_impl.cc | 2 +- test/common/event/BUILD | 2 - .../event/user_space_file_event_impl_test.cc | 185 +++++++++++++++++- 3 files changed, 183 insertions(+), 6 deletions(-) diff --git a/source/common/event/user_space_file_event_impl.cc b/source/common/event/user_space_file_event_impl.cc index 5e7164c5d3f7..11d136364419 100644 --- a/source/common/event/user_space_file_event_impl.cc +++ b/source/common/event/user_space_file_event_impl.cc @@ -17,7 +17,7 @@ void DefaultEventListener::onEventActivated(uint32_t activated_events) { // Event owner should not activate any event which is disabled. // Also see onEventEnabled which clears ephemeral events. // The overall prevents callback on disabled events. - ASSERT((ephermal_events_ & ~enabled_events_) == 0); + ASSERT((activated_events & ~enabled_events_) == 0); ephermal_events_ |= activated_events; } diff --git a/test/common/event/BUILD b/test/common/event/BUILD index 763d05bb033f..290f9f80865f 100644 --- a/test/common/event/BUILD +++ b/test/common/event/BUILD @@ -45,12 +45,10 @@ envoy_cc_test( envoy_cc_test( name = "user_space_file_event_impl_test", srcs = ["user_space_file_event_impl_test.cc"], - #tags = ["fails_on_windows"], deps = [ "//include/envoy/event:file_event_interface", "//source/common/event:dispatcher_includes", "//source/common/event:dispatcher_lib", - "//source/common/stats:isolated_store_lib", "//test/mocks:common_lib", "//test/test_common:environment_lib", "//test/test_common:test_runtime_lib", diff --git a/test/common/event/user_space_file_event_impl_test.cc b/test/common/event/user_space_file_event_impl_test.cc index 5b2471e0b1fa..31b2286f338b 100644 --- a/test/common/event/user_space_file_event_impl_test.cc +++ b/test/common/event/user_space_file_event_impl_test.cc @@ -2,30 +2,209 @@ #include "envoy/event/file_event.h" -#include "common/api/os_sys_calls_impl.h" #include "common/event/dispatcher_impl.h" -#include "common/stats/isolated_store_impl.h" +#include "common/event/user_space_file_event_impl.h" #include "test/mocks/common.h" #include "test/test_common/environment.h" #include "test/test_common/test_runtime.h" #include "test/test_common/utility.h" +#include "gmock/gmock.h" #include "gtest/gtest.h" namespace Envoy { namespace Event { namespace { +constexpr auto event_rw = Event::FileReadyType::Read | Event::FileReadyType::Write; +class MockReadyCb { +public: + MOCK_METHOD(void, called, (uint32_t)); +}; + class UserSpaceFileEventImplTest : public testing::Test { public: UserSpaceFileEventImplTest() - : api_(Api::createApiForTest()), dispatcher_(api_->allocateDispatcher("test_thread")) {} + : api_(Api::createApiForTest()), dispatcher_(api_->allocateDispatcher("test_thread")) { + io_callback_ = + dispatcher_->createSchedulableCallback([this]() { user_file_event_->onEvents(); }); + } + + void scheduleNextEvent() { + ASSERT(io_callback_ != nullptr); + io_callback_->scheduleCallbackNextIteration(); + } protected: + MockReadyCb ready_cb_; Api::ApiPtr api_; DispatcherPtr dispatcher_; + std::unique_ptr user_file_event_; + Event::SchedulableCallbackPtr io_callback_; }; + +TEST_F(UserSpaceFileEventImplTest, TestLevelTriggerIsNotSupported) { + ASSERT_DEBUG_DEATH(Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, + Event::FileTriggerType::Level, event_rw, *io_callback_), + "assert failure"); +} + +TEST_F(UserSpaceFileEventImplTest, TestEnabledEventsTriggeredAfterCreate) { + user_file_event_ = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, + event_rw, *io_callback_); + scheduleNextEvent(); + EXPECT_CALL(ready_cb_, called(event_rw)); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); +} + +TEST_F(UserSpaceFileEventImplTest, TestDebugDeathOnActivateDisabledEvents) { + user_file_event_ = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, + Event::FileReadyType::Read, *io_callback_); + ASSERT_DEBUG_DEATH(user_file_event_->activate(Event::FileReadyType::Write), ""); +} + +TEST_F(UserSpaceFileEventImplTest, TestRescheduleAfterTriggered) { + user_file_event_ = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, + event_rw, *io_callback_); + { + SCOPED_TRACE("1st schedule"); + scheduleNextEvent(); + EXPECT_CALL(ready_cb_, called(event_rw)); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } + + { + SCOPED_TRACE("2nd schedule"); + scheduleNextEvent(); + EXPECT_CALL(ready_cb_, called(event_rw)); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } +} + +TEST_F(UserSpaceFileEventImplTest, TestRescheduleIsDeduplicated) { + user_file_event_ = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, + event_rw, *io_callback_); + { + SCOPED_TRACE("1st schedule"); + scheduleNextEvent(); + scheduleNextEvent(); + EXPECT_CALL(ready_cb_, called(event_rw)).Times(1); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } + + { + SCOPED_TRACE("further dispatcher drive"); + EXPECT_CALL(ready_cb_, called(_)).Times(0); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } +} + +TEST_F(UserSpaceFileEventImplTest, TestDefaultReturnAllEnabledReadAndWriteEvents) { + std::vector events{Event::FileReadyType::Read, Event::FileReadyType::Write, event_rw}; + for (const auto& e : events) { + SCOPED_TRACE(absl::StrCat("current event:", e)); + user_file_event_ = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, + event_rw, *io_callback_); + scheduleNextEvent(); + EXPECT_CALL(ready_cb_, called(event_rw)); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + user_file_event_.reset(); + } +} + +TEST_F(UserSpaceFileEventImplTest, TestActivateWillSchedule) { + user_file_event_ = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, + event_rw, *io_callback_); + { + EXPECT_CALL(ready_cb_, called(_)).Times(0); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } + { + user_file_event_->activate(Event::FileReadyType::Read); + EXPECT_CALL(ready_cb_, called(event_rw)).Times(1); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } + { + user_file_event_->activate(Event::FileReadyType::Write); + EXPECT_CALL(ready_cb_, called(event_rw)).Times(1); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } +} + +TEST_F(UserSpaceFileEventImplTest, TestActivateDedup) { + user_file_event_ = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, + event_rw, *io_callback_); + { + EXPECT_CALL(ready_cb_, called(_)).Times(0); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } + { + user_file_event_->activate(Event::FileReadyType::Read); + user_file_event_->activate(Event::FileReadyType::Write); + user_file_event_->activate(Event::FileReadyType::Write); + user_file_event_->activate(Event::FileReadyType::Read); + EXPECT_CALL(ready_cb_, called(event_rw)).Times(1); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } + { + EXPECT_CALL(ready_cb_, called(_)).Times(0); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } +} + +TEST_F(UserSpaceFileEventImplTest, TestEnabledClearActivate) { + user_file_event_ = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, + event_rw, *io_callback_); + { + EXPECT_CALL(ready_cb_, called(_)).Times(0); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } + { + user_file_event_->activate(Event::FileReadyType::Read); + user_file_event_->setEnabled(Event::FileReadyType::Write); + + EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Write)).Times(1); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } + { + EXPECT_CALL(ready_cb_, called(_)).Times(0); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } +} + +TEST_F(UserSpaceFileEventImplTest, TestEventClosedIsNotTriggeredUnlessManullyActivated) { + user_file_event_ = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, + Event::FileReadyType::Write | Event::FileReadyType::Closed, *io_callback_); + { + scheduleNextEvent(); + // No Closed event bit if enabled by not activated. + EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Write)).Times(1); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } + { + user_file_event_->activate(Event::FileReadyType::Closed); + // Activate could deliver Closed event bit. + EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Write | Event::FileReadyType::Closed)) + .Times(1); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } + { + EXPECT_CALL(ready_cb_, called(_)).Times(0); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } +} + } // namespace } // namespace Event } // namespace Envoy \ No newline at end of file From 9299130ff6a12c09dbb1b2571c7d57ba1cdea1ed Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 22 Oct 2020 19:29:26 +0000 Subject: [PATCH 070/100] fix destroy order in test Signed-off-by: Yuchen Dai --- test/common/event/user_space_file_event_impl_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/common/event/user_space_file_event_impl_test.cc b/test/common/event/user_space_file_event_impl_test.cc index 31b2286f338b..1eabfafe6867 100644 --- a/test/common/event/user_space_file_event_impl_test.cc +++ b/test/common/event/user_space_file_event_impl_test.cc @@ -40,8 +40,8 @@ class UserSpaceFileEventImplTest : public testing::Test { MockReadyCb ready_cb_; Api::ApiPtr api_; DispatcherPtr dispatcher_; - std::unique_ptr user_file_event_; Event::SchedulableCallbackPtr io_callback_; + std::unique_ptr user_file_event_; }; TEST_F(UserSpaceFileEventImplTest, TestLevelTriggerIsNotSupported) { From 1b4a204df625485bb02be5a80c9b528e193af02b Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Tue, 27 Oct 2020 09:02:55 +0000 Subject: [PATCH 071/100] address comment: no schedule next, typo Signed-off-by: Yuchen Dai --- .../event/user_space_file_event_impl.cc | 17 ++++++++-------- .../common/event/user_space_file_event_impl.h | 10 +++++----- .../network/buffered_io_socket_handle_impl.cc | 4 +--- .../network/buffered_io_socket_handle_impl.h | 20 +++++++++---------- .../event/user_space_file_event_impl_test.cc | 7 +++---- .../buffered_io_socket_handle_impl_test.cc | 3 +++ 6 files changed, 29 insertions(+), 32 deletions(-) diff --git a/source/common/event/user_space_file_event_impl.cc b/source/common/event/user_space_file_event_impl.cc index 11d136364419..7dc05d9ca686 100644 --- a/source/common/event/user_space_file_event_impl.cc +++ b/source/common/event/user_space_file_event_impl.cc @@ -7,18 +7,17 @@ namespace Envoy { namespace Event { -void DefaultEventListener::onEventEnabled(uint32_t enabled_events) { +void EventListenerImpl::onEventEnabled(uint32_t enabled_events) { enabled_events_ = enabled_events; // Clear ephemeral events to align with FileEventImpl::setEnable(). - ephermal_events_ = 0; + ephemeral_events_ = 0; } -void DefaultEventListener::onEventActivated(uint32_t activated_events) { - // Event owner should not activate any event which is disabled. - // Also see onEventEnabled which clears ephemeral events. - // The overall prevents callback on disabled events. - ASSERT((activated_events & ~enabled_events_) == 0); - ephermal_events_ |= activated_events; +void EventListenerImpl::onEventActivated(uint32_t activated_events) { + // Normally event owner should not activate any event which is disabled. Known exceptions includes + // ConsumerWantsToRead() == true. + // TODO(lambdai): Stricter check. + ephemeral_events_ |= activated_events; } void UserSpaceFileEventImpl::activate(uint32_t events) { @@ -52,7 +51,7 @@ UserSpaceFileEventImpl::UserSpaceFileEventImpl(Event::FileReadyCb cb, uint32_t e static_cast(this), all_events, ephemeral_events); cb(all_events | ephemeral_events); }) { - event_listener_.onEventEnabled(events); + setEnabled(events); } std::unique_ptr UserSpaceFileEventFactory::createUserSpaceFileEventImpl( diff --git a/source/common/event/user_space_file_event_impl.h b/source/common/event/user_space_file_event_impl.h index 7579b2a1fff0..ed2f3de3409f 100644 --- a/source/common/event/user_space_file_event_impl.h +++ b/source/common/event/user_space_file_event_impl.h @@ -49,9 +49,9 @@ class EventListener { // must assume EV_CLOSED is never activated. Also event owner must tolerate that OS could notify // events which are not actually triggered. // TODO(lambdai): Add support of delivering EV_CLOSED. -class DefaultEventListener : public EventListener { +class EventListenerImpl : public EventListener { public: - ~DefaultEventListener() override = default; + ~EventListenerImpl() override = default; // Return both read and write if enabled. Note that this implementation is inefficient. Read and // write events are supposed to be independent. @@ -60,13 +60,13 @@ class DefaultEventListener : public EventListener { void onEventEnabled(uint32_t enabled_events) override; void onEventActivated(uint32_t activated_events) override; - uint32_t getAndClearEphemeralEvents() override { return std::exchange(ephermal_events_, 0); } + uint32_t getAndClearEphemeralEvents() override { return std::exchange(ephemeral_events_, 0); } private: // The persisted interested events. The name on libevent document is pending event. uint32_t enabled_events_{}; // The events set by activate() and will be cleared after the io callback. - uint32_t ephermal_events_{}; + uint32_t ephemeral_events_{}; }; // A FileEvent implementation which is used to drive BufferedIoSocketHandle. @@ -92,7 +92,7 @@ class UserSpaceFileEventImpl : public FileEvent, Logger::Loggable(writable_peer_)); // Notify the peer we won't write more data. shutdown(WRITE). writable_peer_->setWriteEnd(); + writable_peer_->maybeSetNewData(); // Notify the peer that we no longer accept data. shutdown(RD). writable_peer_->onPeerDestroy(); - writable_peer_->maybeSetNewData(); writable_peer_ = nullptr; } else { ENVOY_LOG(trace, "socket {} close after peer closed.", static_cast(this)); @@ -260,8 +260,6 @@ Event::FileEventPtr BufferedIoSocketHandleImpl::createFileEvent(Event::Dispatche auto event = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( dispatcher, cb, trigger_type, events, *io_callback_); user_file_event_ = event.get(); - // Blindly activate the events. - io_callback_->scheduleCallbackNextIteration(); return event; } diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/common/network/buffered_io_socket_handle_impl.h index aaba6167784a..44f438089fa4 100644 --- a/source/common/network/buffered_io_socket_handle_impl.h +++ b/source/common/network/buffered_io_socket_handle_impl.h @@ -73,14 +73,6 @@ class BufferedIoSocketHandleImpl : public IoHandle, Buffer::WatermarkBuffer& getBufferForTest() { return pending_received_data_; } - void scheduleNextEvent() { - // It's possible there is no pending file event so as no io_callback. - if (io_callback_) { - ENVOY_LOG(trace, "Schedule IO callback on {}", static_cast(this)); - io_callback_->scheduleCallbackNextIteration(); - } - } - void setWritablePeer(WritablePeer* writable_peer) { // Swapping writable peer is undefined behavior. ASSERT(!writable_peer_); @@ -93,13 +85,19 @@ class BufferedIoSocketHandleImpl : public IoHandle, bool isWriteEndSet() override { return read_end_stream_; } void maybeSetNewData() override { ENVOY_LOG(trace, "{} on socket {}", __FUNCTION__, static_cast(this)); - scheduleNextEvent(); + if (user_file_event_) { + user_file_event_->activate(Event::FileReadyType::Write); + } } void onPeerDestroy() override { writable_peer_ = nullptr; write_shutdown_ = true; } - void onPeerBufferWritable() override { scheduleNextEvent(); } + void onPeerBufferWritable() override { + if (user_file_event_) { + user_file_event_->activate(Event::FileReadyType::Read); + } + } bool isWritable() const override { return !isOverHighWatermark(); } Buffer::Instance* getWriteBuffer() override { return &pending_received_data_; } @@ -118,7 +116,7 @@ class BufferedIoSocketHandleImpl : public IoHandle, // The attached file event with this socket. The event is not owned by the socket in the current // Envoy model. Multiple events can be created during the life time of this IO handle but at any // moment at most 1 event is attached. - Event::UserSpaceFileEventImpl* user_file_event_; + Event::UserSpaceFileEventImpl* user_file_event_{}; // The schedulable handle of the above event. Event::SchedulableCallbackPtr io_callback_; diff --git a/test/common/event/user_space_file_event_impl_test.cc b/test/common/event/user_space_file_event_impl_test.cc index 1eabfafe6867..a42a35b0bf8a 100644 --- a/test/common/event/user_space_file_event_impl_test.cc +++ b/test/common/event/user_space_file_event_impl_test.cc @@ -124,7 +124,7 @@ TEST_F(UserSpaceFileEventImplTest, TestActivateWillSchedule) { *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, event_rw, *io_callback_); { - EXPECT_CALL(ready_cb_, called(_)).Times(0); + EXPECT_CALL(ready_cb_, called(_)).Times(1); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } { @@ -144,7 +144,7 @@ TEST_F(UserSpaceFileEventImplTest, TestActivateDedup) { *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, event_rw, *io_callback_); { - EXPECT_CALL(ready_cb_, called(_)).Times(0); + EXPECT_CALL(ready_cb_, called(_)).Times(1); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } { @@ -166,7 +166,7 @@ TEST_F(UserSpaceFileEventImplTest, TestEnabledClearActivate) { *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, event_rw, *io_callback_); { - EXPECT_CALL(ready_cb_, called(_)).Times(0); + EXPECT_CALL(ready_cb_, called(_)).Times(1); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } { @@ -187,7 +187,6 @@ TEST_F(UserSpaceFileEventImplTest, TestEventClosedIsNotTriggeredUnlessManullyAct *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, Event::FileReadyType::Write | Event::FileReadyType::Closed, *io_callback_); { - scheduleNextEvent(); // No Closed event bit if enabled by not activated. EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Write)).Times(1); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index 52f8b6bc9205..752a65e41a2d 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -316,6 +316,8 @@ TEST_F(BufferedIoSocketHandleTest, TestDrainToLowWaterMarkTriggerReadEvent) { EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()).Times(1); auto result = io_handle_->recv(buf_.data(), 232, 0); EXPECT_TRUE(handle_as_peer->isWritable()); + EXPECT_CALL(cb_, called(_)); + scheduable_cb_->invokeCallback(); } EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()).Times(1); @@ -414,6 +416,7 @@ TEST_F(BufferedIoSocketHandleTest, TestShutDownRaiseEvent) { TEST_F(BufferedIoSocketHandleTest, TestRepeatedShutdownWR) { EXPECT_EQ(io_handle_peer_->shutdown(ENVOY_SHUT_WR).rc_, 0); + ENVOY_LOG_MISC(debug, "lambdai: next shutdown"); EXPECT_EQ(io_handle_peer_->shutdown(ENVOY_SHUT_WR).rc_, 0); } From 58971d92cc2aeae20ac91938fab353fdd14e09b6 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Wed, 28 Oct 2020 08:51:47 +0000 Subject: [PATCH 072/100] file event owned by io handle Signed-off-by: Yuchen Dai --- .../event/user_space_file_event_impl.cc | 23 ++---- .../common/event/user_space_file_event_impl.h | 30 ++++---- .../network/buffered_io_socket_handle_impl.cc | 40 +++++++--- .../network/buffered_io_socket_handle_impl.h | 15 ++-- .../event/user_space_file_event_impl_test.cc | 75 ++++++------------- .../buffered_io_socket_handle_impl_test.cc | 52 ++++++------- 6 files changed, 110 insertions(+), 125 deletions(-) diff --git a/source/common/event/user_space_file_event_impl.cc b/source/common/event/user_space_file_event_impl.cc index 7dc05d9ca686..ae188d5c4ea3 100644 --- a/source/common/event/user_space_file_event_impl.cc +++ b/source/common/event/user_space_file_event_impl.cc @@ -24,8 +24,8 @@ void UserSpaceFileEventImpl::activate(uint32_t events) { // Only supported event types are set. ASSERT((events & (FileReadyType::Read | FileReadyType::Write | FileReadyType::Closed)) == events); event_listener_.onEventActivated(events); - if (!schedulable_.enabled()) { - schedulable_.scheduleCallbackNextIteration(); + if (!schedulable_->enabled()) { + schedulable_->scheduleCallbackNextIteration(); } } @@ -33,17 +33,18 @@ void UserSpaceFileEventImpl::setEnabled(uint32_t events) { // Only supported event types are set. ASSERT((events & (FileReadyType::Read | FileReadyType::Write | FileReadyType::Closed)) == events); event_listener_.onEventEnabled(events); - bool was_enabled = schedulable_.enabled(); + bool was_enabled = schedulable_->enabled(); if (!was_enabled) { - schedulable_.scheduleCallbackNextIteration(); + schedulable_->scheduleCallbackNextIteration(); } ENVOY_LOG(trace, "User space file event {} set events {}. Will {} reschedule.", static_cast(this), events, was_enabled ? "not " : ""); } -UserSpaceFileEventImpl::UserSpaceFileEventImpl(Event::FileReadyCb cb, uint32_t events, - SchedulableCallback& schedulable_cb) - : schedulable_(schedulable_cb), cb_([this, cb]() { +UserSpaceFileEventImpl::UserSpaceFileEventImpl(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, uint32_t events) + : schedulable_( + dispatcher.createSchedulableCallback([this]() { onEvents(); }) + ), cb_([this, cb]() { auto all_events = getEventListener().triggeredEvents(); auto ephemeral_events = getEventListener().getAndClearEphemeralEvents(); ENVOY_LOG(trace, @@ -54,13 +55,5 @@ UserSpaceFileEventImpl::UserSpaceFileEventImpl(Event::FileReadyCb cb, uint32_t e setEnabled(events); } -std::unique_ptr UserSpaceFileEventFactory::createUserSpaceFileEventImpl( - Event::Dispatcher&, Event::FileReadyCb cb, Event::FileTriggerType trigger_type, uint32_t events, - SchedulableCallback& scheduable_cb) { - ASSERT(trigger_type == Event::FileTriggerType::Edge); - return std::unique_ptr( - new UserSpaceFileEventImpl(cb, events, scheduable_cb)); -} - } // namespace Event } // namespace Envoy \ No newline at end of file diff --git a/source/common/event/user_space_file_event_impl.h b/source/common/event/user_space_file_event_impl.h index ed2f3de3409f..2cab56f53c1f 100644 --- a/source/common/event/user_space_file_event_impl.h +++ b/source/common/event/user_space_file_event_impl.h @@ -14,9 +14,6 @@ class BufferedIoSocketHandleImpl; } namespace Event { -// Forward declare for friend class. -class UserSpaceFileEventFactory; - // The interface of populating event watcher and obtaining the active events. The events are the // combination of FileReadyType values. The event listener is populated by user event registration // and io events passively. Also the owner of this listener query the activated events by calling @@ -72,9 +69,11 @@ class EventListenerImpl : public EventListener { // A FileEvent implementation which is used to drive BufferedIoSocketHandle. class UserSpaceFileEventImpl : public FileEvent, Logger::Loggable { public: + UserSpaceFileEventImpl(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, uint32_t events); + ~UserSpaceFileEventImpl() override { - if (schedulable_.enabled()) { - schedulable_.cancel(); + if (schedulable_->enabled()) { + schedulable_->cancel(); } } @@ -84,30 +83,27 @@ class UserSpaceFileEventImpl : public FileEvent, Logger::Loggableenabled()) { + schedulable_->scheduleCallbackNextIteration(); + } + } + friend class Network::BufferedIoSocketHandleImpl; private: - UserSpaceFileEventImpl(Event::FileReadyCb cb, uint32_t events, - SchedulableCallback& schedulable_cb); - // Used to populate the event operations of enable and activate. EventListenerImpl event_listener_; // The handle to registered async callback from dispatcher. - SchedulableCallback& schedulable_; + Event::SchedulableCallbackPtr schedulable_; // The registered callback of this event. This callback is usually on top of the frame of // Dispatcher::run(). std::function cb_; }; -class UserSpaceFileEventFactory { -public: - static std::unique_ptr - createUserSpaceFileEventImpl(Event::Dispatcher&, Event::FileReadyCb cb, Event::FileTriggerType, - uint32_t events, SchedulableCallback& scheduable_cb); -}; - } // namespace Event } // namespace Envoy diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc index e6dae7e5ca37..6e47ab9fb543 100644 --- a/source/common/network/buffered_io_socket_handle_impl.cc +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -252,16 +252,38 @@ Address::InstanceConstSharedPtr BufferedIoSocketHandleImpl::peerAddress() { throw EnvoyException(fmt::format("getsockname failed for BufferedIoSocketHandleImpl")); } -Event::FileEventPtr BufferedIoSocketHandleImpl::createFileEvent(Event::Dispatcher& dispatcher, - Event::FileReadyCb cb, - Event::FileTriggerType trigger_type, - uint32_t events) { - io_callback_ = dispatcher.createSchedulableCallback([this]() { user_file_event_->onEvents(); }); - auto event = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( - dispatcher, cb, trigger_type, events, *io_callback_); - user_file_event_ = event.get(); - return event; +void BufferedIoSocketHandleImpl::initializeFileEvent(Event::Dispatcher& dispatcher, + Event::FileReadyCb cb, + Event::FileTriggerType trigger, + uint32_t events) { + ASSERT(user_file_event_ == nullptr, "Attempting to initialize two `file_event_` for the same " + "file descriptor. This is not allowed."); + ASSERT(trigger == Event::FileTriggerType::Edge, "Only support edge type."); + user_file_event_ = std::make_unique(dispatcher, cb, events); } +IoHandlePtr BufferedIoSocketHandleImpl::duplicate() { + // duplicate() is supposed to be used on listener io handle while this implementation doesn't + // support listen. + NOT_IMPLEMENTED_GCOVR_EXCL_LINE; +} + +void BufferedIoSocketHandleImpl::activateFileEvents(uint32_t events) { + if (user_file_event_) { + user_file_event_->activate(events); + } else { + ENVOY_BUG(false, "Null user_file_event_"); + } +} + +void BufferedIoSocketHandleImpl::enableFileEvents(uint32_t events) { + if (user_file_event_) { + user_file_event_->setEnabled(events); + } else { + ENVOY_BUG(false, "Null user_file_event_"); + } +} + +void BufferedIoSocketHandleImpl::resetFileEvents() { user_file_event_.reset(); } Api::SysCallIntResult BufferedIoSocketHandleImpl::shutdown(int how) { // Support only shutdown write. diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/common/network/buffered_io_socket_handle_impl.h index 44f438089fa4..b87b9baf04a4 100644 --- a/source/common/network/buffered_io_socket_handle_impl.h +++ b/source/common/network/buffered_io_socket_handle_impl.h @@ -66,8 +66,14 @@ class BufferedIoSocketHandleImpl : public IoHandle, absl::optional domain() override; Address::InstanceConstSharedPtr localAddress() override; Address::InstanceConstSharedPtr peerAddress() override; - Event::FileEventPtr createFileEvent(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, - Event::FileTriggerType trigger, uint32_t events) override; + + void initializeFileEvent(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, + Event::FileTriggerType trigger, uint32_t events) override; + IoHandlePtr duplicate() override; + void activateFileEvents(uint32_t events) override; + void enableFileEvents(uint32_t events) override; + void resetFileEvents() override; + Api::SysCallIntResult shutdown(int how) override; absl::optional lastRoundTripTime() override { return absl::nullopt; } @@ -116,10 +122,7 @@ class BufferedIoSocketHandleImpl : public IoHandle, // The attached file event with this socket. The event is not owned by the socket in the current // Envoy model. Multiple events can be created during the life time of this IO handle but at any // moment at most 1 event is attached. - Event::UserSpaceFileEventImpl* user_file_event_{}; - - // The schedulable handle of the above event. - Event::SchedulableCallbackPtr io_callback_; + std::unique_ptr user_file_event_; // True if pending_received_data_ is not addable. Note that pending_received_data_ may have // pending data to drain. diff --git a/test/common/event/user_space_file_event_impl_test.cc b/test/common/event/user_space_file_event_impl_test.cc index a42a35b0bf8a..53914c9f3f19 100644 --- a/test/common/event/user_space_file_event_impl_test.cc +++ b/test/common/event/user_space_file_event_impl_test.cc @@ -27,73 +27,48 @@ class UserSpaceFileEventImplTest : public testing::Test { public: UserSpaceFileEventImplTest() : api_(Api::createApiForTest()), dispatcher_(api_->allocateDispatcher("test_thread")) { - io_callback_ = - dispatcher_->createSchedulableCallback([this]() { user_file_event_->onEvents(); }); - } - - void scheduleNextEvent() { - ASSERT(io_callback_ != nullptr); - io_callback_->scheduleCallbackNextIteration(); } protected: MockReadyCb ready_cb_; Api::ApiPtr api_; DispatcherPtr dispatcher_; - Event::SchedulableCallbackPtr io_callback_; std::unique_ptr user_file_event_; }; -TEST_F(UserSpaceFileEventImplTest, TestLevelTriggerIsNotSupported) { - ASSERT_DEBUG_DEATH(Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, - Event::FileTriggerType::Level, event_rw, *io_callback_), - "assert failure"); -} - TEST_F(UserSpaceFileEventImplTest, TestEnabledEventsTriggeredAfterCreate) { - user_file_event_ = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, - event_rw, *io_callback_); - scheduleNextEvent(); + user_file_event_ = std::make_unique( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw); EXPECT_CALL(ready_cb_, called(event_rw)); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } -TEST_F(UserSpaceFileEventImplTest, TestDebugDeathOnActivateDisabledEvents) { - user_file_event_ = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, - Event::FileReadyType::Read, *io_callback_); - ASSERT_DEBUG_DEATH(user_file_event_->activate(Event::FileReadyType::Write), ""); -} - TEST_F(UserSpaceFileEventImplTest, TestRescheduleAfterTriggered) { - user_file_event_ = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, - event_rw, *io_callback_); + user_file_event_ = std::make_unique( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw); { SCOPED_TRACE("1st schedule"); - scheduleNextEvent(); + user_file_event_->activate(event_rw); EXPECT_CALL(ready_cb_, called(event_rw)); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } { SCOPED_TRACE("2nd schedule"); - scheduleNextEvent(); + user_file_event_->activate(event_rw); EXPECT_CALL(ready_cb_, called(event_rw)); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } } TEST_F(UserSpaceFileEventImplTest, TestRescheduleIsDeduplicated) { - user_file_event_ = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, - event_rw, *io_callback_); + user_file_event_ = std::make_unique( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw); { SCOPED_TRACE("1st schedule"); - scheduleNextEvent(); - scheduleNextEvent(); + user_file_event_->activate(event_rw); + + user_file_event_->activate(event_rw); EXPECT_CALL(ready_cb_, called(event_rw)).Times(1); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } @@ -109,10 +84,9 @@ TEST_F(UserSpaceFileEventImplTest, TestDefaultReturnAllEnabledReadAndWriteEvents std::vector events{Event::FileReadyType::Read, Event::FileReadyType::Write, event_rw}; for (const auto& e : events) { SCOPED_TRACE(absl::StrCat("current event:", e)); - user_file_event_ = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, - event_rw, *io_callback_); - scheduleNextEvent(); + user_file_event_ = std::make_unique( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw); + user_file_event_->activate(e); EXPECT_CALL(ready_cb_, called(event_rw)); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); user_file_event_.reset(); @@ -120,9 +94,8 @@ TEST_F(UserSpaceFileEventImplTest, TestDefaultReturnAllEnabledReadAndWriteEvents } TEST_F(UserSpaceFileEventImplTest, TestActivateWillSchedule) { - user_file_event_ = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, - event_rw, *io_callback_); + user_file_event_ = std::make_unique( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw); { EXPECT_CALL(ready_cb_, called(_)).Times(1); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); @@ -140,9 +113,8 @@ TEST_F(UserSpaceFileEventImplTest, TestActivateWillSchedule) { } TEST_F(UserSpaceFileEventImplTest, TestActivateDedup) { - user_file_event_ = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, - event_rw, *io_callback_); + user_file_event_ = std::make_unique( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw); { EXPECT_CALL(ready_cb_, called(_)).Times(1); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); @@ -162,9 +134,8 @@ TEST_F(UserSpaceFileEventImplTest, TestActivateDedup) { } TEST_F(UserSpaceFileEventImplTest, TestEnabledClearActivate) { - user_file_event_ = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, - event_rw, *io_callback_); + user_file_event_ = std::make_unique( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw); { EXPECT_CALL(ready_cb_, called(_)).Times(1); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); @@ -183,9 +154,9 @@ TEST_F(UserSpaceFileEventImplTest, TestEnabledClearActivate) { } TEST_F(UserSpaceFileEventImplTest, TestEventClosedIsNotTriggeredUnlessManullyActivated) { - user_file_event_ = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, - Event::FileReadyType::Write | Event::FileReadyType::Closed, *io_callback_); + user_file_event_ = std::make_unique( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, + Event::FileReadyType::Write | Event::FileReadyType::Closed); { // No Closed event bit if enabled by not activated. EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Write)).Times(1); diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index 752a65e41a2d..7bd72fde5671 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -189,19 +189,19 @@ TEST_F(BufferedIoSocketHandleTest, FlowControl) { TEST_F(BufferedIoSocketHandleTest, EventScheduleBasic) { scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); - auto ev = io_handle_->createFileEvent( + io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); EXPECT_CALL(cb_, called(_)); scheduable_cb_->invokeCallback(); - ev.reset(); + io_handle_->resetFileEvents(); } TEST_F(BufferedIoSocketHandleTest, TestSetEnabledTriggerEventSchedule) { scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); - auto ev = io_handle_->createFileEvent( + io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); @@ -211,32 +211,32 @@ TEST_F(BufferedIoSocketHandleTest, TestSetEnabledTriggerEventSchedule) { ASSERT_FALSE(scheduable_cb_->enabled()); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); - ev->setEnabled(Event::FileReadyType::Read); + io_handle_->enableFileEvents(Event::FileReadyType::Read); ASSERT_TRUE(scheduable_cb_->enabled()); EXPECT_CALL(cb_, called(_)); scheduable_cb_->invokeCallback(); ASSERT_FALSE(scheduable_cb_->enabled()); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); - ev->setEnabled(Event::FileReadyType::Write); + io_handle_->enableFileEvents(Event::FileReadyType::Write); ASSERT_TRUE(scheduable_cb_->enabled()); EXPECT_CALL(cb_, called(Event::FileReadyType::Write)); scheduable_cb_->invokeCallback(); ASSERT_FALSE(scheduable_cb_->enabled()); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); - ev->setEnabled(Event::FileReadyType::Write | Event::FileReadyType::Read); + io_handle_->enableFileEvents(Event::FileReadyType::Write | Event::FileReadyType::Read); ASSERT_TRUE(scheduable_cb_->enabled()); EXPECT_CALL(cb_, called(Event::FileReadyType::Write | Event::FileReadyType::Read)); scheduable_cb_->invokeCallback(); ASSERT_FALSE(scheduable_cb_->enabled()); - ev.reset(); + io_handle_->resetFileEvents(); } TEST_F(BufferedIoSocketHandleTest, TestReadAndWriteAreEdgeTriggered) { scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); - auto ev = io_handle_->createFileEvent( + io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); @@ -254,35 +254,35 @@ TEST_F(BufferedIoSocketHandleTest, TestReadAndWriteAreEdgeTriggered) { EXPECT_EQ(1, result.rc_); ASSERT_FALSE(scheduable_cb_->enabled()); - ev.reset(); + io_handle_->resetFileEvents(); } TEST_F(BufferedIoSocketHandleTest, TestSetDisabledBlockEventSchedule) { scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); - auto ev = io_handle_->createFileEvent( + io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); - ev->setEnabled(0); + io_handle_->enableFileEvents(0); EXPECT_CALL(cb_, called(0)); scheduable_cb_->invokeCallback(); ASSERT_FALSE(scheduable_cb_->enabled()); - ev.reset(); + io_handle_->resetFileEvents(); } TEST_F(BufferedIoSocketHandleTest, TestEventResetClearCallback) { scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); - auto ev = io_handle_->createFileEvent( + io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); ASSERT_TRUE(scheduable_cb_->enabled()); - - ev.reset(); - ASSERT_FALSE(scheduable_cb_->enabled()); + + EXPECT_CALL(cb_, called(_)).Times(0); + io_handle_->resetFileEvents(); } TEST_F(BufferedIoSocketHandleTest, TestDrainToLowWaterMarkTriggerReadEvent) { @@ -300,7 +300,7 @@ TEST_F(BufferedIoSocketHandleTest, TestDrainToLowWaterMarkTriggerReadEvent) { // Clear invoke callback on peer. scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); - auto ev = io_handle_peer_->createFileEvent( + io_handle_peer_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); ASSERT_TRUE(scheduable_cb_->enabled()); @@ -331,7 +331,7 @@ TEST_F(BufferedIoSocketHandleTest, TestClose) { scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); bool should_close = false; - auto ev = io_handle_->createFileEvent( + io_handle_->initializeFileEvent( dispatcher_, [this, &should_close, handle = io_handle_.get(), &accumulator](uint32_t events) { if (events & Event::FileReadyType::Read) { @@ -369,7 +369,7 @@ TEST_F(BufferedIoSocketHandleTest, TestClose) { EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()).Times(0); io_handle_->close(); EXPECT_EQ(4, accumulator.size()); - ev.reset(); + io_handle_->resetFileEvents(); } // Test that a readable event is raised when peer shutdown write. Also confirm read will return @@ -382,7 +382,7 @@ TEST_F(BufferedIoSocketHandleTest, TestShutDownRaiseEvent) { scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); bool should_close = false; - auto ev = io_handle_->createFileEvent( + io_handle_->initializeFileEvent( dispatcher_, [this, &should_close, handle = io_handle_.get(), &accumulator](uint32_t events) { if (events & Event::FileReadyType::Read) { @@ -411,7 +411,7 @@ TEST_F(BufferedIoSocketHandleTest, TestShutDownRaiseEvent) { ASSERT_FALSE(should_close); EXPECT_EQ(4, accumulator.size()); io_handle_->close(); - ev.reset(); + io_handle_->resetFileEvents(); } TEST_F(BufferedIoSocketHandleTest, TestRepeatedShutdownWR) { @@ -519,7 +519,7 @@ TEST_F(BufferedIoSocketHandleTest, TestWriteScheduleWritableEvent) { scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); bool should_close = false; - auto ev = io_handle_->createFileEvent( + io_handle_->initializeFileEvent( dispatcher_, [&should_close, handle = io_handle_.get(), &accumulator](uint32_t events) { if (events & Event::FileReadyType::Read) { @@ -559,7 +559,7 @@ TEST_F(BufferedIoSocketHandleTest, TestWritevScheduleWritableEvent) { scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); bool should_close = false; - auto ev = io_handle_->createFileEvent( + io_handle_->initializeFileEvent( dispatcher_, [&should_close, handle = io_handle_.get(), &accumulator](uint32_t events) { if (events & Event::FileReadyType::Read) { @@ -601,7 +601,7 @@ TEST_F(BufferedIoSocketHandleTest, TestReadAfterShutdownWrite) { scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); bool should_close = false; - auto ev = io_handle_peer_->createFileEvent( + io_handle_peer_->initializeFileEvent( dispatcher_, [&should_close, handle = io_handle_peer_.get(), &accumulator](uint32_t events) { if (events & Event::FileReadyType::Read) { @@ -635,7 +635,7 @@ TEST_F(BufferedIoSocketHandleTest, TestReadAfterShutdownWrite) { EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); io_handle_->close(); - ev.reset(); + io_handle_->resetFileEvents(); } TEST_F(BufferedIoSocketHandleTest, TestNotififyWritableAfterShutdownWrite) { @@ -650,7 +650,7 @@ TEST_F(BufferedIoSocketHandleTest, TestNotififyWritableAfterShutdownWrite) { scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); - auto ev = io_handle_->createFileEvent( + io_handle_->initializeFileEvent( dispatcher_, [&, handle = io_handle_.get()](uint32_t) {}, Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); scheduable_cb_->invokeCallback(); From 119a9cb2fdaed919b002d14b233651319a238582 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Wed, 28 Oct 2020 08:53:50 +0000 Subject: [PATCH 073/100] fix format Signed-off-by: Yuchen Dai --- source/common/event/user_space_file_event_impl.cc | 8 ++++---- source/common/version/BUILD | 6 +++--- test/common/event/user_space_file_event_impl_test.cc | 5 ++--- .../common/network/buffered_io_socket_handle_impl_test.cc | 2 +- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/source/common/event/user_space_file_event_impl.cc b/source/common/event/user_space_file_event_impl.cc index ae188d5c4ea3..f372273faf1f 100644 --- a/source/common/event/user_space_file_event_impl.cc +++ b/source/common/event/user_space_file_event_impl.cc @@ -41,10 +41,10 @@ void UserSpaceFileEventImpl::setEnabled(uint32_t events) { static_cast(this), events, was_enabled ? "not " : ""); } -UserSpaceFileEventImpl::UserSpaceFileEventImpl(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, uint32_t events) - : schedulable_( - dispatcher.createSchedulableCallback([this]() { onEvents(); }) - ), cb_([this, cb]() { +UserSpaceFileEventImpl::UserSpaceFileEventImpl(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, + uint32_t events) + : schedulable_(dispatcher.createSchedulableCallback([this]() { onEvents(); })), + cb_([this, cb]() { auto all_events = getEventListener().triggeredEvents(); auto ephemeral_events = getEventListener().getAndClearEphemeralEvents(); ENVOY_LOG(trace, diff --git a/source/common/version/BUILD b/source/common/version/BUILD index 9d726567378a..85f29b8ed9ed 100644 --- a/source/common/version/BUILD +++ b/source/common/version/BUILD @@ -14,7 +14,7 @@ genrule( name = "generate_version_number", srcs = ["//:VERSION"], outs = ["version_number.h"], - cmd = """echo "#define BUILD_VERSION_NUMBER \\"$$(cat $<)\\"" >$@""", + cmd = """echo "#define BUILD_VERSION_NUMBER \"$$(cat $<)\"" >$@""", visibility = ["//visibility:private"], ) @@ -50,8 +50,8 @@ envoy_cc_library( name = "version_lib", srcs = ["version.cc"], copts = envoy_select_boringssl( - ["-DENVOY_SSL_VERSION=\\\"BoringSSL-FIPS\\\""], - ["-DENVOY_SSL_VERSION=\\\"BoringSSL\\\""], + ["-DENVOY_SSL_VERSION=\"BoringSSL-FIPS\""], + ["-DENVOY_SSL_VERSION=\"BoringSSL\""], ), deps = [ ":version_includes", diff --git a/test/common/event/user_space_file_event_impl_test.cc b/test/common/event/user_space_file_event_impl_test.cc index 53914c9f3f19..6942b1e0b9da 100644 --- a/test/common/event/user_space_file_event_impl_test.cc +++ b/test/common/event/user_space_file_event_impl_test.cc @@ -26,8 +26,7 @@ class MockReadyCb { class UserSpaceFileEventImplTest : public testing::Test { public: UserSpaceFileEventImplTest() - : api_(Api::createApiForTest()), dispatcher_(api_->allocateDispatcher("test_thread")) { - } + : api_(Api::createApiForTest()), dispatcher_(api_->allocateDispatcher("test_thread")) {} protected: MockReadyCb ready_cb_; @@ -66,7 +65,7 @@ TEST_F(UserSpaceFileEventImplTest, TestRescheduleIsDeduplicated) { *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw); { SCOPED_TRACE("1st schedule"); - user_file_event_->activate(event_rw); + user_file_event_->activate(event_rw); user_file_event_->activate(event_rw); EXPECT_CALL(ready_cb_, called(event_rw)).Times(1); diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index 7bd72fde5671..801b0a599216 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -280,7 +280,7 @@ TEST_F(BufferedIoSocketHandleTest, TestEventResetClearCallback) { dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); ASSERT_TRUE(scheduable_cb_->enabled()); - + EXPECT_CALL(cb_, called(_)).Times(0); io_handle_->resetFileEvents(); } From f18fb59d5e9a5d124c1243bd26a638ee2b4b4cd6 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Wed, 28 Oct 2020 18:47:40 +0000 Subject: [PATCH 074/100] address comment: also add fails_on_windows to track Signed-off-by: Yuchen Dai --- .../event/user_space_file_event_impl.cc | 32 +++++------ .../common/event/user_space_file_event_impl.h | 13 +---- source/common/version/BUILD | 6 +- test/common/network/BUILD | 12 ++++ ...red_io_socket_handle_impl_platform_test.cc | 57 +++++++++++++++++++ .../buffered_io_socket_handle_impl_test.cc | 37 +++++++----- 6 files changed, 111 insertions(+), 46 deletions(-) create mode 100644 test/common/network/buffered_io_socket_handle_impl_platform_test.cc diff --git a/source/common/event/user_space_file_event_impl.cc b/source/common/event/user_space_file_event_impl.cc index f372273faf1f..5ddfc5a55b62 100644 --- a/source/common/event/user_space_file_event_impl.cc +++ b/source/common/event/user_space_file_event_impl.cc @@ -7,6 +7,20 @@ namespace Envoy { namespace Event { +UserSpaceFileEventImpl::UserSpaceFileEventImpl(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, + uint32_t events) + : schedulable_(dispatcher.createSchedulableCallback([this]() { onEvents(); })), + cb_([this, cb]() { + auto all_events = getEventListener().triggeredEvents(); + auto ephemeral_events = getEventListener().getAndClearEphemeralEvents(); + ENVOY_LOG(trace, + "User space event {} invokes callbacks on allevents = {}, ephermal events = {}", + static_cast(this), all_events, ephemeral_events); + cb(all_events | ephemeral_events); + }) { + setEnabled(events); +} + void EventListenerImpl::onEventEnabled(uint32_t enabled_events) { enabled_events_ = enabled_events; // Clear ephemeral events to align with FileEventImpl::setEnable(). @@ -24,9 +38,7 @@ void UserSpaceFileEventImpl::activate(uint32_t events) { // Only supported event types are set. ASSERT((events & (FileReadyType::Read | FileReadyType::Write | FileReadyType::Closed)) == events); event_listener_.onEventActivated(events); - if (!schedulable_->enabled()) { - schedulable_->scheduleCallbackNextIteration(); - } + schedulable_->scheduleCallbackNextIteration(); } void UserSpaceFileEventImpl::setEnabled(uint32_t events) { @@ -41,19 +53,5 @@ void UserSpaceFileEventImpl::setEnabled(uint32_t events) { static_cast(this), events, was_enabled ? "not " : ""); } -UserSpaceFileEventImpl::UserSpaceFileEventImpl(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, - uint32_t events) - : schedulable_(dispatcher.createSchedulableCallback([this]() { onEvents(); })), - cb_([this, cb]() { - auto all_events = getEventListener().triggeredEvents(); - auto ephemeral_events = getEventListener().getAndClearEphemeralEvents(); - ENVOY_LOG(trace, - "User space event {} invokes callbacks on allevents = {}, ephermal events = {}", - static_cast(this), all_events, ephemeral_events); - cb(all_events | ephemeral_events); - }) { - setEnabled(events); -} - } // namespace Event } // namespace Envoy \ No newline at end of file diff --git a/source/common/event/user_space_file_event_impl.h b/source/common/event/user_space_file_event_impl.h index 2cab56f53c1f..a75eede180f9 100644 --- a/source/common/event/user_space_file_event_impl.h +++ b/source/common/event/user_space_file_event_impl.h @@ -71,11 +71,7 @@ class UserSpaceFileEventImpl : public FileEvent, Logger::Loggableenabled()) { - schedulable_->cancel(); - } - } + ~UserSpaceFileEventImpl() override = default; // Event::FileEvent void activate(uint32_t events) override; @@ -84,13 +80,6 @@ class UserSpaceFileEventImpl : public FileEvent, Logger::Loggableenabled()) { - schedulable_->scheduleCallbackNextIteration(); - } - } - friend class Network::BufferedIoSocketHandleImpl; private: diff --git a/source/common/version/BUILD b/source/common/version/BUILD index 85f29b8ed9ed..9d726567378a 100644 --- a/source/common/version/BUILD +++ b/source/common/version/BUILD @@ -14,7 +14,7 @@ genrule( name = "generate_version_number", srcs = ["//:VERSION"], outs = ["version_number.h"], - cmd = """echo "#define BUILD_VERSION_NUMBER \"$$(cat $<)\"" >$@""", + cmd = """echo "#define BUILD_VERSION_NUMBER \\"$$(cat $<)\\"" >$@""", visibility = ["//visibility:private"], ) @@ -50,8 +50,8 @@ envoy_cc_library( name = "version_lib", srcs = ["version.cc"], copts = envoy_select_boringssl( - ["-DENVOY_SSL_VERSION=\"BoringSSL-FIPS\""], - ["-DENVOY_SSL_VERSION=\"BoringSSL\""], + ["-DENVOY_SSL_VERSION=\\\"BoringSSL-FIPS\\\""], + ["-DENVOY_SSL_VERSION=\\\"BoringSSL\\\""], ), deps = [ ":version_includes", diff --git a/test/common/network/BUILD b/test/common/network/BUILD index da5018861c43..7ccb038ed1cb 100644 --- a/test/common/network/BUILD +++ b/test/common/network/BUILD @@ -462,3 +462,15 @@ envoy_cc_test( "//test/mocks/event:event_mocks", ], ) + +envoy_cc_test( + name = "buffered_io_socket_handle_impl_platform_test", + srcs = ["buffered_io_socket_handle_impl_platform_test.cc"], + tags = ["fails_on_windows"], + deps = [ + "//source/common/common:utility_lib", + "//source/common/network:address_lib", + "//source/common/network:buffered_io_socket_handle_lib", + "//test/mocks/event:event_mocks", + ], +) diff --git a/test/common/network/buffered_io_socket_handle_impl_platform_test.cc b/test/common/network/buffered_io_socket_handle_impl_platform_test.cc new file mode 100644 index 000000000000..2614aab70873 --- /dev/null +++ b/test/common/network/buffered_io_socket_handle_impl_platform_test.cc @@ -0,0 +1,57 @@ +#include "envoy/common/platform.h" +#include "envoy/event/file_event.h" + +#include "common/network/buffered_io_socket_handle_impl.h" + +#include "test/mocks/event/mocks.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +namespace Envoy { +namespace Network { +namespace { + +using testing::NiceMock; + +class MockFileEventCallback { +public: + MOCK_METHOD(void, called, (uint32_t arg)); +}; + +// Explicitly mark the test failing on windows and will be fixed. +class BufferedIoSocketHandlePlatformTest : public testing::Test { +public: + BufferedIoSocketHandlePlatformTest() { + io_handle_ = std::make_unique(); + io_handle_peer_ = std::make_unique(); + io_handle_->setWritablePeer(io_handle_peer_.get()); + io_handle_peer_->setWritablePeer(io_handle_.get()); + } + + ~BufferedIoSocketHandlePlatformTest() override { + if (io_handle_->isOpen()) { + io_handle_->close(); + } + if (io_handle_peer_->isOpen()) { + io_handle_peer_->close(); + } + } + + std::unique_ptr io_handle_; + std::unique_ptr io_handle_peer_; + NiceMock dispatcher_; + MockFileEventCallback cb_; +}; + +TEST_F(BufferedIoSocketHandlePlatformTest, TestCreatePlatformDefaultTriggerTypeFailOnWindows) { + auto scheduable_cb = new NiceMock(&dispatcher_); + EXPECT_CALL(*scheduable_cb, scheduleCallbackNextIteration()); + io_handle_->initializeFileEvent( + dispatcher_, [this](uint32_t events) { cb_.called(events); }, + Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); +} + +} // namespace +} // namespace Network +} // namespace Envoy diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index 801b0a599216..aa7165b9e232 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -1,4 +1,3 @@ -#include "envoy/common/platform.h" #include "envoy/event/file_event.h" #include "common/buffer/buffer_impl.h" @@ -52,7 +51,7 @@ class BufferedIoSocketHandleTest : public testing::Test { EXPECT_EQ(Api::IoError::IoErrorCode::Again, result.err_->getErrorCode()); } - NiceMock dispatcher_{}; + NiceMock dispatcher_; // Owned by BufferedIoSocketHandle. NiceMock* scheduable_cb_; @@ -191,7 +190,7 @@ TEST_F(BufferedIoSocketHandleTest, EventScheduleBasic) { EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, - Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + Event::FileTriggerType::Edge, Event::FileReadyType::Read); EXPECT_CALL(cb_, called(_)); scheduable_cb_->invokeCallback(); @@ -203,7 +202,7 @@ TEST_F(BufferedIoSocketHandleTest, TestSetEnabledTriggerEventSchedule) { EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, - Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + Event::FileTriggerType::Edge, Event::FileReadyType::Read); ASSERT_TRUE(scheduable_cb_->enabled()); EXPECT_CALL(cb_, called(Event::FileReadyType::Read)); @@ -238,7 +237,7 @@ TEST_F(BufferedIoSocketHandleTest, TestReadAndWriteAreEdgeTriggered) { EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, - Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + Event::FileTriggerType::Edge, Event::FileReadyType::Read); EXPECT_CALL(cb_, called(_)); scheduable_cb_->invokeCallback(); @@ -262,7 +261,7 @@ TEST_F(BufferedIoSocketHandleTest, TestSetDisabledBlockEventSchedule) { EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, - Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + Event::FileTriggerType::Edge, Event::FileReadyType::Read); io_handle_->enableFileEvents(0); @@ -278,7 +277,7 @@ TEST_F(BufferedIoSocketHandleTest, TestEventResetClearCallback) { EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, - Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + Event::FileTriggerType::Edge, Event::FileReadyType::Read); ASSERT_TRUE(scheduable_cb_->enabled()); EXPECT_CALL(cb_, called(_)).Times(0); @@ -302,7 +301,7 @@ TEST_F(BufferedIoSocketHandleTest, TestDrainToLowWaterMarkTriggerReadEvent) { EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); io_handle_peer_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, - Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + Event::FileTriggerType::Edge, Event::FileReadyType::Read); ASSERT_TRUE(scheduable_cb_->enabled()); EXPECT_CALL(cb_, called(_)); scheduable_cb_->invokeCallback(); @@ -353,7 +352,7 @@ TEST_F(BufferedIoSocketHandleTest, TestClose) { } } }, - Event::PlatformDefaultTriggerType, Event::FileReadyType::Read | Event::FileReadyType::Write); + Event::FileTriggerType::Edge, Event::FileReadyType::Read | Event::FileReadyType::Write); scheduable_cb_->invokeCallback(); // Not closed yet. @@ -397,7 +396,7 @@ TEST_F(BufferedIoSocketHandleTest, TestShutDownRaiseEvent) { } } }, - Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + Event::FileTriggerType::Edge, Event::FileReadyType::Read); scheduable_cb_->invokeCallback(); // Not closed yet. @@ -537,7 +536,7 @@ TEST_F(BufferedIoSocketHandleTest, TestWriteScheduleWritableEvent) { } } }, - Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + Event::FileTriggerType::Edge, Event::FileReadyType::Read); scheduable_cb_->invokeCallback(); EXPECT_FALSE(scheduable_cb_->enabled()); @@ -577,7 +576,7 @@ TEST_F(BufferedIoSocketHandleTest, TestWritevScheduleWritableEvent) { } } }, - Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + Event::FileTriggerType::Edge, Event::FileReadyType::Read); scheduable_cb_->invokeCallback(); EXPECT_FALSE(scheduable_cb_->enabled()); @@ -619,7 +618,7 @@ TEST_F(BufferedIoSocketHandleTest, TestReadAfterShutdownWrite) { } } }, - Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + Event::FileTriggerType::Edge, Event::FileReadyType::Read); scheduable_cb_->invokeCallback(); EXPECT_FALSE(scheduable_cb_->enabled()); @@ -651,7 +650,7 @@ TEST_F(BufferedIoSocketHandleTest, TestNotififyWritableAfterShutdownWrite) { scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); io_handle_->initializeFileEvent( - dispatcher_, [&, handle = io_handle_.get()](uint32_t) {}, Event::PlatformDefaultTriggerType, + dispatcher_, [&, handle = io_handle_.get()](uint32_t) {}, Event::FileTriggerType::Edge, Event::FileReadyType::Read); scheduable_cb_->invokeCallback(); EXPECT_FALSE(scheduable_cb_->enabled()); @@ -681,6 +680,16 @@ TEST_F(BufferedIoSocketHandleTest, TestConnect) { EXPECT_EQ(0, io_handle_->connect(address_is_ignored).rc_); } +TEST_F(BufferedIoSocketHandleTest, TestDeathOnActivatingDestroyedEvents) { + io_handle_->resetFileEvents(); + ASSERT_DEBUG_DEATH(io_handle_->activateFileEvents(Event::FileReadyType::Read), "Null user_file_event_"); +} + +TEST_F(BufferedIoSocketHandleTest, TestDeathOnEnablingDestroyedEvents) { + io_handle_->resetFileEvents(); + ASSERT_DEBUG_DEATH(io_handle_->enableFileEvents(Event::FileReadyType::Read), "Null user_file_event_"); +} + class BufferedIoSocketHandleNotImplementedTest : public testing::Test { public: BufferedIoSocketHandleNotImplementedTest() { From b3e126495cfa196fed2a2339c8455f6dae55006c Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Wed, 28 Oct 2020 20:05:17 +0000 Subject: [PATCH 075/100] fix cc format Signed-off-by: Yuchen Dai --- .../buffered_io_socket_handle_impl_test.cc | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index aa7165b9e232..182e59872493 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -189,8 +189,8 @@ TEST_F(BufferedIoSocketHandleTest, EventScheduleBasic) { scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); io_handle_->initializeFileEvent( - dispatcher_, [this](uint32_t events) { cb_.called(events); }, - Event::FileTriggerType::Edge, Event::FileReadyType::Read); + dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::FileTriggerType::Edge, + Event::FileReadyType::Read); EXPECT_CALL(cb_, called(_)); scheduable_cb_->invokeCallback(); @@ -201,8 +201,8 @@ TEST_F(BufferedIoSocketHandleTest, TestSetEnabledTriggerEventSchedule) { scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); io_handle_->initializeFileEvent( - dispatcher_, [this](uint32_t events) { cb_.called(events); }, - Event::FileTriggerType::Edge, Event::FileReadyType::Read); + dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::FileTriggerType::Edge, + Event::FileReadyType::Read); ASSERT_TRUE(scheduable_cb_->enabled()); EXPECT_CALL(cb_, called(Event::FileReadyType::Read)); @@ -236,8 +236,8 @@ TEST_F(BufferedIoSocketHandleTest, TestReadAndWriteAreEdgeTriggered) { scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); io_handle_->initializeFileEvent( - dispatcher_, [this](uint32_t events) { cb_.called(events); }, - Event::FileTriggerType::Edge, Event::FileReadyType::Read); + dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::FileTriggerType::Edge, + Event::FileReadyType::Read); EXPECT_CALL(cb_, called(_)); scheduable_cb_->invokeCallback(); @@ -260,8 +260,8 @@ TEST_F(BufferedIoSocketHandleTest, TestSetDisabledBlockEventSchedule) { scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); io_handle_->initializeFileEvent( - dispatcher_, [this](uint32_t events) { cb_.called(events); }, - Event::FileTriggerType::Edge, Event::FileReadyType::Read); + dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::FileTriggerType::Edge, + Event::FileReadyType::Read); io_handle_->enableFileEvents(0); @@ -276,8 +276,8 @@ TEST_F(BufferedIoSocketHandleTest, TestEventResetClearCallback) { scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); io_handle_->initializeFileEvent( - dispatcher_, [this](uint32_t events) { cb_.called(events); }, - Event::FileTriggerType::Edge, Event::FileReadyType::Read); + dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::FileTriggerType::Edge, + Event::FileReadyType::Read); ASSERT_TRUE(scheduable_cb_->enabled()); EXPECT_CALL(cb_, called(_)).Times(0); @@ -300,8 +300,8 @@ TEST_F(BufferedIoSocketHandleTest, TestDrainToLowWaterMarkTriggerReadEvent) { scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); io_handle_peer_->initializeFileEvent( - dispatcher_, [this](uint32_t events) { cb_.called(events); }, - Event::FileTriggerType::Edge, Event::FileReadyType::Read); + dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::FileTriggerType::Edge, + Event::FileReadyType::Read); ASSERT_TRUE(scheduable_cb_->enabled()); EXPECT_CALL(cb_, called(_)); scheduable_cb_->invokeCallback(); @@ -682,12 +682,14 @@ TEST_F(BufferedIoSocketHandleTest, TestConnect) { TEST_F(BufferedIoSocketHandleTest, TestDeathOnActivatingDestroyedEvents) { io_handle_->resetFileEvents(); - ASSERT_DEBUG_DEATH(io_handle_->activateFileEvents(Event::FileReadyType::Read), "Null user_file_event_"); + ASSERT_DEBUG_DEATH(io_handle_->activateFileEvents(Event::FileReadyType::Read), + "Null user_file_event_"); } TEST_F(BufferedIoSocketHandleTest, TestDeathOnEnablingDestroyedEvents) { io_handle_->resetFileEvents(); - ASSERT_DEBUG_DEATH(io_handle_->enableFileEvents(Event::FileReadyType::Read), "Null user_file_event_"); + ASSERT_DEBUG_DEATH(io_handle_->enableFileEvents(Event::FileReadyType::Read), + "Null user_file_event_"); } class BufferedIoSocketHandleNotImplementedTest : public testing::Test { From 7fb8f79ff6b416cb6a2ddbbdabc2636444579d8e Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Wed, 28 Oct 2020 23:19:17 +0000 Subject: [PATCH 076/100] declare UserSpaceFileEventImpl final Signed-off-by: Yuchen Dai --- source/common/event/user_space_file_event_impl.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/common/event/user_space_file_event_impl.h b/source/common/event/user_space_file_event_impl.h index a75eede180f9..468b6be401a4 100644 --- a/source/common/event/user_space_file_event_impl.h +++ b/source/common/event/user_space_file_event_impl.h @@ -67,7 +67,8 @@ class EventListenerImpl : public EventListener { }; // A FileEvent implementation which is used to drive BufferedIoSocketHandle. -class UserSpaceFileEventImpl : public FileEvent, Logger::Loggable { +// Declare the class final to safely call virtual function setEnabled in constructor. +class UserSpaceFileEventImpl final : public FileEvent, Logger::Loggable { public: UserSpaceFileEventImpl(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, uint32_t events); From 1af28883a8abe6a3332e0b8661dddafed4905ee1 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 29 Oct 2020 01:46:26 +0000 Subject: [PATCH 077/100] remove onEvents Signed-off-by: Yuchen Dai --- source/common/event/user_space_file_event_impl.cc | 2 +- source/common/event/user_space_file_event_impl.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/source/common/event/user_space_file_event_impl.cc b/source/common/event/user_space_file_event_impl.cc index 5ddfc5a55b62..74662fbda7a1 100644 --- a/source/common/event/user_space_file_event_impl.cc +++ b/source/common/event/user_space_file_event_impl.cc @@ -9,7 +9,7 @@ namespace Event { UserSpaceFileEventImpl::UserSpaceFileEventImpl(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, uint32_t events) - : schedulable_(dispatcher.createSchedulableCallback([this]() { onEvents(); })), + : schedulable_(dispatcher.createSchedulableCallback([this]() { cb_(); })), cb_([this, cb]() { auto all_events = getEventListener().triggeredEvents(); auto ephemeral_events = getEventListener().getAndClearEphemeralEvents(); diff --git a/source/common/event/user_space_file_event_impl.h b/source/common/event/user_space_file_event_impl.h index 468b6be401a4..3ebeb5855337 100644 --- a/source/common/event/user_space_file_event_impl.h +++ b/source/common/event/user_space_file_event_impl.h @@ -79,7 +79,6 @@ class UserSpaceFileEventImpl final : public FileEvent, Logger::Loggable Date: Thu, 29 Oct 2020 04:30:38 +0000 Subject: [PATCH 078/100] fix user space event test Signed-off-by: Yuchen Dai --- source/common/event/BUILD | 1 + .../event/user_space_file_event_impl.cc | 26 +++-- .../common/event/user_space_file_event_impl.h | 11 +- .../network/buffered_io_socket_handle_impl.cc | 2 +- .../network/buffered_io_socket_handle_impl.h | 11 +- source/common/network/peer_buffer.h | 13 +++ test/common/event/BUILD | 1 + .../event/user_space_file_event_impl_test.cc | 102 ++++++++++++++---- 8 files changed, 132 insertions(+), 35 deletions(-) diff --git a/source/common/event/BUILD b/source/common/event/BUILD index 46404075ad0f..4633bb3887c7 100644 --- a/source/common/event/BUILD +++ b/source/common/event/BUILD @@ -83,6 +83,7 @@ envoy_cc_library( "//source/common/common:minimal_logger_lib", "//source/common/common:thread_lib", "//source/common/signal:fatal_error_handler_lib", + "//source/common/network:peer_buffer_lib", ] + select({ "//bazel:disable_signal_trace": [], "//conditions:default": [ diff --git a/source/common/event/user_space_file_event_impl.cc b/source/common/event/user_space_file_event_impl.cc index 74662fbda7a1..b12b35a53091 100644 --- a/source/common/event/user_space_file_event_impl.cc +++ b/source/common/event/user_space_file_event_impl.cc @@ -3,21 +3,22 @@ #include #include "common/common/assert.h" +#include "common/network/peer_buffer.h" namespace Envoy { namespace Event { UserSpaceFileEventImpl::UserSpaceFileEventImpl(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, - uint32_t events) - : schedulable_(dispatcher.createSchedulableCallback([this]() { cb_(); })), - cb_([this, cb]() { + uint32_t events, Network::ReadWritable& io_source) + : schedulable_(dispatcher.createSchedulableCallback([this]() { cb_(); })), cb_([this, cb]() { auto all_events = getEventListener().triggeredEvents(); auto ephemeral_events = getEventListener().getAndClearEphemeralEvents(); ENVOY_LOG(trace, "User space event {} invokes callbacks on allevents = {}, ephermal events = {}", static_cast(this), all_events, ephemeral_events); cb(all_events | ephemeral_events); - }) { + }), + io_source_(io_source) { setEnabled(events); } @@ -46,8 +47,21 @@ void UserSpaceFileEventImpl::setEnabled(uint32_t events) { ASSERT((events & (FileReadyType::Read | FileReadyType::Write | FileReadyType::Closed)) == events); event_listener_.onEventEnabled(events); bool was_enabled = schedulable_->enabled(); - if (!was_enabled) { - schedulable_->scheduleCallbackNextIteration(); + // if (!was_enabled) { + // schedulable_->scheduleCallbackNextIteration(); + // } + // Recalculate activated events. + uint32_t events_to_notify = 0; + if ((events & FileReadyType::Read) && io_source_.isReadable()) { + events_to_notify |= FileReadyType::Read; + } + if ((events & FileReadyType::Write) && io_source_.isPeerWritable()) { + events_to_notify |= FileReadyType::Write; + } + if (events_to_notify != 0) { + activate(events_to_notify); + } else { + schedulable_->cancel(); } ENVOY_LOG(trace, "User space file event {} set events {}. Will {} reschedule.", static_cast(this), events, was_enabled ? "not " : ""); diff --git a/source/common/event/user_space_file_event_impl.h b/source/common/event/user_space_file_event_impl.h index 3ebeb5855337..332adf25cff9 100644 --- a/source/common/event/user_space_file_event_impl.h +++ b/source/common/event/user_space_file_event_impl.h @@ -6,6 +6,7 @@ #include "common/event/dispatcher_impl.h" #include "common/event/event_impl_base.h" +#include "common/network/peer_buffer.h" namespace Envoy { @@ -52,7 +53,10 @@ class EventListenerImpl : public EventListener { // Return both read and write if enabled. Note that this implementation is inefficient. Read and // write events are supposed to be independent. - uint32_t triggeredEvents() override { return enabled_events_ & (~Event::FileReadyType::Closed); } + uint32_t triggeredEvents() override { + // return enabled_events_ & (~Event::FileReadyType::Closed); + return 0; + } void onEventEnabled(uint32_t enabled_events) override; void onEventActivated(uint32_t activated_events) override; @@ -70,7 +74,8 @@ class EventListenerImpl : public EventListener { // Declare the class final to safely call virtual function setEnabled in constructor. class UserSpaceFileEventImpl final : public FileEvent, Logger::Loggable { public: - UserSpaceFileEventImpl(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, uint32_t events); + UserSpaceFileEventImpl(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, uint32_t events, + Network::ReadWritable& io_source); ~UserSpaceFileEventImpl() override = default; @@ -92,6 +97,8 @@ class UserSpaceFileEventImpl final : public FileEvent, Logger::Loggable cb_; + + Network::ReadWritable& io_source_; }; } // namespace Event diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc index 6e47ab9fb543..00030b61ea1e 100644 --- a/source/common/network/buffered_io_socket_handle_impl.cc +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -259,7 +259,7 @@ void BufferedIoSocketHandleImpl::initializeFileEvent(Event::Dispatcher& dispatch ASSERT(user_file_event_ == nullptr, "Attempting to initialize two `file_event_` for the same " "file descriptor. This is not allowed."); ASSERT(trigger == Event::FileTriggerType::Edge, "Only support edge type."); - user_file_event_ = std::make_unique(dispatcher, cb, events); + user_file_event_ = std::make_unique(dispatcher, cb, events, *this); } IoHandlePtr BufferedIoSocketHandleImpl::duplicate() { // duplicate() is supposed to be used on listener io handle while this implementation doesn't diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/common/network/buffered_io_socket_handle_impl.h index b87b9baf04a4..f1e877005354 100644 --- a/source/common/network/buffered_io_socket_handle_impl.h +++ b/source/common/network/buffered_io_socket_handle_impl.h @@ -28,8 +28,7 @@ namespace Network { * BufferedIoSocketHandle mutates the state of peer handle and no lock is introduced. */ class BufferedIoSocketHandleImpl : public IoHandle, - public WritablePeer, - public ReadableSource, + public ReadWritable, protected Logger::Loggable { public: BufferedIoSocketHandleImpl(); @@ -92,7 +91,7 @@ class BufferedIoSocketHandleImpl : public IoHandle, void maybeSetNewData() override { ENVOY_LOG(trace, "{} on socket {}", __FUNCTION__, static_cast(this)); if (user_file_event_) { - user_file_event_->activate(Event::FileReadyType::Write); + user_file_event_->activate(Event::FileReadyType::Read); } } void onPeerDestroy() override { @@ -101,10 +100,14 @@ class BufferedIoSocketHandleImpl : public IoHandle, } void onPeerBufferWritable() override { if (user_file_event_) { - user_file_event_->activate(Event::FileReadyType::Read); + user_file_event_->activate(Event::FileReadyType::Write); } } bool isWritable() const override { return !isOverHighWatermark(); } + bool isPeerWritable() const override { + return writable_peer_ != nullptr && !writable_peer_->isWriteEndSet() && + writable_peer_->isWritable(); + } Buffer::Instance* getWriteBuffer() override { return &pending_received_data_; } // ReadableSource diff --git a/source/common/network/peer_buffer.h b/source/common/network/peer_buffer.h index 9c0db4ef9f7c..4cab47848fd2 100644 --- a/source/common/network/peer_buffer.h +++ b/source/common/network/peer_buffer.h @@ -40,6 +40,11 @@ class WritablePeer { */ virtual bool isWritable() const PURE; + /** + * @return true if peer is valid and writable. + */ + virtual bool isPeerWritable() const PURE; + /** * Raised by the peer when the peer switch from high water mark to low. */ @@ -61,5 +66,13 @@ class ReadableSource { virtual bool isOverHighWatermark() const PURE; virtual bool isReadable() const PURE; }; + +/** + * The interface as the union of ReadableSource and WritablePeer. + */ +class ReadWritable : public virtual ReadableSource, public virtual WritablePeer { +public: + virtual ~ReadWritable() = default; +}; } // namespace Network } // namespace Envoy \ No newline at end of file diff --git a/test/common/event/BUILD b/test/common/event/BUILD index 290f9f80865f..3095b3600a6b 100644 --- a/test/common/event/BUILD +++ b/test/common/event/BUILD @@ -49,6 +49,7 @@ envoy_cc_test( "//include/envoy/event:file_event_interface", "//source/common/event:dispatcher_includes", "//source/common/event:dispatcher_lib", + "//source/common/network:peer_buffer_lib", "//test/mocks:common_lib", "//test/test_common:environment_lib", "//test/test_common:test_runtime_lib", diff --git a/test/common/event/user_space_file_event_impl_test.cc b/test/common/event/user_space_file_event_impl_test.cc index 6942b1e0b9da..0d652ca23074 100644 --- a/test/common/event/user_space_file_event_impl_test.cc +++ b/test/common/event/user_space_file_event_impl_test.cc @@ -4,6 +4,7 @@ #include "common/event/dispatcher_impl.h" #include "common/event/user_space_file_event_impl.h" +#include "common/network/peer_buffer.h" #include "test/mocks/common.h" #include "test/test_common/environment.h" @@ -17,18 +18,39 @@ namespace Envoy { namespace Event { namespace { +using testing::NiceMock; +using testing::Return; + constexpr auto event_rw = Event::FileReadyType::Read | Event::FileReadyType::Write; class MockReadyCb { public: MOCK_METHOD(void, called, (uint32_t)); }; +class MockReadWritable : public Network::ReadWritable { +public: + MOCK_METHOD(void, setWriteEnd, ()); + MOCK_METHOD(bool, isWriteEndSet, ()); + MOCK_METHOD(void, onPeerDestroy, ()); + MOCK_METHOD(void, maybeSetNewData, ()); + MOCK_METHOD(Buffer::Instance*, getWriteBuffer, ()); + MOCK_METHOD(bool, isWritable, (), (const)); + MOCK_METHOD(bool, isPeerWritable, (), (const)); + MOCK_METHOD(void, onPeerBufferWritable, ()); + MOCK_METHOD(bool, isPeerShutDownWrite, (), (const)); + MOCK_METHOD(bool, isOverHighWatermark, (), (const)); + MOCK_METHOD(bool, isReadable, (), (const)); +}; class UserSpaceFileEventImplTest : public testing::Test { public: UserSpaceFileEventImplTest() : api_(Api::createApiForTest()), dispatcher_(api_->allocateDispatcher("test_thread")) {} + void setWritable() { EXPECT_CALL(io_source_, isPeerWritable()).WillRepeatedly(Return(true)); } + void setReadable() { EXPECT_CALL(io_source_, isReadable()).WillRepeatedly(Return(true)); } + protected: + NiceMock io_source_; MockReadyCb ready_cb_; Api::ApiPtr api_; DispatcherPtr dispatcher_; @@ -36,15 +58,16 @@ class UserSpaceFileEventImplTest : public testing::Test { }; TEST_F(UserSpaceFileEventImplTest, TestEnabledEventsTriggeredAfterCreate) { + setWritable(); user_file_event_ = std::make_unique( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw); - EXPECT_CALL(ready_cb_, called(event_rw)); + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); + EXPECT_CALL(ready_cb_, called(FileReadyType::Write)); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } TEST_F(UserSpaceFileEventImplTest, TestRescheduleAfterTriggered) { user_file_event_ = std::make_unique( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw); + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); { SCOPED_TRACE("1st schedule"); user_file_event_->activate(event_rw); @@ -62,7 +85,7 @@ TEST_F(UserSpaceFileEventImplTest, TestRescheduleAfterTriggered) { TEST_F(UserSpaceFileEventImplTest, TestRescheduleIsDeduplicated) { user_file_event_ = std::make_unique( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw); + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); { SCOPED_TRACE("1st schedule"); user_file_event_->activate(event_rw); @@ -80,42 +103,72 @@ TEST_F(UserSpaceFileEventImplTest, TestRescheduleIsDeduplicated) { } TEST_F(UserSpaceFileEventImplTest, TestDefaultReturnAllEnabledReadAndWriteEvents) { - std::vector events{Event::FileReadyType::Read, Event::FileReadyType::Write, event_rw}; - for (const auto& e : events) { - SCOPED_TRACE(absl::StrCat("current event:", e)); + { + auto current_event = Event::FileReadyType::Read; + SCOPED_TRACE(absl::StrCat("current event:", current_event)); + EXPECT_CALL(io_source_, isReadable()).WillOnce(Return(true)).RetiresOnSaturation(); + EXPECT_CALL(io_source_, isPeerWritable()).WillOnce(Return(false)).RetiresOnSaturation(); user_file_event_ = std::make_unique( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw); - user_file_event_->activate(e); - EXPECT_CALL(ready_cb_, called(event_rw)); + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); + // user_file_event_->activate(e); + EXPECT_CALL(ready_cb_, called(current_event)); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + user_file_event_.reset(); + } + + { + auto current_event = Event::FileReadyType::Write; + SCOPED_TRACE(absl::StrCat("current event:", current_event)); + EXPECT_CALL(io_source_, isReadable()).WillOnce(Return(false)).RetiresOnSaturation(); + EXPECT_CALL(io_source_, isPeerWritable()).WillOnce(Return(true)).RetiresOnSaturation(); + user_file_event_ = std::make_unique( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); + // user_file_event_->activate(e); + EXPECT_CALL(ready_cb_, called(current_event)); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + user_file_event_.reset(); + } + + { + auto current_event = event_rw; + SCOPED_TRACE(absl::StrCat("current event:", current_event)); + EXPECT_CALL(io_source_, isReadable()).WillOnce(Return(true)).RetiresOnSaturation(); + EXPECT_CALL(io_source_, isPeerWritable()).WillOnce(Return(true)).RetiresOnSaturation(); + user_file_event_ = std::make_unique( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); + // user_file_event_->activate(e); + EXPECT_CALL(ready_cb_, called(current_event)); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); user_file_event_.reset(); } } TEST_F(UserSpaceFileEventImplTest, TestActivateWillSchedule) { + // IO is neither readable nor writable. user_file_event_ = std::make_unique( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw); + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); { - EXPECT_CALL(ready_cb_, called(_)).Times(1); + EXPECT_CALL(ready_cb_, called(_)).Times(0); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } { user_file_event_->activate(Event::FileReadyType::Read); - EXPECT_CALL(ready_cb_, called(event_rw)).Times(1); + EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Read)).Times(1); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } { user_file_event_->activate(Event::FileReadyType::Write); - EXPECT_CALL(ready_cb_, called(event_rw)).Times(1); + EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Write)).Times(1); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } } TEST_F(UserSpaceFileEventImplTest, TestActivateDedup) { + // IO is neither readable nor writable. user_file_event_ = std::make_unique( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw); + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); { - EXPECT_CALL(ready_cb_, called(_)).Times(1); + EXPECT_CALL(ready_cb_, called(_)).Times(0); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } { @@ -133,16 +186,19 @@ TEST_F(UserSpaceFileEventImplTest, TestActivateDedup) { } TEST_F(UserSpaceFileEventImplTest, TestEnabledClearActivate) { + // IO is neither readable nor writable. user_file_event_ = std::make_unique( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw); + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); { - EXPECT_CALL(ready_cb_, called(_)).Times(1); + EXPECT_CALL(ready_cb_, called(_)).Times(0); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } + { + setWritable(); + setReadable(); user_file_event_->activate(Event::FileReadyType::Read); user_file_event_->setEnabled(Event::FileReadyType::Write); - EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Write)).Times(1); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } @@ -155,16 +211,18 @@ TEST_F(UserSpaceFileEventImplTest, TestEnabledClearActivate) { TEST_F(UserSpaceFileEventImplTest, TestEventClosedIsNotTriggeredUnlessManullyActivated) { user_file_event_ = std::make_unique( *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, - Event::FileReadyType::Write | Event::FileReadyType::Closed); + Event::FileReadyType::Write | Event::FileReadyType::Closed, io_source_); { // No Closed event bit if enabled by not activated. - EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Write)).Times(1); + EXPECT_CALL(ready_cb_, called(_)).Times(0); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } { + setWritable(); + setReadable(); user_file_event_->activate(Event::FileReadyType::Closed); // Activate could deliver Closed event bit. - EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Write | Event::FileReadyType::Closed)) + EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Closed)) .Times(1); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } From 6ca32cf24ae57b9185007b01a6a1967abc8ffdb7 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 29 Oct 2020 04:49:24 +0000 Subject: [PATCH 079/100] fix buffer io socket handle test Signed-off-by: Yuchen Dai --- .../event/user_space_file_event_impl.cc | 3 - .../common/event/user_space_file_event_impl.h | 8 +- .../event/user_space_file_event_impl_test.cc | 3 +- ...red_io_socket_handle_impl_platform_test.cc | 2 +- .../buffered_io_socket_handle_impl_test.cc | 121 +++++++++--------- 5 files changed, 66 insertions(+), 71 deletions(-) diff --git a/source/common/event/user_space_file_event_impl.cc b/source/common/event/user_space_file_event_impl.cc index b12b35a53091..d41dc060834b 100644 --- a/source/common/event/user_space_file_event_impl.cc +++ b/source/common/event/user_space_file_event_impl.cc @@ -47,9 +47,6 @@ void UserSpaceFileEventImpl::setEnabled(uint32_t events) { ASSERT((events & (FileReadyType::Read | FileReadyType::Write | FileReadyType::Closed)) == events); event_listener_.onEventEnabled(events); bool was_enabled = schedulable_->enabled(); - // if (!was_enabled) { - // schedulable_->scheduleCallbackNextIteration(); - // } // Recalculate activated events. uint32_t events_to_notify = 0; if ((events & FileReadyType::Read) && io_source_.isReadable()) { diff --git a/source/common/event/user_space_file_event_impl.h b/source/common/event/user_space_file_event_impl.h index 332adf25cff9..15b29b8424d7 100644 --- a/source/common/event/user_space_file_event_impl.h +++ b/source/common/event/user_space_file_event_impl.h @@ -51,12 +51,8 @@ class EventListenerImpl : public EventListener { public: ~EventListenerImpl() override = default; - // Return both read and write if enabled. Note that this implementation is inefficient. Read and - // write events are supposed to be independent. - uint32_t triggeredEvents() override { - // return enabled_events_ & (~Event::FileReadyType::Closed); - return 0; - } + // The ready events are not preserved. All ready events must be notified by activate(). + uint32_t triggeredEvents() override { return 0; } void onEventEnabled(uint32_t enabled_events) override; void onEventActivated(uint32_t activated_events) override; diff --git a/test/common/event/user_space_file_event_impl_test.cc b/test/common/event/user_space_file_event_impl_test.cc index 0d652ca23074..f4b9fe4c7b11 100644 --- a/test/common/event/user_space_file_event_impl_test.cc +++ b/test/common/event/user_space_file_event_impl_test.cc @@ -222,8 +222,7 @@ TEST_F(UserSpaceFileEventImplTest, TestEventClosedIsNotTriggeredUnlessManullyAct setReadable(); user_file_event_->activate(Event::FileReadyType::Closed); // Activate could deliver Closed event bit. - EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Closed)) - .Times(1); + EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Closed)).Times(1); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } { diff --git a/test/common/network/buffered_io_socket_handle_impl_platform_test.cc b/test/common/network/buffered_io_socket_handle_impl_platform_test.cc index 2614aab70873..c7044eacd1ac 100644 --- a/test/common/network/buffered_io_socket_handle_impl_platform_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_platform_test.cc @@ -46,7 +46,7 @@ class BufferedIoSocketHandlePlatformTest : public testing::Test { TEST_F(BufferedIoSocketHandlePlatformTest, TestCreatePlatformDefaultTriggerTypeFailOnWindows) { auto scheduable_cb = new NiceMock(&dispatcher_); - EXPECT_CALL(*scheduable_cb, scheduleCallbackNextIteration()); + EXPECT_CALL(*scheduable_cb, scheduleCallbackNextIteration()).Times(0); io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index 182e59872493..955759047193 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -190,7 +190,7 @@ TEST_F(BufferedIoSocketHandleTest, EventScheduleBasic) { EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::FileTriggerType::Edge, - Event::FileReadyType::Read); + Event::FileReadyType::Read | Event::FileReadyType::Write); EXPECT_CALL(cb_, called(_)); scheduable_cb_->invokeCallback(); @@ -199,37 +199,33 @@ TEST_F(BufferedIoSocketHandleTest, EventScheduleBasic) { TEST_F(BufferedIoSocketHandleTest, TestSetEnabledTriggerEventSchedule) { scheduable_cb_ = new NiceMock(&dispatcher_); - EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); - io_handle_->initializeFileEvent( - dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::FileTriggerType::Edge, - Event::FileReadyType::Read); - - ASSERT_TRUE(scheduable_cb_->enabled()); - EXPECT_CALL(cb_, called(Event::FileReadyType::Read)); - scheduable_cb_->invokeCallback(); - ASSERT_FALSE(scheduable_cb_->enabled()); - - EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); - io_handle_->enableFileEvents(Event::FileReadyType::Read); - ASSERT_TRUE(scheduable_cb_->enabled()); - EXPECT_CALL(cb_, called(_)); - scheduable_cb_->invokeCallback(); - ASSERT_FALSE(scheduable_cb_->enabled()); - EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); - io_handle_->enableFileEvents(Event::FileReadyType::Write); - ASSERT_TRUE(scheduable_cb_->enabled()); - EXPECT_CALL(cb_, called(Event::FileReadyType::Write)); - scheduable_cb_->invokeCallback(); - ASSERT_FALSE(scheduable_cb_->enabled()); - - EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); - io_handle_->enableFileEvents(Event::FileReadyType::Write | Event::FileReadyType::Read); - ASSERT_TRUE(scheduable_cb_->enabled()); - EXPECT_CALL(cb_, called(Event::FileReadyType::Write | Event::FileReadyType::Read)); - scheduable_cb_->invokeCallback(); - ASSERT_FALSE(scheduable_cb_->enabled()); - io_handle_->resetFileEvents(); + // No data is available to read. Will not schedule read. + { + SCOPED_TRACE("enable read but no readable."); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()).Times(0); + io_handle_->initializeFileEvent( + dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::FileTriggerType::Edge, + Event::FileReadyType::Read); + } + { + SCOPED_TRACE("enable readwrite but only writable."); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + io_handle_->enableFileEvents(Event::FileReadyType::Read | Event::FileReadyType::Write); + ASSERT_TRUE(scheduable_cb_->enabled()); + EXPECT_CALL(cb_, called(Event::FileReadyType::Write)); + scheduable_cb_->invokeCallback(); + ASSERT_FALSE(scheduable_cb_->enabled()); + } + { + SCOPED_TRACE("enable write and writable."); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + io_handle_->enableFileEvents(Event::FileReadyType::Write); + ASSERT_TRUE(scheduable_cb_->enabled()); + EXPECT_CALL(cb_, called(Event::FileReadyType::Write)); + scheduable_cb_->invokeCallback(); + ASSERT_FALSE(scheduable_cb_->enabled()); + } } TEST_F(BufferedIoSocketHandleTest, TestReadAndWriteAreEdgeTriggered) { @@ -237,12 +233,12 @@ TEST_F(BufferedIoSocketHandleTest, TestReadAndWriteAreEdgeTriggered) { EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::FileTriggerType::Edge, - Event::FileReadyType::Read); + Event::FileReadyType::Read | Event::FileReadyType::Write); - EXPECT_CALL(cb_, called(_)); + EXPECT_CALL(cb_, called(Event::FileReadyType::Write)); scheduable_cb_->invokeCallback(); - // Neither read and write will trigger self readiness. + // Neither read nor write triggers self readiness. EXPECT_CALL(cb_, called(_)).Times(0); // Drain 1 bytes. @@ -261,12 +257,11 @@ TEST_F(BufferedIoSocketHandleTest, TestSetDisabledBlockEventSchedule) { EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::FileTriggerType::Edge, - Event::FileReadyType::Read); - - io_handle_->enableFileEvents(0); + Event::FileReadyType::Write); + ASSERT_TRUE(scheduable_cb_->enabled()); - EXPECT_CALL(cb_, called(0)); - scheduable_cb_->invokeCallback(); + // The write event is cleared and the read event is not ready. + io_handle_->enableFileEvents(Event::FileReadyType::Read); ASSERT_FALSE(scheduable_cb_->enabled()); io_handle_->resetFileEvents(); @@ -277,7 +272,7 @@ TEST_F(BufferedIoSocketHandleTest, TestEventResetClearCallback) { EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::FileTriggerType::Edge, - Event::FileReadyType::Read); + Event::FileReadyType::Write); ASSERT_TRUE(scheduable_cb_->enabled()); EXPECT_CALL(cb_, called(_)).Times(0); @@ -296,15 +291,11 @@ TEST_F(BufferedIoSocketHandleTest, TestDrainToLowWaterMarkTriggerReadEvent) { EXPECT_TRUE(io_handle_->isReadable()); EXPECT_FALSE(handle_as_peer->isWritable()); - // Clear invoke callback on peer. scheduable_cb_ = new NiceMock(&dispatcher_); - EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); io_handle_peer_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::FileTriggerType::Edge, - Event::FileReadyType::Read); - ASSERT_TRUE(scheduable_cb_->enabled()); - EXPECT_CALL(cb_, called(_)); - scheduable_cb_->invokeCallback(); + Event::FileReadyType::Read | Event::FileReadyType::Write); + // Neither readable nor writable. ASSERT_FALSE(scheduable_cb_->enabled()); { @@ -334,14 +325,24 @@ TEST_F(BufferedIoSocketHandleTest, TestClose) { dispatcher_, [this, &should_close, handle = io_handle_.get(), &accumulator](uint32_t events) { if (events & Event::FileReadyType::Read) { - auto result = io_handle_->recv(buf_.data(), buf_.size(), 0); - if (result.ok()) { - accumulator += absl::string_view(buf_.data(), result.rc_); - } else if (result.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { - ENVOY_LOG_MISC(debug, "read returns EAGAIN"); - } else { - ENVOY_LOG_MISC(debug, "will close"); - should_close = true; + while (true) { + auto result = io_handle_->recv(buf_.data(), buf_.size(), 0); + if (result.ok()) { + // Read EOF. + if (result.rc_ == 0) { + should_close = true; + break; + } else { + accumulator += absl::string_view(buf_.data(), result.rc_); + } + } else if (result.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { + ENVOY_LOG_MISC(debug, "read returns EAGAIN"); + break; + } else { + ENVOY_LOG_MISC(debug, "will close"); + should_close = true; + break; + } } } if (events & Event::FileReadyType::Write) { @@ -536,7 +537,7 @@ TEST_F(BufferedIoSocketHandleTest, TestWriteScheduleWritableEvent) { } } }, - Event::FileTriggerType::Edge, Event::FileReadyType::Read); + Event::FileTriggerType::Edge, Event::FileReadyType::Read | Event::FileReadyType::Write); scheduable_cb_->invokeCallback(); EXPECT_FALSE(scheduable_cb_->enabled()); @@ -576,7 +577,7 @@ TEST_F(BufferedIoSocketHandleTest, TestWritevScheduleWritableEvent) { } } }, - Event::FileTriggerType::Edge, Event::FileReadyType::Read); + Event::FileTriggerType::Edge, Event::FileReadyType::Read | Event::FileReadyType::Write); scheduable_cb_->invokeCallback(); EXPECT_FALSE(scheduable_cb_->enabled()); @@ -598,7 +599,6 @@ TEST_F(BufferedIoSocketHandleTest, TestReadAfterShutdownWrite) { ENVOY_LOG_MISC(debug, "after {} shutdown write ", static_cast(io_handle_peer_.get())); std::string accumulator; scheduable_cb_ = new NiceMock(&dispatcher_); - EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); bool should_close = false; io_handle_peer_->initializeFileEvent( dispatcher_, @@ -609,7 +609,11 @@ TEST_F(BufferedIoSocketHandleTest, TestReadAfterShutdownWrite) { buf.reserve(1024, &slice, 1); auto result = handle->readv(1024, &slice, 1); if (result.ok()) { - accumulator += absl::string_view(static_cast(slice.mem_), result.rc_); + if (result.rc_ == 0) { + should_close = true; + } else { + accumulator += absl::string_view(static_cast(slice.mem_), result.rc_); + } } else if (result.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { ENVOY_LOG_MISC(debug, "read returns EAGAIN"); } else { @@ -619,7 +623,6 @@ TEST_F(BufferedIoSocketHandleTest, TestReadAfterShutdownWrite) { } }, Event::FileTriggerType::Edge, Event::FileReadyType::Read); - scheduable_cb_->invokeCallback(); EXPECT_FALSE(scheduable_cb_->enabled()); std::string raw_data("0123456789"); From fd7e7eaaa83927e14bcc92120f3c10c4d19c16f6 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 29 Oct 2020 16:51:26 +0000 Subject: [PATCH 080/100] clang tidy Signed-off-by: Yuchen Dai --- source/common/network/peer_buffer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/common/network/peer_buffer.h b/source/common/network/peer_buffer.h index 4cab47848fd2..9ce027a6eb21 100644 --- a/source/common/network/peer_buffer.h +++ b/source/common/network/peer_buffer.h @@ -72,7 +72,7 @@ class ReadableSource { */ class ReadWritable : public virtual ReadableSource, public virtual WritablePeer { public: - virtual ~ReadWritable() = default; + virtual ~ReadWritable() override = default; }; } // namespace Network } // namespace Envoy \ No newline at end of file From bd745ab739811b295609288781bf5ad959092edc Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 29 Oct 2020 20:27:38 +0000 Subject: [PATCH 081/100] clang tidy and test coverage Signed-off-by: Yuchen Dai --- source/common/network/peer_buffer.h | 2 +- .../buffered_io_socket_handle_impl_test.cc | 52 +++++++++++++++++-- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/source/common/network/peer_buffer.h b/source/common/network/peer_buffer.h index 9ce027a6eb21..2c4f8aafc25f 100644 --- a/source/common/network/peer_buffer.h +++ b/source/common/network/peer_buffer.h @@ -72,7 +72,7 @@ class ReadableSource { */ class ReadWritable : public virtual ReadableSource, public virtual WritablePeer { public: - virtual ~ReadWritable() override = default; + ~ReadWritable() override = default; }; } // namespace Network } // namespace Envoy \ No newline at end of file diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index 955759047193..b2c9fb4e3735 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -100,7 +100,7 @@ TEST_F(BufferedIoSocketHandleTest, TestBasicRecv) { EXPECT_TRUE(result.ok()); } -// Test recv side effects. +// Test read side effects. TEST_F(BufferedIoSocketHandleTest, TestReadEmpty) { Buffer::OwnedImpl buf; auto result = io_handle_->read(buf, 10); @@ -111,7 +111,7 @@ TEST_F(BufferedIoSocketHandleTest, TestReadEmpty) { EXPECT_TRUE(result.ok()); } -// Test recv side effects. +// Test read side effects. TEST_F(BufferedIoSocketHandleTest, TestReadContent) { Buffer::OwnedImpl buf; auto& internal_buffer = io_handle_->getBufferForTest(); @@ -128,6 +128,31 @@ TEST_F(BufferedIoSocketHandleTest, TestReadContent) { ASSERT_EQ(0, internal_buffer.length()); } +// Test readv behavior. +TEST_F(BufferedIoSocketHandleTest, TestBasicReadv) { + Buffer::OwnedImpl buf_to_write("abc"); + io_handle_peer_->write(buf_to_write); + + Buffer::OwnedImpl buf; + Buffer::RawSlice slice; + buf.reserve(1024, &slice, 1); + auto result = io_handle_->readv(1024, &slice, 1); + + EXPECT_TRUE(result.ok()); + EXPECT_EQ(3, result.rc_); + + result = io_handle_->readv(1024, &slice, 1); + + EXPECT_FALSE(result.ok()); + EXPECT_EQ(Api::IoError::IoErrorCode::Again, result.err_->getErrorCode()); + + io_handle_->setWriteEnd(); + result = io_handle_->readv(1024, &slice, 1); + // EOF + EXPECT_TRUE(result.ok()); + EXPECT_EQ(0, result.rc_); +} + // Test recv side effects. TEST_F(BufferedIoSocketHandleTest, TestBasicPeek) { auto result = io_handle_->recv(buf_.data(), buf_.size(), MSG_PEEK); @@ -416,7 +441,6 @@ TEST_F(BufferedIoSocketHandleTest, TestShutDownRaiseEvent) { TEST_F(BufferedIoSocketHandleTest, TestRepeatedShutdownWR) { EXPECT_EQ(io_handle_peer_->shutdown(ENVOY_SHUT_WR).rc_, 0); - ENVOY_LOG_MISC(debug, "lambdai: next shutdown"); EXPECT_EQ(io_handle_peer_->shutdown(ENVOY_SHUT_WR).rc_, 0); } @@ -683,6 +707,16 @@ TEST_F(BufferedIoSocketHandleTest, TestConnect) { EXPECT_EQ(0, io_handle_->connect(address_is_ignored).rc_); } +TEST_F(BufferedIoSocketHandleTest, TestActivateEvent) { + scheduable_cb_ = new NiceMock(&dispatcher_); + io_handle_->initializeFileEvent( + dispatcher_, [&, handle = io_handle_.get()](uint32_t) {}, Event::FileTriggerType::Edge, + Event::FileReadyType::Read); + EXPECT_FALSE(scheduable_cb_->enabled()); + io_handle_->activateFileEvents(Event::FileReadyType::Read); + ASSERT_TRUE(scheduable_cb_->enabled()); +} + TEST_F(BufferedIoSocketHandleTest, TestDeathOnActivatingDestroyedEvents) { io_handle_->resetFileEvents(); ASSERT_DEBUG_DEATH(io_handle_->activateFileEvents(Event::FileReadyType::Read), @@ -695,6 +729,18 @@ TEST_F(BufferedIoSocketHandleTest, TestDeathOnEnablingDestroyedEvents) { "Null user_file_event_"); } +TEST_F(BufferedIoSocketHandleTest, TestNotImplementDuplicate) { + ASSERT_DEATH(io_handle_->duplicate(), ""); +} + +TEST_F(BufferedIoSocketHandleTest, TestNotImplementAccept) { + ASSERT_DEATH(io_handle_->accept(nullptr, 0), ""); +} + +TEST_F(BufferedIoSocketHandleTest, TestLastRoundtripTimeNullOpt) { + ASSERT_EQ(absl::nullopt, io_handle_->lastRoundTripTime()); +} + class BufferedIoSocketHandleNotImplementedTest : public testing::Test { public: BufferedIoSocketHandleNotImplementedTest() { From 2e80156d45bedda0b368d195c52b30ffb062cff9 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Fri, 30 Oct 2020 05:39:28 +0000 Subject: [PATCH 082/100] ct Signed-off-by: Yuchen Dai --- test/common/network/buffered_io_socket_handle_impl_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index b2c9fb4e3735..2caabfee9f47 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -734,7 +734,7 @@ TEST_F(BufferedIoSocketHandleTest, TestNotImplementDuplicate) { } TEST_F(BufferedIoSocketHandleTest, TestNotImplementAccept) { - ASSERT_DEATH(io_handle_->accept(nullptr, 0), ""); + ASSERT_DEATH(io_handle_->accept(nullptr, nullptr), ""); } TEST_F(BufferedIoSocketHandleTest, TestLastRoundtripTimeNullOpt) { From 089526f28ad45449ec4761a2160d8ce22f77bf3d Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Fri, 30 Oct 2020 22:54:17 +0000 Subject: [PATCH 083/100] address comments Signed-off-by: Yuchen Dai --- .../event/user_space_file_event_impl.cc | 4 +-- .../common/event/user_space_file_event_impl.h | 2 -- .../network/buffered_io_socket_handle_impl.cc | 6 ++++ .../network/buffered_io_socket_handle_impl.h | 24 +++++++------- source/common/network/peer_buffer.h | 23 ++++++------- .../event/user_space_file_event_impl_test.cc | 1 - .../buffered_io_socket_handle_impl_test.cc | 33 +++++++++++-------- 7 files changed, 49 insertions(+), 44 deletions(-) diff --git a/source/common/event/user_space_file_event_impl.cc b/source/common/event/user_space_file_event_impl.cc index d41dc060834b..0d8da7966e79 100644 --- a/source/common/event/user_space_file_event_impl.cc +++ b/source/common/event/user_space_file_event_impl.cc @@ -11,8 +11,8 @@ namespace Event { UserSpaceFileEventImpl::UserSpaceFileEventImpl(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, uint32_t events, Network::ReadWritable& io_source) : schedulable_(dispatcher.createSchedulableCallback([this]() { cb_(); })), cb_([this, cb]() { - auto all_events = getEventListener().triggeredEvents(); - auto ephemeral_events = getEventListener().getAndClearEphemeralEvents(); + auto all_events = event_listener_.triggeredEvents(); + auto ephemeral_events = event_listener_.getAndClearEphemeralEvents(); ENVOY_LOG(trace, "User space event {} invokes callbacks on allevents = {}, ephermal events = {}", static_cast(this), all_events, ephemeral_events); diff --git a/source/common/event/user_space_file_event_impl.h b/source/common/event/user_space_file_event_impl.h index 15b29b8424d7..6ede629e7851 100644 --- a/source/common/event/user_space_file_event_impl.h +++ b/source/common/event/user_space_file_event_impl.h @@ -79,8 +79,6 @@ class UserSpaceFileEventImpl final : public FileEvent, Logger::Loggable void {}) {} +BufferedIoSocketHandleImpl::~BufferedIoSocketHandleImpl() { + if (!closed_) { + close(); + } +} + Api::IoCallUint64Result BufferedIoSocketHandleImpl::close() { ASSERT(!closed_); if (!closed_) { diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/common/network/buffered_io_socket_handle_impl.h index f1e877005354..259ea30107fd 100644 --- a/source/common/network/buffered_io_socket_handle_impl.h +++ b/source/common/network/buffered_io_socket_handle_impl.h @@ -33,7 +33,7 @@ class BufferedIoSocketHandleImpl : public IoHandle, public: BufferedIoSocketHandleImpl(); - ~BufferedIoSocketHandleImpl() override { ASSERT(closed_); } + ~BufferedIoSocketHandleImpl() override; // IoHandle os_fd_t fdDoNotUse() const override { return INVALID_SOCKET; } @@ -76,15 +76,6 @@ class BufferedIoSocketHandleImpl : public IoHandle, Api::SysCallIntResult shutdown(int how) override; absl::optional lastRoundTripTime() override { return absl::nullopt; } - Buffer::WatermarkBuffer& getBufferForTest() { return pending_received_data_; } - - void setWritablePeer(WritablePeer* writable_peer) { - // Swapping writable peer is undefined behavior. - ASSERT(!writable_peer_); - ASSERT(!write_shutdown_); - writable_peer_ = writable_peer; - } - // WritablePeer void setWriteEnd() override { read_end_stream_ = true; } bool isWriteEndSet() override { return read_end_stream_; } @@ -103,20 +94,27 @@ class BufferedIoSocketHandleImpl : public IoHandle, user_file_event_->activate(Event::FileReadyType::Write); } } - bool isWritable() const override { return !isOverHighWatermark(); } + bool isWritable() const override { return !over_high_watermark_; } bool isPeerWritable() const override { return writable_peer_ != nullptr && !writable_peer_->isWriteEndSet() && writable_peer_->isWritable(); } Buffer::Instance* getWriteBuffer() override { return &pending_received_data_; } - // ReadableSource + // ReadWritable bool isPeerShutDownWrite() const override { return read_end_stream_; } - bool isOverHighWatermark() const override { return over_high_watermark_; } bool isReadable() const override { return isPeerShutDownWrite() || pending_received_data_.length() > 0; } + // Set the peer which will populate the owned pending_received_data. + void setWritablePeer(WritablePeer* writable_peer) { + // Swapping writable peer is undefined behavior. + ASSERT(!writable_peer_); + ASSERT(!write_shutdown_); + writable_peer_ = writable_peer; + } + private: // Support isOpen() and close(). IoHandle owner must invoke close() to avoid potential resource // leak. diff --git a/source/common/network/peer_buffer.h b/source/common/network/peer_buffer.h index 2c4f8aafc25f..f42592daee93 100644 --- a/source/common/network/peer_buffer.h +++ b/source/common/network/peer_buffer.h @@ -17,6 +17,9 @@ class WritablePeer { * Set the flag to indicate no further write from peer. */ virtual void setWriteEnd() PURE; + /** + * @return true if the peer promise no more write. + */ virtual bool isWriteEndSet() PURE; /** @@ -52,27 +55,21 @@ class WritablePeer { }; /** - * The interface for the buffer owner who want to consume the buffer. + * The interface as the union of ReadableSource and WritablePeer. */ -class ReadableSource { +class ReadWritable : public WritablePeer { public: - virtual ~ReadableSource() = default; + ~ReadWritable() override = default; /** * Read the flag to indicate no further write. Used by early close detection. */ virtual bool isPeerShutDownWrite() const PURE; - virtual bool isOverHighWatermark() const PURE; + /** + * @return true if the pending receive buffer is not full. + */ virtual bool isReadable() const PURE; }; - -/** - * The interface as the union of ReadableSource and WritablePeer. - */ -class ReadWritable : public virtual ReadableSource, public virtual WritablePeer { -public: - ~ReadWritable() override = default; -}; } // namespace Network -} // namespace Envoy \ No newline at end of file +} // namespace Envoy diff --git a/test/common/event/user_space_file_event_impl_test.cc b/test/common/event/user_space_file_event_impl_test.cc index f4b9fe4c7b11..b9c350239111 100644 --- a/test/common/event/user_space_file_event_impl_test.cc +++ b/test/common/event/user_space_file_event_impl_test.cc @@ -38,7 +38,6 @@ class MockReadWritable : public Network::ReadWritable { MOCK_METHOD(bool, isPeerWritable, (), (const)); MOCK_METHOD(void, onPeerBufferWritable, ()); MOCK_METHOD(bool, isPeerShutDownWrite, (), (const)); - MOCK_METHOD(bool, isOverHighWatermark, (), (const)); MOCK_METHOD(bool, isReadable, (), (const)); }; class UserSpaceFileEventImplTest : public testing::Test { diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index 2caabfee9f47..4429a4ceb21e 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -51,6 +51,11 @@ class BufferedIoSocketHandleTest : public testing::Test { EXPECT_EQ(Api::IoError::IoErrorCode::Again, result.err_->getErrorCode()); } + Buffer::WatermarkBuffer& + getWatermarkBufferHelper(Network::BufferedIoSocketHandleImpl& io_handle) { + return dynamic_cast(*io_handle.getWriteBuffer()); + } + NiceMock dispatcher_; // Owned by BufferedIoSocketHandle. @@ -114,7 +119,7 @@ TEST_F(BufferedIoSocketHandleTest, TestReadEmpty) { // Test read side effects. TEST_F(BufferedIoSocketHandleTest, TestReadContent) { Buffer::OwnedImpl buf; - auto& internal_buffer = io_handle_->getBufferForTest(); + auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); internal_buffer.add("abcdefg"); auto result = io_handle_->read(buf, 3); EXPECT_TRUE(result.ok()); @@ -165,7 +170,7 @@ TEST_F(BufferedIoSocketHandleTest, TestBasicPeek) { } TEST_F(BufferedIoSocketHandleTest, TestRecvDrain) { - auto& internal_buffer = io_handle_->getBufferForTest(); + auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); internal_buffer.add("abcd"); auto result = io_handle_->recv(buf_.data(), buf_.size(), 0); EXPECT_TRUE(result.ok()); @@ -176,7 +181,7 @@ TEST_F(BufferedIoSocketHandleTest, TestRecvDrain) { } TEST_F(BufferedIoSocketHandleTest, FlowControl) { - auto& internal_buffer = io_handle_->getBufferForTest(); + auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); WritablePeer* handle_as_peer = io_handle_.get(); internal_buffer.setWatermarks(128); EXPECT_FALSE(io_handle_->isReadable()); @@ -267,7 +272,7 @@ TEST_F(BufferedIoSocketHandleTest, TestReadAndWriteAreEdgeTriggered) { EXPECT_CALL(cb_, called(_)).Times(0); // Drain 1 bytes. - auto& internal_buffer = io_handle_->getBufferForTest(); + auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); internal_buffer.add("abcd"); auto result = io_handle_->recv(buf_.data(), 1, 0); EXPECT_TRUE(result.ok()); @@ -305,7 +310,7 @@ TEST_F(BufferedIoSocketHandleTest, TestEventResetClearCallback) { } TEST_F(BufferedIoSocketHandleTest, TestDrainToLowWaterMarkTriggerReadEvent) { - auto& internal_buffer = io_handle_->getBufferForTest(); + auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); WritablePeer* handle_as_peer = io_handle_.get(); internal_buffer.setWatermarks(128); EXPECT_FALSE(io_handle_->isReadable()); @@ -340,7 +345,7 @@ TEST_F(BufferedIoSocketHandleTest, TestDrainToLowWaterMarkTriggerReadEvent) { } TEST_F(BufferedIoSocketHandleTest, TestClose) { - auto& internal_buffer = io_handle_->getBufferForTest(); + auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); internal_buffer.add("abcd"); std::string accumulator; scheduable_cb_ = new NiceMock(&dispatcher_); @@ -400,7 +405,7 @@ TEST_F(BufferedIoSocketHandleTest, TestClose) { // Test that a readable event is raised when peer shutdown write. Also confirm read will return // EAGAIN. TEST_F(BufferedIoSocketHandleTest, TestShutDownRaiseEvent) { - auto& internal_buffer = io_handle_->getBufferForTest(); + auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); internal_buffer.add("abcd"); std::string accumulator; @@ -451,8 +456,10 @@ TEST_F(BufferedIoSocketHandleTest, TestShutDownOptionsNotSupported) { TEST_F(BufferedIoSocketHandleTest, TestWriteByMove) { Buffer::OwnedImpl buf("0123456789"); - io_handle_peer_->write(buf); - auto& internal_buffer = io_handle_->getBufferForTest(); + auto result = io_handle_peer_->write(buf); + EXPECT_TRUE(result.ok()); + EXPECT_EQ(10, result.rc_); + auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); EXPECT_EQ("0123456789", internal_buffer.toString()); EXPECT_EQ(0, buf.length()); } @@ -464,7 +471,7 @@ TEST_F(BufferedIoSocketHandleTest, TestWriteErrorCode) { { // Populate write destination with massive data so as to not writable. - auto& internal_buffer = io_handle_peer_->getBufferForTest(); + auto& internal_buffer = getWatermarkBufferHelper(*io_handle_peer_); internal_buffer.setWatermarks(1024); internal_buffer.add(std::string(2048, ' ')); @@ -497,7 +504,7 @@ TEST_F(BufferedIoSocketHandleTest, TestWritevErrorCode) { { // Populate write destination with massive data so as to not writable. - auto& internal_buffer = io_handle_peer_->getBufferForTest(); + auto& internal_buffer = getWatermarkBufferHelper(*io_handle_peer_); internal_buffer.setWatermarks(1024); internal_buffer.add(std::string(2048, ' ')); result = io_handle_->writev(&slice, 1); @@ -533,7 +540,7 @@ TEST_F(BufferedIoSocketHandleTest, TestWritevToPeer) { Buffer::RawSlice{raw_data.data() + 1, 2}, }; io_handle_peer_->writev(slices.data(), slices.size()); - auto& internal_buffer = io_handle_->getBufferForTest(); + auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); EXPECT_EQ(3, internal_buffer.length()); EXPECT_EQ("012", internal_buffer.toString()); } @@ -665,7 +672,7 @@ TEST_F(BufferedIoSocketHandleTest, TestReadAfterShutdownWrite) { } TEST_F(BufferedIoSocketHandleTest, TestNotififyWritableAfterShutdownWrite) { - auto& peer_internal_buffer = io_handle_peer_->getBufferForTest(); + auto& peer_internal_buffer = getWatermarkBufferHelper(*io_handle_peer_); peer_internal_buffer.setWatermarks(128); std::string big_chunk(256, 'a'); peer_internal_buffer.add(big_chunk); From f203b6e93a422aace633680433176ed5e48c2f6c Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Fri, 30 Oct 2020 22:59:14 +0000 Subject: [PATCH 084/100] simplify test on new dtor Signed-off-by: Yuchen Dai --- .../network/buffered_io_socket_handle_impl_test.cc | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index 4429a4ceb21e..3b9472c799b7 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -36,14 +36,7 @@ class BufferedIoSocketHandleTest : public testing::Test { io_handle_peer_->setWritablePeer(io_handle_.get()); } - ~BufferedIoSocketHandleTest() override { - if (io_handle_->isOpen()) { - io_handle_->close(); - } - if (io_handle_peer_->isOpen()) { - io_handle_peer_->close(); - } - } + ~BufferedIoSocketHandleTest() override = default; void expectAgain() { auto result = io_handle_->recv(buf_.data(), buf_.size(), MSG_PEEK); @@ -255,6 +248,7 @@ TEST_F(BufferedIoSocketHandleTest, TestSetEnabledTriggerEventSchedule) { EXPECT_CALL(cb_, called(Event::FileReadyType::Write)); scheduable_cb_->invokeCallback(); ASSERT_FALSE(scheduable_cb_->enabled()); + io_handle_->close(); } } From 34b18ed2bbfa9ffb6f5335e7d671eedf8df85cf4 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Fri, 30 Oct 2020 23:39:42 +0000 Subject: [PATCH 085/100] erase triggered events Signed-off-by: Yuchen Dai --- source/common/event/user_space_file_event_impl.cc | 11 ++++------- source/common/event/user_space_file_event_impl.h | 7 ------- .../network/buffered_io_socket_handle_impl_test.cc | 2 ++ 3 files changed, 6 insertions(+), 14 deletions(-) diff --git a/source/common/event/user_space_file_event_impl.cc b/source/common/event/user_space_file_event_impl.cc index 0d8da7966e79..87c5c01576f6 100644 --- a/source/common/event/user_space_file_event_impl.cc +++ b/source/common/event/user_space_file_event_impl.cc @@ -11,19 +11,16 @@ namespace Event { UserSpaceFileEventImpl::UserSpaceFileEventImpl(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, uint32_t events, Network::ReadWritable& io_source) : schedulable_(dispatcher.createSchedulableCallback([this]() { cb_(); })), cb_([this, cb]() { - auto all_events = event_listener_.triggeredEvents(); auto ephemeral_events = event_listener_.getAndClearEphemeralEvents(); - ENVOY_LOG(trace, - "User space event {} invokes callbacks on allevents = {}, ephermal events = {}", - static_cast(this), all_events, ephemeral_events); - cb(all_events | ephemeral_events); + ENVOY_LOG(trace, "User space event {} invokes callbacks on events = {}", + static_cast(this), ephemeral_events); + cb(ephemeral_events); }), io_source_(io_source) { setEnabled(events); } -void EventListenerImpl::onEventEnabled(uint32_t enabled_events) { - enabled_events_ = enabled_events; +void EventListenerImpl::onEventEnabled(uint32_t) { // Clear ephemeral events to align with FileEventImpl::setEnable(). ephemeral_events_ = 0; } diff --git a/source/common/event/user_space_file_event_impl.h b/source/common/event/user_space_file_event_impl.h index 6ede629e7851..b79e538c1fef 100644 --- a/source/common/event/user_space_file_event_impl.h +++ b/source/common/event/user_space_file_event_impl.h @@ -23,8 +23,6 @@ class EventListener { public: virtual ~EventListener() = default; - // Get the events which are enabled and triggered. - virtual uint32_t triggeredEvents() PURE; // Get the events which are ephemerally activated. Upon returning the ephemeral events are // cleared. virtual uint32_t getAndClearEphemeralEvents() PURE; @@ -51,17 +49,12 @@ class EventListenerImpl : public EventListener { public: ~EventListenerImpl() override = default; - // The ready events are not preserved. All ready events must be notified by activate(). - uint32_t triggeredEvents() override { return 0; } - void onEventEnabled(uint32_t enabled_events) override; void onEventActivated(uint32_t activated_events) override; uint32_t getAndClearEphemeralEvents() override { return std::exchange(ephemeral_events_, 0); } private: - // The persisted interested events. The name on libevent document is pending event. - uint32_t enabled_events_{}; // The events set by activate() and will be cleared after the io callback. uint32_t ephemeral_events_{}; }; diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index 3b9472c799b7..153b735b91ec 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -248,7 +248,9 @@ TEST_F(BufferedIoSocketHandleTest, TestSetEnabledTriggerEventSchedule) { EXPECT_CALL(cb_, called(Event::FileReadyType::Write)); scheduable_cb_->invokeCallback(); ASSERT_FALSE(scheduable_cb_->enabled()); + // Close io_handle_ first to prevent events originated from peer close. io_handle_->close(); + io_handle_peer_->close(); } } From 83bd452a057eb2c8d2271e085b6d9339dbeba028 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Mon, 2 Nov 2020 08:26:16 +0000 Subject: [PATCH 086/100] final and remove EventListener interface Signed-off-by: Yuchen Dai --- .../common/event/user_space_file_event_impl.h | 36 ++++--------------- .../network/buffered_io_socket_handle_impl.h | 6 ++-- 2 files changed, 9 insertions(+), 33 deletions(-) diff --git a/source/common/event/user_space_file_event_impl.h b/source/common/event/user_space_file_event_impl.h index b79e538c1fef..2fc7a20ed65b 100644 --- a/source/common/event/user_space_file_event_impl.h +++ b/source/common/event/user_space_file_event_impl.h @@ -13,46 +13,22 @@ namespace Envoy { namespace Network { class BufferedIoSocketHandleImpl; } -namespace Event { -// The interface of populating event watcher and obtaining the active events. The events are the -// combination of FileReadyType values. The event listener is populated by user event registration -// and io events passively. Also the owner of this listener query the activated events by calling -// triggeredEvents and getAndClearEphemeralEvents. -class EventListener { -public: - virtual ~EventListener() = default; - - // Get the events which are ephemerally activated. Upon returning the ephemeral events are - // cleared. - virtual uint32_t getAndClearEphemeralEvents() PURE; - - /** - * FileEvent::setEnabled is invoked. - * @param enabled_events supplied the event of setEnabled. - */ - virtual void onEventEnabled(uint32_t enabled_events) PURE; - - /** - * FileEvent::activate is invoked. - * @param enabled_events supplied the event of activate(). - */ - virtual void onEventActivated(uint32_t activated_events) PURE; -}; +namespace Event { // Return the enabled events except EV_CLOSED. This implementation is generally good since only // epoll supports EV_CLOSED but the entire envoy code base supports another poller. The event owner // must assume EV_CLOSED is never activated. Also event owner must tolerate that OS could notify // events which are not actually triggered. // TODO(lambdai): Add support of delivering EV_CLOSED. -class EventListenerImpl : public EventListener { +class EventListenerImpl { public: - ~EventListenerImpl() override = default; + ~EventListenerImpl() = default; - void onEventEnabled(uint32_t enabled_events) override; - void onEventActivated(uint32_t activated_events) override; + void onEventEnabled(uint32_t enabled_events); + void onEventActivated(uint32_t activated_events); - uint32_t getAndClearEphemeralEvents() override { return std::exchange(ephemeral_events_, 0); } + uint32_t getAndClearEphemeralEvents() { return std::exchange(ephemeral_events_, 0); } private: // The events set by activate() and will be cleared after the io callback. diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/common/network/buffered_io_socket_handle_impl.h index 259ea30107fd..d26b9abfed22 100644 --- a/source/common/network/buffered_io_socket_handle_impl.h +++ b/source/common/network/buffered_io_socket_handle_impl.h @@ -27,9 +27,9 @@ namespace Network { * 4. The peer BufferedIoSocket must be scheduled in the same thread to avoid data race because * BufferedIoSocketHandle mutates the state of peer handle and no lock is introduced. */ -class BufferedIoSocketHandleImpl : public IoHandle, - public ReadWritable, - protected Logger::Loggable { +class BufferedIoSocketHandleImpl final : public IoHandle, + public ReadWritable, + protected Logger::Loggable { public: BufferedIoSocketHandleImpl(); From c98c4f9f86f709ae198a466ed2e8c52d77b41fe3 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Mon, 2 Nov 2020 08:54:47 +0000 Subject: [PATCH 087/100] move to test extensions Signed-off-by: Yuchen Dai --- source/common/event/BUILD | 2 - source/common/network/BUILD | 12 +---- source/extensions/io_socket/BUILD | 19 ++++++++ .../io_socket/buffered_io_socket/BUILD | 26 ++++++++++ .../buffered_io_socket_handle_impl.cc | 4 +- .../buffered_io_socket_handle_impl.h | 2 +- .../user_space_file_event_impl.cc | 2 +- .../user_space_file_event_impl.h | 0 .../extensions/io_socket/well_known_names.h | 34 +++++++++++++ test/common/event/BUILD | 15 ------ test/common/network/BUILD | 25 +--------- .../io_socket/buffered_io_socket/BUILD | 48 +++++++++++++++++++ ...red_io_socket_handle_impl_platform_test.cc | 2 +- .../buffered_io_socket_handle_impl_test.cc | 2 +- .../user_space_file_event_impl_test.cc | 2 +- 15 files changed, 136 insertions(+), 59 deletions(-) create mode 100644 source/extensions/io_socket/BUILD create mode 100644 source/extensions/io_socket/buffered_io_socket/BUILD rename source/{common/network => extensions/io_socket/buffered_io_socket}/buffered_io_socket_handle_impl.cc (98%) rename source/{common/network => extensions/io_socket/buffered_io_socket}/buffered_io_socket_handle_impl.h (98%) rename source/{common/event => extensions/io_socket/buffered_io_socket}/user_space_file_event_impl.cc (96%) rename source/{common/event => extensions/io_socket/buffered_io_socket}/user_space_file_event_impl.h (100%) create mode 100644 source/extensions/io_socket/well_known_names.h create mode 100644 test/extensions/io_socket/buffered_io_socket/BUILD rename test/{common/network => extensions/io_socket/buffered_io_socket}/buffered_io_socket_handle_impl_platform_test.cc (95%) rename test/{common/network => extensions/io_socket/buffered_io_socket}/buffered_io_socket_handle_impl_test.cc (99%) rename test/{common/event => extensions/io_socket/buffered_io_socket}/user_space_file_event_impl_test.cc (99%) diff --git a/source/common/event/BUILD b/source/common/event/BUILD index 4633bb3887c7..e931c2985ba8 100644 --- a/source/common/event/BUILD +++ b/source/common/event/BUILD @@ -14,7 +14,6 @@ envoy_cc_library( "dispatcher_impl.cc", "file_event_impl.cc", "signal_impl.cc", - "user_space_file_event_impl.cc", ], hdrs = [ "signal_impl.h", @@ -70,7 +69,6 @@ envoy_cc_library( "event_impl_base.h", "file_event_impl.h", "schedulable_cb_impl.h", - "user_space_file_event_impl.h", ], deps = [ ":libevent_lib", diff --git a/source/common/network/BUILD b/source/common/network/BUILD index 5f631932eb75..a2d0e26f0600 100644 --- a/source/common/network/BUILD +++ b/source/common/network/BUILD @@ -480,14 +480,4 @@ envoy_cc_library( "//source/common/buffer:watermark_buffer_lib", "//source/common/common:empty_string", ], -) - -envoy_cc_library( - name = "buffered_io_socket_handle_lib", - srcs = ["buffered_io_socket_handle_impl.cc"], - hdrs = ["buffered_io_socket_handle_impl.h"], - deps = [ - "default_socket_interface_lib", - ":peer_buffer_lib", - ], -) +) \ No newline at end of file diff --git a/source/extensions/io_socket/BUILD b/source/extensions/io_socket/BUILD new file mode 100644 index 000000000000..40a5e79b39d3 --- /dev/null +++ b/source/extensions/io_socket/BUILD @@ -0,0 +1,19 @@ +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_library", + "envoy_extension_package", +) + +licenses(["notice"]) # Apache 2 + +envoy_extension_package() + +envoy_cc_library( + name = "well_known_names", + hdrs = ["well_known_names.h"], + # well known names files are public as long as they exist. + visibility = ["//visibility:public"], + deps = [ + "//source/common/singleton:const_singleton", + ], +) diff --git a/source/extensions/io_socket/buffered_io_socket/BUILD b/source/extensions/io_socket/buffered_io_socket/BUILD new file mode 100644 index 000000000000..539f9f1d2247 --- /dev/null +++ b/source/extensions/io_socket/buffered_io_socket/BUILD @@ -0,0 +1,26 @@ +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_library", + "envoy_package", +) + +licenses(["notice"]) # Apache 2 + +envoy_package() + +envoy_cc_library( + name = "buffered_io_socket_handle_lib", + srcs = [ + "buffered_io_socket_handle_impl.cc", + "user_space_file_event_impl.cc", + ], + hdrs = [ + "buffered_io_socket_handle_impl.h", + "user_space_file_event_impl.h", + ], + deps = [ + "//source/common/network:default_socket_interface_lib", + "//source/common/event:dispatcher_includes", + "//source/common/network:peer_buffer_lib", + ], +) diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc similarity index 98% rename from source/common/network/buffered_io_socket_handle_impl.cc rename to source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc index 1c8cc4fd8892..0b1b8cf2bcdf 100644 --- a/source/common/network/buffered_io_socket_handle_impl.cc +++ b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc @@ -1,4 +1,4 @@ -#include "common/network/buffered_io_socket_handle_impl.h" +#include "extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h" #include "envoy/buffer/buffer.h" #include "envoy/common/platform.h" @@ -6,7 +6,7 @@ #include "common/api/os_sys_calls_impl.h" #include "common/common/assert.h" #include "common/common/utility.h" -#include "common/event/user_space_file_event_impl.h" +#include "extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h" #include "common/network/address_impl.h" #include "absl/container/fixed_array.h" diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h similarity index 98% rename from source/common/network/buffered_io_socket_handle_impl.h rename to source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h index d26b9abfed22..17b4c89f52ea 100644 --- a/source/common/network/buffered_io_socket_handle_impl.h +++ b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h @@ -10,7 +10,7 @@ #include "common/buffer/watermark_buffer.h" #include "common/common/logger.h" -#include "common/event/user_space_file_event_impl.h" +#include "extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h" #include "common/network/io_socket_error_impl.h" #include "common/network/peer_buffer.h" diff --git a/source/common/event/user_space_file_event_impl.cc b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc similarity index 96% rename from source/common/event/user_space_file_event_impl.cc rename to source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc index 87c5c01576f6..3499c2b90595 100644 --- a/source/common/event/user_space_file_event_impl.cc +++ b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc @@ -1,4 +1,4 @@ -#include "common/event/user_space_file_event_impl.h" +#include "extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h" #include diff --git a/source/common/event/user_space_file_event_impl.h b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h similarity index 100% rename from source/common/event/user_space_file_event_impl.h rename to source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h diff --git a/source/extensions/io_socket/well_known_names.h b/source/extensions/io_socket/well_known_names.h new file mode 100644 index 000000000000..86ab21d36be5 --- /dev/null +++ b/source/extensions/io_socket/well_known_names.h @@ -0,0 +1,34 @@ +#pragma once + +#include + +#include "common/singleton/const_singleton.h" + +namespace Envoy { +namespace Extensions { +namespace IoSocket { + +/** + * Well-known io socket names. + * NOTE: New io sockets should use the well known name: envoy.io_socket.name. + */ +class IoSocketNameValues { +public: + const std::string BufferedIoSocket = "envoy.io_socket.buffered_io_socket"; +}; + +using IoSocketNames = ConstSingleton; + +/** + * Well-known io socket names. + */ +class IoSocketShortNameValues { +public: + const std::string BufferedIoSocket = "buffered_io_socket"; +}; + +using IoSocketShortNameValues = ConstSingleton; + +} // namespace IoSocket +} // namespace Extensions +} // namespace Envoy diff --git a/test/common/event/BUILD b/test/common/event/BUILD index 3095b3600a6b..882d2afa9506 100644 --- a/test/common/event/BUILD +++ b/test/common/event/BUILD @@ -42,21 +42,6 @@ envoy_cc_test( ], ) -envoy_cc_test( - name = "user_space_file_event_impl_test", - srcs = ["user_space_file_event_impl_test.cc"], - deps = [ - "//include/envoy/event:file_event_interface", - "//source/common/event:dispatcher_includes", - "//source/common/event:dispatcher_lib", - "//source/common/network:peer_buffer_lib", - "//test/mocks:common_lib", - "//test/test_common:environment_lib", - "//test/test_common:test_runtime_lib", - "//test/test_common:utility_lib", - ], -) - envoy_cc_test( name = "scaled_range_timer_manager_impl_test", srcs = ["scaled_range_timer_manager_impl_test.cc"], diff --git a/test/common/network/BUILD b/test/common/network/BUILD index 7ccb038ed1cb..ceed3c112081 100644 --- a/test/common/network/BUILD +++ b/test/common/network/BUILD @@ -450,27 +450,4 @@ envoy_cc_test( "//source/common/network:filter_matcher_lib", "//test/mocks/network:network_mocks", ], -) - -envoy_cc_test( - name = "buffered_io_socket_handle_impl_test", - srcs = ["buffered_io_socket_handle_impl_test.cc"], - deps = [ - "//source/common/common:utility_lib", - "//source/common/network:address_lib", - "//source/common/network:buffered_io_socket_handle_lib", - "//test/mocks/event:event_mocks", - ], -) - -envoy_cc_test( - name = "buffered_io_socket_handle_impl_platform_test", - srcs = ["buffered_io_socket_handle_impl_platform_test.cc"], - tags = ["fails_on_windows"], - deps = [ - "//source/common/common:utility_lib", - "//source/common/network:address_lib", - "//source/common/network:buffered_io_socket_handle_lib", - "//test/mocks/event:event_mocks", - ], -) +) \ No newline at end of file diff --git a/test/extensions/io_socket/buffered_io_socket/BUILD b/test/extensions/io_socket/buffered_io_socket/BUILD new file mode 100644 index 000000000000..55b7b5d1e2df --- /dev/null +++ b/test/extensions/io_socket/buffered_io_socket/BUILD @@ -0,0 +1,48 @@ +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_test", + "envoy_package", +) + +licenses(["notice"]) # Apache 2 + +envoy_package() + +envoy_cc_test( + name = "buffered_io_socket_handle_impl_test", + srcs = ["buffered_io_socket_handle_impl_test.cc"], + deps = [ + "//source/common/common:utility_lib", + "//source/common/network:address_lib", + "//source/extensions/io_socket/buffered_io_socket:buffered_io_socket_handle_lib", + "//test/mocks/event:event_mocks", + ], +) + +envoy_cc_test( + name = "buffered_io_socket_handle_impl_platform_test", + srcs = ["buffered_io_socket_handle_impl_platform_test.cc"], + tags = ["fails_on_windows"], + deps = [ + "//source/common/common:utility_lib", + "//source/common/network:address_lib", + "//source/extensions/io_socket/buffered_io_socket:buffered_io_socket_handle_lib", + "//test/mocks/event:event_mocks", + ], +) + +envoy_cc_test( + name = "user_space_file_event_impl_test", + srcs = ["user_space_file_event_impl_test.cc"], + deps = [ + "//include/envoy/event:file_event_interface", + "//source/common/event:dispatcher_includes", + "//source/common/event:dispatcher_lib", + "//source/common/network:peer_buffer_lib", + "//source/extensions/io_socket/buffered_io_socket:buffered_io_socket_handle_lib", + "//test/mocks:common_lib", + "//test/test_common:environment_lib", + "//test/test_common:test_runtime_lib", + "//test/test_common:utility_lib", + ], +) diff --git a/test/common/network/buffered_io_socket_handle_impl_platform_test.cc b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_platform_test.cc similarity index 95% rename from test/common/network/buffered_io_socket_handle_impl_platform_test.cc rename to test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_platform_test.cc index c7044eacd1ac..7c56aaee43e5 100644 --- a/test/common/network/buffered_io_socket_handle_impl_platform_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_platform_test.cc @@ -1,7 +1,7 @@ #include "envoy/common/platform.h" #include "envoy/event/file_event.h" -#include "common/network/buffered_io_socket_handle_impl.h" +#include "extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h" #include "test/mocks/event/mocks.h" diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc similarity index 99% rename from test/common/network/buffered_io_socket_handle_impl_test.cc rename to test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc index 153b735b91ec..fdda535be873 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc @@ -2,7 +2,7 @@ #include "common/buffer/buffer_impl.h" #include "common/network/address_impl.h" -#include "common/network/buffered_io_socket_handle_impl.h" +#include "extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h" #include "test/mocks/event/mocks.h" diff --git a/test/common/event/user_space_file_event_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc similarity index 99% rename from test/common/event/user_space_file_event_impl_test.cc rename to test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc index b9c350239111..d4704ed861dc 100644 --- a/test/common/event/user_space_file_event_impl_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc @@ -3,7 +3,7 @@ #include "envoy/event/file_event.h" #include "common/event/dispatcher_impl.h" -#include "common/event/user_space_file_event_impl.h" +#include "extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h" #include "common/network/peer_buffer.h" #include "test/mocks/common.h" From 8d87a543d0348d2a4fddfea35c9ff003f83fef37 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Mon, 2 Nov 2020 09:15:14 +0000 Subject: [PATCH 088/100] ns Extensions::IoSocket::BufferedIoSocket Signed-off-by: Yuchen Dai --- .../io_socket/buffered_io_socket/BUILD | 2 +- .../buffered_io_socket_handle_impl.cc | 91 ++++++++++--------- .../buffered_io_socket_handle_impl.h | 56 +++++++----- .../user_space_file_event_impl.cc | 23 +++-- .../user_space_file_event_impl.h | 17 ++-- 5 files changed, 104 insertions(+), 85 deletions(-) diff --git a/source/extensions/io_socket/buffered_io_socket/BUILD b/source/extensions/io_socket/buffered_io_socket/BUILD index 539f9f1d2247..ff9a710ff569 100644 --- a/source/extensions/io_socket/buffered_io_socket/BUILD +++ b/source/extensions/io_socket/buffered_io_socket/BUILD @@ -19,8 +19,8 @@ envoy_cc_library( "user_space_file_event_impl.h", ], deps = [ - "//source/common/network:default_socket_interface_lib", "//source/common/event:dispatcher_includes", + "//source/common/network:default_socket_interface_lib", "//source/common/network:peer_buffer_lib", ], ) diff --git a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc index 0b1b8cf2bcdf..25668e00e012 100644 --- a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc +++ b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc @@ -13,8 +13,10 @@ #include "absl/types/optional.h" namespace Envoy { -namespace Network { +namespace Extensions { +namespace IoSocket { +namespace BufferedIoSocket { namespace { Api::SysCallIntResult makeInvalidSyscall() { return Api::SysCallIntResult{-1, SOCKET_ERROR_NOT_SUP}; @@ -70,15 +72,16 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::readv(uint64_t max_length, uint64_t num_slice) { if (!isOpen()) { return {0, - // TODO(lambdai): Add EBADF in IoSocketError and adopt it here. - Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; + // TODO(lambdai): Add EBADF in Network::IoSocketError and adopt it here. + Api::IoErrorPtr(new Network::IoSocketError(SOCKET_ERROR_INVAL), + Network::IoSocketError::deleteIoError)}; } if (pending_received_data_.length() == 0) { if (read_end_stream_) { return {0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } else { - return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), - IoSocketError::deleteIoError)}; + return {0, Api::IoErrorPtr(Network::IoSocketError::getIoSocketEagainInstance(), + Network::IoSocketError::deleteIoError)}; } } absl::FixedArray iov(num_slice); @@ -100,15 +103,15 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::readv(uint64_t max_length, Api::IoCallUint64Result BufferedIoSocketHandleImpl::read(Buffer::Instance& buffer, uint64_t max_length) { if (!isOpen()) { - return {0, - Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; + return {0, Api::IoErrorPtr(new Network::IoSocketError(SOCKET_ERROR_INVAL), + Network::IoSocketError::deleteIoError)}; } if (pending_received_data_.length() == 0) { if (read_end_stream_) { return {0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } else { - return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), - IoSocketError::deleteIoError)}; + return {0, Api::IoErrorPtr(Network::IoSocketError::getIoSocketEagainInstance(), + Network::IoSocketError::deleteIoError)}; } } // TODO(lambdai): Move at slice boundary to move to reduce the copy. @@ -120,24 +123,24 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::read(Buffer::Instance& buffe Api::IoCallUint64Result BufferedIoSocketHandleImpl::writev(const Buffer::RawSlice* slices, uint64_t num_slice) { if (!isOpen()) { - return {0, - Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; + return {0, Api::IoErrorPtr(new Network::IoSocketError(SOCKET_ERROR_INVAL), + Network::IoSocketError::deleteIoError)}; } // Closed peer. if (!writable_peer_) { - return {0, - Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; + return {0, Api::IoErrorPtr(new Network::IoSocketError(SOCKET_ERROR_INVAL), + Network::IoSocketError::deleteIoError)}; } // Error: write after close. if (writable_peer_->isWriteEndSet()) { // TODO(lambdai): EPIPE or ENOTCONN - return {0, - Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; + return {0, Api::IoErrorPtr(new Network::IoSocketError(SOCKET_ERROR_INVAL), + Network::IoSocketError::deleteIoError)}; } // The peer is valid but temporary not accepts new data. Likely due to flow control. if (!writable_peer_->isWritable()) { - return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), - IoSocketError::deleteIoError)}; + return {0, Api::IoErrorPtr(Network::IoSocketError::getIoSocketEagainInstance(), + Network::IoSocketError::deleteIoError)}; } // Write along with iteration. Buffer guarantee the fragment is always append-able. uint64_t bytes_written = 0; @@ -154,24 +157,24 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::writev(const Buffer::RawSlic Api::IoCallUint64Result BufferedIoSocketHandleImpl::write(Buffer::Instance& buffer) { if (!isOpen()) { - return {0, - Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; + return {0, Api::IoErrorPtr(new Network::IoSocketError(SOCKET_ERROR_INVAL), + Network::IoSocketError::deleteIoError)}; } // Closed peer. if (!writable_peer_) { - return {0, - Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; + return {0, Api::IoErrorPtr(new Network::IoSocketError(SOCKET_ERROR_INVAL), + Network::IoSocketError::deleteIoError)}; } // Error: write after close. if (writable_peer_->isWriteEndSet()) { // TODO(lambdai): EPIPE or ENOTCONN - return {0, - Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; + return {0, Api::IoErrorPtr(new Network::IoSocketError(SOCKET_ERROR_INVAL), + Network::IoSocketError::deleteIoError)}; } // The peer is valid but temporary not accepts new data. Likely due to flow control. if (!writable_peer_->isWritable()) { - return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), - IoSocketError::deleteIoError)}; + return {0, Api::IoErrorPtr(Network::IoSocketError::getIoSocketEagainInstance(), + Network::IoSocketError::deleteIoError)}; } uint64_t total_bytes_to_write = buffer.length(); writable_peer_->getWriteBuffer()->move(buffer); @@ -181,33 +184,33 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::write(Buffer::Instance& buff } Api::IoCallUint64Result BufferedIoSocketHandleImpl::sendmsg(const Buffer::RawSlice*, uint64_t, int, - const Address::Ip*, - const Address::Instance&) { - return IoSocketError::ioResultSocketInvalidAddress(); + const Network::Address::Ip*, + const Network::Address::Instance&) { + return Network::IoSocketError::ioResultSocketInvalidAddress(); } Api::IoCallUint64Result BufferedIoSocketHandleImpl::recvmsg(Buffer::RawSlice*, const uint64_t, uint32_t, RecvMsgOutput&) { - return IoSocketError::ioResultSocketInvalidAddress(); + return Network::IoSocketError::ioResultSocketInvalidAddress(); } Api::IoCallUint64Result BufferedIoSocketHandleImpl::recvmmsg(RawSliceArrays&, uint32_t, RecvMsgOutput&) { - return IoSocketError::ioResultSocketInvalidAddress(); + return Network::IoSocketError::ioResultSocketInvalidAddress(); } Api::IoCallUint64Result BufferedIoSocketHandleImpl::recv(void* buffer, size_t length, int flags) { if (!isOpen()) { - return {0, - Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; + return {0, Api::IoErrorPtr(new Network::IoSocketError(SOCKET_ERROR_INVAL), + Network::IoSocketError::deleteIoError)}; } // No data and the writer closed. if (pending_received_data_.length() == 0) { if (read_end_stream_) { return {0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } else { - return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), - IoSocketError::deleteIoError)}; + return {0, Api::IoErrorPtr(Network::IoSocketError::getIoSocketEagainInstance(), + Network::IoSocketError::deleteIoError)}; } } auto max_bytes_to_read = std::min(pending_received_data_.length(), length); @@ -222,17 +225,18 @@ bool BufferedIoSocketHandleImpl::supportsMmsg() const { return false; } bool BufferedIoSocketHandleImpl::supportsUdpGro() const { return false; } -Api::SysCallIntResult BufferedIoSocketHandleImpl::bind(Address::InstanceConstSharedPtr) { +Api::SysCallIntResult BufferedIoSocketHandleImpl::bind(Network::Address::InstanceConstSharedPtr) { return makeInvalidSyscall(); } Api::SysCallIntResult BufferedIoSocketHandleImpl::listen(int) { return makeInvalidSyscall(); } -IoHandlePtr BufferedIoSocketHandleImpl::accept(struct sockaddr*, socklen_t*) { +Network::IoHandlePtr BufferedIoSocketHandleImpl::accept(struct sockaddr*, socklen_t*) { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } -Api::SysCallIntResult BufferedIoSocketHandleImpl::connect(Address::InstanceConstSharedPtr) { +Api::SysCallIntResult +BufferedIoSocketHandleImpl::connect(Network::Address::InstanceConstSharedPtr) { // Buffered Io handle should always be considered as connected. // Use write or read to determine if peer is closed. return {0, 0}; @@ -250,11 +254,11 @@ Api::SysCallIntResult BufferedIoSocketHandleImpl::setBlocking(bool) { return mak absl::optional BufferedIoSocketHandleImpl::domain() { return absl::nullopt; } -Address::InstanceConstSharedPtr BufferedIoSocketHandleImpl::localAddress() { +Network::Address::InstanceConstSharedPtr BufferedIoSocketHandleImpl::localAddress() { throw EnvoyException(fmt::format("getsockname failed for BufferedIoSocketHandleImpl")); } -Address::InstanceConstSharedPtr BufferedIoSocketHandleImpl::peerAddress() { +Network::Address::InstanceConstSharedPtr BufferedIoSocketHandleImpl::peerAddress() { throw EnvoyException(fmt::format("getsockname failed for BufferedIoSocketHandleImpl")); } @@ -265,9 +269,10 @@ void BufferedIoSocketHandleImpl::initializeFileEvent(Event::Dispatcher& dispatch ASSERT(user_file_event_ == nullptr, "Attempting to initialize two `file_event_` for the same " "file descriptor. This is not allowed."); ASSERT(trigger == Event::FileTriggerType::Edge, "Only support edge type."); - user_file_event_ = std::make_unique(dispatcher, cb, events, *this); + user_file_event_ = std::make_unique(dispatcher, cb, events, *this); } -IoHandlePtr BufferedIoSocketHandleImpl::duplicate() { + +Network::IoHandlePtr BufferedIoSocketHandleImpl::duplicate() { // duplicate() is supposed to be used on listener io handle while this implementation doesn't // support listen. NOT_IMPLEMENTED_GCOVR_EXCL_LINE; @@ -304,5 +309,7 @@ Api::SysCallIntResult BufferedIoSocketHandleImpl::shutdown(int how) { } return {0, 0}; } -} // namespace Network +} // namespace BufferedIoSocket +} // namespace IoSocket +} // namespace Extensions } // namespace Envoy \ No newline at end of file diff --git a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h index 17b4c89f52ea..faadc0672f3c 100644 --- a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h +++ b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h @@ -15,11 +15,12 @@ #include "common/network/peer_buffer.h" namespace Envoy { -namespace Network { - +namespace Extensions { +namespace IoSocket { +namespace BufferedIoSocket { /** - * IoHandle implementation which provides a buffer as data source. It is designed to used by - * Network::ConnectionImpl. Some known limitations include + * Network::IoHandle implementation which provides a buffer as data source. It is designed to used + * by Network::ConnectionImpl. Some known limitations include * 1. It doesn't not include a file descriptor. Do not use "fdDoNotUse". * 2. It doesn't support socket options. Wrap this in ConnectionSocket and implement the socket * getter/setter options. @@ -27,15 +28,15 @@ namespace Network { * 4. The peer BufferedIoSocket must be scheduled in the same thread to avoid data race because * BufferedIoSocketHandle mutates the state of peer handle and no lock is introduced. */ -class BufferedIoSocketHandleImpl final : public IoHandle, - public ReadWritable, +class BufferedIoSocketHandleImpl final : public Network::IoHandle, + public Network::ReadWritable, protected Logger::Loggable { public: BufferedIoSocketHandleImpl(); ~BufferedIoSocketHandleImpl() override; - // IoHandle + // Network::IoHandle os_fd_t fdDoNotUse() const override { return INVALID_SOCKET; } Api::IoCallUint64Result close() override; bool isOpen() const override; @@ -45,8 +46,8 @@ class BufferedIoSocketHandleImpl final : public IoHandle, Api::IoCallUint64Result writev(const Buffer::RawSlice* slices, uint64_t num_slice) override; Api::IoCallUint64Result write(Buffer::Instance& buffer) override; Api::IoCallUint64Result sendmsg(const Buffer::RawSlice* slices, uint64_t num_slice, int flags, - const Address::Ip* self_ip, - const Address::Instance& peer_address) override; + const Network::Address::Ip* self_ip, + const Network::Address::Instance& peer_address) override; Api::IoCallUint64Result recvmsg(Buffer::RawSlice* slices, const uint64_t num_slice, uint32_t self_port, RecvMsgOutput& output) override; Api::IoCallUint64Result recvmmsg(RawSliceArrays& slices, uint32_t self_port, @@ -54,21 +55,21 @@ class BufferedIoSocketHandleImpl final : public IoHandle, Api::IoCallUint64Result recv(void* buffer, size_t length, int flags) override; bool supportsMmsg() const override; bool supportsUdpGro() const override; - Api::SysCallIntResult bind(Address::InstanceConstSharedPtr address) override; + Api::SysCallIntResult bind(Network::Address::InstanceConstSharedPtr address) override; Api::SysCallIntResult listen(int backlog) override; - IoHandlePtr accept(struct sockaddr* addr, socklen_t* addrlen) override; - Api::SysCallIntResult connect(Address::InstanceConstSharedPtr address) override; + Network::IoHandlePtr accept(struct sockaddr* addr, socklen_t* addrlen) override; + Api::SysCallIntResult connect(Network::Address::InstanceConstSharedPtr address) override; Api::SysCallIntResult setOption(int level, int optname, const void* optval, socklen_t optlen) override; Api::SysCallIntResult getOption(int level, int optname, void* optval, socklen_t* optlen) override; Api::SysCallIntResult setBlocking(bool blocking) override; absl::optional domain() override; - Address::InstanceConstSharedPtr localAddress() override; - Address::InstanceConstSharedPtr peerAddress() override; + Network::Address::InstanceConstSharedPtr localAddress() override; + Network::Address::InstanceConstSharedPtr peerAddress() override; void initializeFileEvent(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, Event::FileTriggerType trigger, uint32_t events) override; - IoHandlePtr duplicate() override; + Network::IoHandlePtr duplicate() override; void activateFileEvents(uint32_t events) override; void enableFileEvents(uint32_t events) override; void resetFileEvents() override; @@ -76,7 +77,7 @@ class BufferedIoSocketHandleImpl final : public IoHandle, Api::SysCallIntResult shutdown(int how) override; absl::optional lastRoundTripTime() override { return absl::nullopt; } - // WritablePeer + // Network::WritablePeer void setWriteEnd() override { read_end_stream_ = true; } bool isWriteEndSet() override { return read_end_stream_; } void maybeSetNewData() override { @@ -101,14 +102,14 @@ class BufferedIoSocketHandleImpl final : public IoHandle, } Buffer::Instance* getWriteBuffer() override { return &pending_received_data_; } - // ReadWritable + // Network::ReadWritable bool isPeerShutDownWrite() const override { return read_end_stream_; } bool isReadable() const override { return isPeerShutDownWrite() || pending_received_data_.length() > 0; } // Set the peer which will populate the owned pending_received_data. - void setWritablePeer(WritablePeer* writable_peer) { + void setWritablePeer(Network::WritablePeer* writable_peer) { // Swapping writable peer is undefined behavior. ASSERT(!writable_peer_); ASSERT(!write_shutdown_); @@ -116,28 +117,33 @@ class BufferedIoSocketHandleImpl final : public IoHandle, } private: - // Support isOpen() and close(). IoHandle owner must invoke close() to avoid potential resource - // leak. + // Support isOpen() and close(). Network::IoHandle owner must invoke close() to avoid potential + // resource leak. bool closed_{false}; // The attached file event with this socket. The event is not owned by the socket in the current // Envoy model. Multiple events can be created during the life time of this IO handle but at any // moment at most 1 event is attached. - std::unique_ptr user_file_event_; + std::unique_ptr user_file_event_; // True if pending_received_data_ is not addable. Note that pending_received_data_ may have // pending data to drain. bool read_end_stream_{false}; + + // The buffer owned by this socket. This buffer is populated by the write operations of the peer + // socket and drained by read operations of this socket. Buffer::WatermarkBuffer pending_received_data_; - // Destination of the write(). - WritablePeer* writable_peer_{nullptr}; + // Destination of the write(). The value remains non-null until the peer is closed. + Network::WritablePeer* writable_peer_{nullptr}; // The flag whether the peer is valid. Any write attempt must check this flag. bool write_shutdown_{false}; + // The watermark state of pending_received_data_. bool over_high_watermark_{false}; }; - -} // namespace Network +} // namespace BufferedIoSocket +} // namespace IoSocket +} // namespace Extensions } // namespace Envoy \ No newline at end of file diff --git a/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc index 3499c2b90595..03b08ed489f1 100644 --- a/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc +++ b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc @@ -6,7 +6,9 @@ #include "common/network/peer_buffer.h" namespace Envoy { -namespace Event { +namespace Extensions { +namespace IoSocket { +namespace BufferedIoSocket { UserSpaceFileEventImpl::UserSpaceFileEventImpl(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, uint32_t events, Network::ReadWritable& io_source) @@ -34,23 +36,25 @@ void EventListenerImpl::onEventActivated(uint32_t activated_events) { void UserSpaceFileEventImpl::activate(uint32_t events) { // Only supported event types are set. - ASSERT((events & (FileReadyType::Read | FileReadyType::Write | FileReadyType::Closed)) == events); + ASSERT((events & (Event::FileReadyType::Read | Event::FileReadyType::Write | + Event::FileReadyType::Closed)) == events); event_listener_.onEventActivated(events); schedulable_->scheduleCallbackNextIteration(); } void UserSpaceFileEventImpl::setEnabled(uint32_t events) { // Only supported event types are set. - ASSERT((events & (FileReadyType::Read | FileReadyType::Write | FileReadyType::Closed)) == events); + ASSERT((events & (Event::FileReadyType::Read | Event::FileReadyType::Write | + Event::FileReadyType::Closed)) == events); event_listener_.onEventEnabled(events); bool was_enabled = schedulable_->enabled(); // Recalculate activated events. uint32_t events_to_notify = 0; - if ((events & FileReadyType::Read) && io_source_.isReadable()) { - events_to_notify |= FileReadyType::Read; + if ((events & Event::FileReadyType::Read) && io_source_.isReadable()) { + events_to_notify |= Event::FileReadyType::Read; } - if ((events & FileReadyType::Write) && io_source_.isPeerWritable()) { - events_to_notify |= FileReadyType::Write; + if ((events & Event::FileReadyType::Write) && io_source_.isPeerWritable()) { + events_to_notify |= Event::FileReadyType::Write; } if (events_to_notify != 0) { activate(events_to_notify); @@ -60,6 +64,7 @@ void UserSpaceFileEventImpl::setEnabled(uint32_t events) { ENVOY_LOG(trace, "User space file event {} set events {}. Will {} reschedule.", static_cast(this), events, was_enabled ? "not " : ""); } - -} // namespace Event +} // namespace BufferedIoSocket +} // namespace IoSocket +} // namespace Extensions } // namespace Envoy \ No newline at end of file diff --git a/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h index 2fc7a20ed65b..0ad34ca1ff94 100644 --- a/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h +++ b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h @@ -10,11 +10,11 @@ namespace Envoy { -namespace Network { -class BufferedIoSocketHandleImpl; -} +namespace Extensions { +namespace IoSocket { +namespace BufferedIoSocket { -namespace Event { +class BufferedIoSocketHandleImpl; // Return the enabled events except EV_CLOSED. This implementation is generally good since only // epoll supports EV_CLOSED but the entire envoy code base supports another poller. The event owner @@ -37,7 +37,7 @@ class EventListenerImpl { // A FileEvent implementation which is used to drive BufferedIoSocketHandle. // Declare the class final to safely call virtual function setEnabled in constructor. -class UserSpaceFileEventImpl final : public FileEvent, Logger::Loggable { +class UserSpaceFileEventImpl final : public Event::FileEvent, Logger::Loggable { public: UserSpaceFileEventImpl(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, uint32_t events, Network::ReadWritable& io_source); @@ -48,7 +48,7 @@ class UserSpaceFileEventImpl final : public FileEvent, Logger::Loggable Date: Mon, 2 Nov 2020 09:24:18 +0000 Subject: [PATCH 089/100] test: ns Extensions::IoSocket::BufferedIoSocket Signed-off-by: Yuchen Dai --- ...red_io_socket_handle_impl_platform_test.cc | 16 +++++---- .../buffered_io_socket_handle_impl_test.cc | 30 +++++++++------- .../user_space_file_event_impl_test.cc | 34 +++++++++++-------- 3 files changed, 46 insertions(+), 34 deletions(-) diff --git a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_platform_test.cc b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_platform_test.cc index 7c56aaee43e5..3fee0d4b1378 100644 --- a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_platform_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_platform_test.cc @@ -9,7 +9,9 @@ #include "gtest/gtest.h" namespace Envoy { -namespace Network { +namespace Extensions { +namespace IoSocket { +namespace BufferedIoSocket { namespace { using testing::NiceMock; @@ -23,8 +25,8 @@ class MockFileEventCallback { class BufferedIoSocketHandlePlatformTest : public testing::Test { public: BufferedIoSocketHandlePlatformTest() { - io_handle_ = std::make_unique(); - io_handle_peer_ = std::make_unique(); + io_handle_ = std::make_unique(); + io_handle_peer_ = std::make_unique(); io_handle_->setWritablePeer(io_handle_peer_.get()); io_handle_peer_->setWritablePeer(io_handle_.get()); } @@ -38,8 +40,8 @@ class BufferedIoSocketHandlePlatformTest : public testing::Test { } } - std::unique_ptr io_handle_; - std::unique_ptr io_handle_peer_; + std::unique_ptr io_handle_; + std::unique_ptr io_handle_peer_; NiceMock dispatcher_; MockFileEventCallback cb_; }; @@ -53,5 +55,7 @@ TEST_F(BufferedIoSocketHandlePlatformTest, TestCreatePlatformDefaultTriggerTypeF } } // namespace -} // namespace Network +} // namespace BufferedIoSocket +} // namespace IoSocket +} // namespace Extensions } // namespace Envoy diff --git a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc index fdda535be873..f099222bcf1e 100644 --- a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc @@ -14,7 +14,9 @@ using testing::_; using testing::NiceMock; namespace Envoy { -namespace Network { +namespace Extensions { +namespace IoSocket { +namespace BufferedIoSocket { namespace { MATCHER(IsInvalidateAddress, "") { @@ -30,8 +32,8 @@ class MockFileEventCallback { class BufferedIoSocketHandleTest : public testing::Test { public: BufferedIoSocketHandleTest() : buf_(1024) { - io_handle_ = std::make_unique(); - io_handle_peer_ = std::make_unique(); + io_handle_ = std::make_unique(); + io_handle_peer_ = std::make_unique(); io_handle_->setWritablePeer(io_handle_peer_.get()); io_handle_peer_->setWritablePeer(io_handle_.get()); } @@ -45,7 +47,7 @@ class BufferedIoSocketHandleTest : public testing::Test { } Buffer::WatermarkBuffer& - getWatermarkBufferHelper(Network::BufferedIoSocketHandleImpl& io_handle) { + getWatermarkBufferHelper(BufferedIoSocketHandleImpl& io_handle) { return dynamic_cast(*io_handle.getWriteBuffer()); } @@ -54,8 +56,8 @@ class BufferedIoSocketHandleTest : public testing::Test { // Owned by BufferedIoSocketHandle. NiceMock* scheduable_cb_; MockFileEventCallback cb_; - std::unique_ptr io_handle_; - std::unique_ptr io_handle_peer_; + std::unique_ptr io_handle_; + std::unique_ptr io_handle_peer_; absl::FixedArray buf_; }; @@ -175,7 +177,7 @@ TEST_F(BufferedIoSocketHandleTest, TestRecvDrain) { TEST_F(BufferedIoSocketHandleTest, FlowControl) { auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); - WritablePeer* handle_as_peer = io_handle_.get(); + Network::WritablePeer* handle_as_peer = io_handle_.get(); internal_buffer.setWatermarks(128); EXPECT_FALSE(io_handle_->isReadable()); EXPECT_TRUE(io_handle_peer_->isWritable()); @@ -307,7 +309,7 @@ TEST_F(BufferedIoSocketHandleTest, TestEventResetClearCallback) { TEST_F(BufferedIoSocketHandleTest, TestDrainToLowWaterMarkTriggerReadEvent) { auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); - WritablePeer* handle_as_peer = io_handle_.get(); + Network::WritablePeer* handle_as_peer = io_handle_.get(); internal_buffer.setWatermarks(128); EXPECT_FALSE(io_handle_->isReadable()); EXPECT_TRUE(io_handle_peer_->isWritable()); @@ -747,8 +749,8 @@ TEST_F(BufferedIoSocketHandleTest, TestLastRoundtripTimeNullOpt) { class BufferedIoSocketHandleNotImplementedTest : public testing::Test { public: BufferedIoSocketHandleNotImplementedTest() { - io_handle_ = std::make_unique(); - io_handle_peer_ = std::make_unique(); + io_handle_ = std::make_unique(); + io_handle_peer_ = std::make_unique(); io_handle_->setWritablePeer(io_handle_peer_.get()); io_handle_peer_->setWritablePeer(io_handle_.get()); } @@ -762,8 +764,8 @@ class BufferedIoSocketHandleNotImplementedTest : public testing::Test { } } - std::unique_ptr io_handle_; - std::unique_ptr io_handle_peer_; + std::unique_ptr io_handle_; + std::unique_ptr io_handle_peer_; Buffer::RawSlice slice_; }; @@ -813,5 +815,7 @@ TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnGetOption) { EXPECT_THAT(io_handle_->getOption(0, 0, nullptr, nullptr), IsNotSupportedResult()); } } // namespace -} // namespace Network +} // namespace BufferedIoSocket +} // namespace IoSocket +} // namespace Extensions } // namespace Envoy diff --git a/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc index d4704ed861dc..8285e254473b 100644 --- a/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc @@ -15,7 +15,9 @@ #include "gtest/gtest.h" namespace Envoy { -namespace Event { +namespace Extensions { +namespace IoSocket { +namespace BufferedIoSocket { namespace { using testing::NiceMock; @@ -52,20 +54,20 @@ class UserSpaceFileEventImplTest : public testing::Test { NiceMock io_source_; MockReadyCb ready_cb_; Api::ApiPtr api_; - DispatcherPtr dispatcher_; - std::unique_ptr user_file_event_; + Event::DispatcherPtr dispatcher_; + std::unique_ptr user_file_event_; }; TEST_F(UserSpaceFileEventImplTest, TestEnabledEventsTriggeredAfterCreate) { setWritable(); - user_file_event_ = std::make_unique( + user_file_event_ = std::make_unique( *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); - EXPECT_CALL(ready_cb_, called(FileReadyType::Write)); + EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Write)); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } TEST_F(UserSpaceFileEventImplTest, TestRescheduleAfterTriggered) { - user_file_event_ = std::make_unique( + user_file_event_ = std::make_unique( *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); { SCOPED_TRACE("1st schedule"); @@ -83,7 +85,7 @@ TEST_F(UserSpaceFileEventImplTest, TestRescheduleAfterTriggered) { } TEST_F(UserSpaceFileEventImplTest, TestRescheduleIsDeduplicated) { - user_file_event_ = std::make_unique( + user_file_event_ = std::make_unique( *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); { SCOPED_TRACE("1st schedule"); @@ -107,7 +109,7 @@ TEST_F(UserSpaceFileEventImplTest, TestDefaultReturnAllEnabledReadAndWriteEvents SCOPED_TRACE(absl::StrCat("current event:", current_event)); EXPECT_CALL(io_source_, isReadable()).WillOnce(Return(true)).RetiresOnSaturation(); EXPECT_CALL(io_source_, isPeerWritable()).WillOnce(Return(false)).RetiresOnSaturation(); - user_file_event_ = std::make_unique( + user_file_event_ = std::make_unique( *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); // user_file_event_->activate(e); EXPECT_CALL(ready_cb_, called(current_event)); @@ -120,7 +122,7 @@ TEST_F(UserSpaceFileEventImplTest, TestDefaultReturnAllEnabledReadAndWriteEvents SCOPED_TRACE(absl::StrCat("current event:", current_event)); EXPECT_CALL(io_source_, isReadable()).WillOnce(Return(false)).RetiresOnSaturation(); EXPECT_CALL(io_source_, isPeerWritable()).WillOnce(Return(true)).RetiresOnSaturation(); - user_file_event_ = std::make_unique( + user_file_event_ = std::make_unique( *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); // user_file_event_->activate(e); EXPECT_CALL(ready_cb_, called(current_event)); @@ -133,7 +135,7 @@ TEST_F(UserSpaceFileEventImplTest, TestDefaultReturnAllEnabledReadAndWriteEvents SCOPED_TRACE(absl::StrCat("current event:", current_event)); EXPECT_CALL(io_source_, isReadable()).WillOnce(Return(true)).RetiresOnSaturation(); EXPECT_CALL(io_source_, isPeerWritable()).WillOnce(Return(true)).RetiresOnSaturation(); - user_file_event_ = std::make_unique( + user_file_event_ = std::make_unique( *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); // user_file_event_->activate(e); EXPECT_CALL(ready_cb_, called(current_event)); @@ -144,7 +146,7 @@ TEST_F(UserSpaceFileEventImplTest, TestDefaultReturnAllEnabledReadAndWriteEvents TEST_F(UserSpaceFileEventImplTest, TestActivateWillSchedule) { // IO is neither readable nor writable. - user_file_event_ = std::make_unique( + user_file_event_ = std::make_unique( *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); { EXPECT_CALL(ready_cb_, called(_)).Times(0); @@ -164,7 +166,7 @@ TEST_F(UserSpaceFileEventImplTest, TestActivateWillSchedule) { TEST_F(UserSpaceFileEventImplTest, TestActivateDedup) { // IO is neither readable nor writable. - user_file_event_ = std::make_unique( + user_file_event_ = std::make_unique( *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); { EXPECT_CALL(ready_cb_, called(_)).Times(0); @@ -186,7 +188,7 @@ TEST_F(UserSpaceFileEventImplTest, TestActivateDedup) { TEST_F(UserSpaceFileEventImplTest, TestEnabledClearActivate) { // IO is neither readable nor writable. - user_file_event_ = std::make_unique( + user_file_event_ = std::make_unique( *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); { EXPECT_CALL(ready_cb_, called(_)).Times(0); @@ -208,7 +210,7 @@ TEST_F(UserSpaceFileEventImplTest, TestEnabledClearActivate) { } TEST_F(UserSpaceFileEventImplTest, TestEventClosedIsNotTriggeredUnlessManullyActivated) { - user_file_event_ = std::make_unique( + user_file_event_ = std::make_unique( *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileReadyType::Write | Event::FileReadyType::Closed, io_source_); { @@ -231,5 +233,7 @@ TEST_F(UserSpaceFileEventImplTest, TestEventClosedIsNotTriggeredUnlessManullyAct } } // namespace -} // namespace Event +} // namespace BufferedIoSocket +} // namespace IoSocket +} // namespace Extensions } // namespace Envoy \ No newline at end of file From f780926e81553edb9a0f82239f6dc964bffc7e83 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Mon, 2 Nov 2020 09:32:56 +0000 Subject: [PATCH 090/100] codeformat and owners Signed-off-by: Yuchen Dai --- CODEOWNERS | 2 ++ source/common/network/BUILD | 2 +- source/extensions/io_socket/buffered_io_socket/BUILD | 4 ++-- .../buffered_io_socket/buffered_io_socket_handle_impl.cc | 3 ++- .../buffered_io_socket/buffered_io_socket_handle_impl.h | 3 ++- test/common/network/BUILD | 2 +- .../buffered_io_socket/buffered_io_socket_handle_impl_test.cc | 4 ++-- .../buffered_io_socket/user_space_file_event_impl_test.cc | 3 ++- 8 files changed, 14 insertions(+), 9 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 66d902367b36..2e4731444c02 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -152,3 +152,5 @@ extensions/filters/http/oauth2 @rgs1 @derekargueta @snowp # HTTP Local Rate Limit /*/extensions/filters/http/local_ratelimit @rgs1 @mattklein123 /*/extensions/filters/common/local_ratelimit @mattklein123 @rgs1 +# user space socket pair and event +/*/extensions/io_socket/buffered_io_socket @lambdai @antoniovicente \ No newline at end of file diff --git a/source/common/network/BUILD b/source/common/network/BUILD index a2d0e26f0600..d9a6e7717671 100644 --- a/source/common/network/BUILD +++ b/source/common/network/BUILD @@ -480,4 +480,4 @@ envoy_cc_library( "//source/common/buffer:watermark_buffer_lib", "//source/common/common:empty_string", ], -) \ No newline at end of file +) diff --git a/source/extensions/io_socket/buffered_io_socket/BUILD b/source/extensions/io_socket/buffered_io_socket/BUILD index ff9a710ff569..5046e7a2f10c 100644 --- a/source/extensions/io_socket/buffered_io_socket/BUILD +++ b/source/extensions/io_socket/buffered_io_socket/BUILD @@ -1,12 +1,12 @@ load( "//bazel:envoy_build_system.bzl", "envoy_cc_library", - "envoy_package", + "envoy_extension_package", ) licenses(["notice"]) # Apache 2 -envoy_package() +envoy_extension_package() envoy_cc_library( name = "buffered_io_socket_handle_lib", diff --git a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc index 25668e00e012..5cf5bad161bc 100644 --- a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc +++ b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc @@ -6,9 +6,10 @@ #include "common/api/os_sys_calls_impl.h" #include "common/common/assert.h" #include "common/common/utility.h" -#include "extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h" #include "common/network/address_impl.h" +#include "extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h" + #include "absl/container/fixed_array.h" #include "absl/types/optional.h" diff --git a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h index faadc0672f3c..2dea13134fc3 100644 --- a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h +++ b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h @@ -10,10 +10,11 @@ #include "common/buffer/watermark_buffer.h" #include "common/common/logger.h" -#include "extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h" #include "common/network/io_socket_error_impl.h" #include "common/network/peer_buffer.h" +#include "extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h" + namespace Envoy { namespace Extensions { namespace IoSocket { diff --git a/test/common/network/BUILD b/test/common/network/BUILD index ceed3c112081..e92b72c35af0 100644 --- a/test/common/network/BUILD +++ b/test/common/network/BUILD @@ -450,4 +450,4 @@ envoy_cc_test( "//source/common/network:filter_matcher_lib", "//test/mocks/network:network_mocks", ], -) \ No newline at end of file +) diff --git a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc index f099222bcf1e..7a738911d7c9 100644 --- a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc @@ -2,6 +2,7 @@ #include "common/buffer/buffer_impl.h" #include "common/network/address_impl.h" + #include "extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h" #include "test/mocks/event/mocks.h" @@ -46,8 +47,7 @@ class BufferedIoSocketHandleTest : public testing::Test { EXPECT_EQ(Api::IoError::IoErrorCode::Again, result.err_->getErrorCode()); } - Buffer::WatermarkBuffer& - getWatermarkBufferHelper(BufferedIoSocketHandleImpl& io_handle) { + Buffer::WatermarkBuffer& getWatermarkBufferHelper(BufferedIoSocketHandleImpl& io_handle) { return dynamic_cast(*io_handle.getWriteBuffer()); } diff --git a/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc index 8285e254473b..690d8653aa42 100644 --- a/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc @@ -3,9 +3,10 @@ #include "envoy/event/file_event.h" #include "common/event/dispatcher_impl.h" -#include "extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h" #include "common/network/peer_buffer.h" +#include "extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h" + #include "test/mocks/common.h" #include "test/test_common/environment.h" #include "test/test_common/test_runtime.h" From aefff6a825341cde7b74b1f6ab660f7851a6abcf Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Mon, 2 Nov 2020 19:41:02 +0000 Subject: [PATCH 091/100] moving peer buffer to extension Signed-off-by: Yuchen Dai --- source/common/event/BUILD | 1 - source/common/event/file_event_impl.h | 2 +- source/common/network/BUILD | 10 ---------- source/common/network/io_socket_error_impl.h | 2 +- source/extensions/io_socket/buffered_io_socket/BUILD | 12 +++++++++++- .../buffered_io_socket_handle_impl.h | 12 ++++++------ .../io_socket/buffered_io_socket}/peer_buffer.h | 8 ++++++-- .../buffered_io_socket/user_space_file_event_impl.cc | 5 +++-- .../buffered_io_socket/user_space_file_event_impl.h | 7 ++++--- test/common/network/BUILD | 4 ++-- test/extensions/io_socket/buffered_io_socket/BUILD | 2 +- .../buffered_io_socket_handle_impl_test.cc | 4 ++-- .../user_space_file_event_impl_test.cc | 4 ++-- 13 files changed, 39 insertions(+), 34 deletions(-) rename source/{common/network => extensions/io_socket/buffered_io_socket}/peer_buffer.h (91%) diff --git a/source/common/event/BUILD b/source/common/event/BUILD index e931c2985ba8..5e538bc52cf6 100644 --- a/source/common/event/BUILD +++ b/source/common/event/BUILD @@ -81,7 +81,6 @@ envoy_cc_library( "//source/common/common:minimal_logger_lib", "//source/common/common:thread_lib", "//source/common/signal:fatal_error_handler_lib", - "//source/common/network:peer_buffer_lib", ] + select({ "//bazel:disable_signal_trace": [], "//conditions:default": [ diff --git a/source/common/event/file_event_impl.h b/source/common/event/file_event_impl.h index cb5521483183..cc3e505d788b 100644 --- a/source/common/event/file_event_impl.h +++ b/source/common/event/file_event_impl.h @@ -42,4 +42,4 @@ class FileEventImpl : public FileEvent, ImplBase { const bool activate_fd_events_next_event_loop_; }; } // namespace Event -} // namespace Envoy \ No newline at end of file +} // namespace Envoy diff --git a/source/common/network/BUILD b/source/common/network/BUILD index d9a6e7717671..9840662f797a 100644 --- a/source/common/network/BUILD +++ b/source/common/network/BUILD @@ -471,13 +471,3 @@ envoy_cc_library( "//source/common/common:macros", ], ) - -envoy_cc_library( - name = "peer_buffer_lib", - hdrs = ["peer_buffer.h"], - deps = [ - "//source/common/buffer:buffer_lib", - "//source/common/buffer:watermark_buffer_lib", - "//source/common/common:empty_string", - ], -) diff --git a/source/common/network/io_socket_error_impl.h b/source/common/network/io_socket_error_impl.h index e101ee4ee499..50d08b55f26a 100644 --- a/source/common/network/io_socket_error_impl.h +++ b/source/common/network/io_socket_error_impl.h @@ -1,7 +1,6 @@ #pragma once #include "envoy/api/io_error.h" -#include "envoy/api/os_sys_calls_common.h" #include "common/common/assert.h" @@ -33,5 +32,6 @@ class IoSocketError : public Api::IoError { private: int errno_; }; + } // namespace Network } // namespace Envoy diff --git a/source/extensions/io_socket/buffered_io_socket/BUILD b/source/extensions/io_socket/buffered_io_socket/BUILD index 5046e7a2f10c..60c746e0c5f8 100644 --- a/source/extensions/io_socket/buffered_io_socket/BUILD +++ b/source/extensions/io_socket/buffered_io_socket/BUILD @@ -8,6 +8,16 @@ licenses(["notice"]) # Apache 2 envoy_extension_package() +envoy_cc_library( + name = "peer_buffer_lib", + hdrs = ["peer_buffer.h"], + deps = [ + "//source/common/buffer:buffer_lib", + "//source/common/buffer:watermark_buffer_lib", + "//source/common/common:empty_string", + ], +) + envoy_cc_library( name = "buffered_io_socket_handle_lib", srcs = [ @@ -19,8 +29,8 @@ envoy_cc_library( "user_space_file_event_impl.h", ], deps = [ + ":peer_buffer_lib", "//source/common/event:dispatcher_includes", "//source/common/network:default_socket_interface_lib", - "//source/common/network:peer_buffer_lib", ], ) diff --git a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h index 2dea13134fc3..cbb9363fdc31 100644 --- a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h +++ b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h @@ -11,8 +11,8 @@ #include "common/buffer/watermark_buffer.h" #include "common/common/logger.h" #include "common/network/io_socket_error_impl.h" -#include "common/network/peer_buffer.h" +#include "extensions/io_socket/buffered_io_socket/peer_buffer.h" #include "extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h" namespace Envoy { @@ -30,7 +30,7 @@ namespace BufferedIoSocket { * BufferedIoSocketHandle mutates the state of peer handle and no lock is introduced. */ class BufferedIoSocketHandleImpl final : public Network::IoHandle, - public Network::ReadWritable, + public ReadWritable, protected Logger::Loggable { public: BufferedIoSocketHandleImpl(); @@ -78,7 +78,7 @@ class BufferedIoSocketHandleImpl final : public Network::IoHandle, Api::SysCallIntResult shutdown(int how) override; absl::optional lastRoundTripTime() override { return absl::nullopt; } - // Network::WritablePeer + // WritablePeer void setWriteEnd() override { read_end_stream_ = true; } bool isWriteEndSet() override { return read_end_stream_; } void maybeSetNewData() override { @@ -103,14 +103,14 @@ class BufferedIoSocketHandleImpl final : public Network::IoHandle, } Buffer::Instance* getWriteBuffer() override { return &pending_received_data_; } - // Network::ReadWritable + // ReadWritable bool isPeerShutDownWrite() const override { return read_end_stream_; } bool isReadable() const override { return isPeerShutDownWrite() || pending_received_data_.length() > 0; } // Set the peer which will populate the owned pending_received_data. - void setWritablePeer(Network::WritablePeer* writable_peer) { + void setWritablePeer(WritablePeer* writable_peer) { // Swapping writable peer is undefined behavior. ASSERT(!writable_peer_); ASSERT(!write_shutdown_); @@ -136,7 +136,7 @@ class BufferedIoSocketHandleImpl final : public Network::IoHandle, Buffer::WatermarkBuffer pending_received_data_; // Destination of the write(). The value remains non-null until the peer is closed. - Network::WritablePeer* writable_peer_{nullptr}; + WritablePeer* writable_peer_{nullptr}; // The flag whether the peer is valid. Any write attempt must check this flag. bool write_shutdown_{false}; diff --git a/source/common/network/peer_buffer.h b/source/extensions/io_socket/buffered_io_socket/peer_buffer.h similarity index 91% rename from source/common/network/peer_buffer.h rename to source/extensions/io_socket/buffered_io_socket/peer_buffer.h index f42592daee93..aa54a0974876 100644 --- a/source/common/network/peer_buffer.h +++ b/source/extensions/io_socket/buffered_io_socket/peer_buffer.h @@ -4,7 +4,9 @@ #include "envoy/common/pure.h" namespace Envoy { -namespace Network { +namespace Extensions { +namespace IoSocket { +namespace BufferedIoSocket { /** * The interface for the writer. @@ -71,5 +73,7 @@ class ReadWritable : public WritablePeer { */ virtual bool isReadable() const PURE; }; -} // namespace Network +} // namespace BufferedIoSocket +} // namespace IoSocket +} // namespace Extensions } // namespace Envoy diff --git a/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc index 03b08ed489f1..f9353dce44e8 100644 --- a/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc +++ b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc @@ -3,7 +3,8 @@ #include #include "common/common/assert.h" -#include "common/network/peer_buffer.h" + +#include "extensions/io_socket/buffered_io_socket/peer_buffer.h" namespace Envoy { namespace Extensions { @@ -11,7 +12,7 @@ namespace IoSocket { namespace BufferedIoSocket { UserSpaceFileEventImpl::UserSpaceFileEventImpl(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, - uint32_t events, Network::ReadWritable& io_source) + uint32_t events, ReadWritable& io_source) : schedulable_(dispatcher.createSchedulableCallback([this]() { cb_(); })), cb_([this, cb]() { auto ephemeral_events = event_listener_.getAndClearEphemeralEvents(); ENVOY_LOG(trace, "User space event {} invokes callbacks on events = {}", diff --git a/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h index 0ad34ca1ff94..0830c466dca3 100644 --- a/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h +++ b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h @@ -6,7 +6,8 @@ #include "common/event/dispatcher_impl.h" #include "common/event/event_impl_base.h" -#include "common/network/peer_buffer.h" + +#include "extensions/io_socket/buffered_io_socket/peer_buffer.h" namespace Envoy { @@ -40,7 +41,7 @@ class EventListenerImpl { class UserSpaceFileEventImpl final : public Event::FileEvent, Logger::Loggable { public: UserSpaceFileEventImpl(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, uint32_t events, - Network::ReadWritable& io_source); + ReadWritable& io_source); ~UserSpaceFileEventImpl() override = default; @@ -61,7 +62,7 @@ class UserSpaceFileEventImpl final : public Event::FileEvent, Logger::Loggable cb_; - Network::ReadWritable& io_source_; + ReadWritable& io_source_; }; } // namespace BufferedIoSocket } // namespace IoSocket diff --git a/test/common/network/BUILD b/test/common/network/BUILD index e92b72c35af0..b37ad410fe06 100644 --- a/test/common/network/BUILD +++ b/test/common/network/BUILD @@ -75,7 +75,7 @@ envoy_cc_test( name = "connection_impl_test", srcs = ["connection_impl_test.cc"], deps = [ - "//source/common/buffer:buffer_lib", + ":buffer_lib", "//source/common/common:empty_string", "//source/common/event:dispatcher_includes", "//source/common/event:dispatcher_lib", @@ -107,7 +107,7 @@ envoy_cc_test( "//include/envoy/event:dispatcher_interface", "//include/envoy/network:address_interface", "//include/envoy/network:dns_interface", - "//source/common/buffer:buffer_lib", + ":buffer_lib", "//source/common/event:dispatcher_includes", "//source/common/event:dispatcher_lib", "//source/common/network:address_lib", diff --git a/test/extensions/io_socket/buffered_io_socket/BUILD b/test/extensions/io_socket/buffered_io_socket/BUILD index 55b7b5d1e2df..82b16c32c7d0 100644 --- a/test/extensions/io_socket/buffered_io_socket/BUILD +++ b/test/extensions/io_socket/buffered_io_socket/BUILD @@ -38,8 +38,8 @@ envoy_cc_test( "//include/envoy/event:file_event_interface", "//source/common/event:dispatcher_includes", "//source/common/event:dispatcher_lib", - "//source/common/network:peer_buffer_lib", "//source/extensions/io_socket/buffered_io_socket:buffered_io_socket_handle_lib", + "//source/extensions/io_socket/buffered_io_socket:peer_buffer_lib", "//test/mocks:common_lib", "//test/test_common:environment_lib", "//test/test_common:test_runtime_lib", diff --git a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc index 7a738911d7c9..31dbbfdd304c 100644 --- a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc @@ -177,7 +177,7 @@ TEST_F(BufferedIoSocketHandleTest, TestRecvDrain) { TEST_F(BufferedIoSocketHandleTest, FlowControl) { auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); - Network::WritablePeer* handle_as_peer = io_handle_.get(); + WritablePeer* handle_as_peer = io_handle_.get(); internal_buffer.setWatermarks(128); EXPECT_FALSE(io_handle_->isReadable()); EXPECT_TRUE(io_handle_peer_->isWritable()); @@ -309,7 +309,7 @@ TEST_F(BufferedIoSocketHandleTest, TestEventResetClearCallback) { TEST_F(BufferedIoSocketHandleTest, TestDrainToLowWaterMarkTriggerReadEvent) { auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); - Network::WritablePeer* handle_as_peer = io_handle_.get(); + WritablePeer* handle_as_peer = io_handle_.get(); internal_buffer.setWatermarks(128); EXPECT_FALSE(io_handle_->isReadable()); EXPECT_TRUE(io_handle_peer_->isWritable()); diff --git a/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc index 690d8653aa42..002f899c2507 100644 --- a/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc @@ -3,8 +3,8 @@ #include "envoy/event/file_event.h" #include "common/event/dispatcher_impl.h" -#include "common/network/peer_buffer.h" +#include "extensions/io_socket/buffered_io_socket/peer_buffer.h" #include "extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h" #include "test/mocks/common.h" @@ -30,7 +30,7 @@ class MockReadyCb { MOCK_METHOD(void, called, (uint32_t)); }; -class MockReadWritable : public Network::ReadWritable { +class MockReadWritable : public ReadWritable { public: MOCK_METHOD(void, setWriteEnd, ()); MOCK_METHOD(bool, isWriteEndSet, ()); From 47cf2a8ac243249703cc1e4d32aa9095bef52c4c Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Mon, 2 Nov 2020 19:43:26 +0000 Subject: [PATCH 092/100] save file Signed-off-by: Yuchen Dai --- test/common/network/BUILD | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/common/network/BUILD b/test/common/network/BUILD index b37ad410fe06..e92b72c35af0 100644 --- a/test/common/network/BUILD +++ b/test/common/network/BUILD @@ -75,7 +75,7 @@ envoy_cc_test( name = "connection_impl_test", srcs = ["connection_impl_test.cc"], deps = [ - ":buffer_lib", + "//source/common/buffer:buffer_lib", "//source/common/common:empty_string", "//source/common/event:dispatcher_includes", "//source/common/event:dispatcher_lib", @@ -107,7 +107,7 @@ envoy_cc_test( "//include/envoy/event:dispatcher_interface", "//include/envoy/network:address_interface", "//include/envoy/network:dns_interface", - ":buffer_lib", + "//source/common/buffer:buffer_lib", "//source/common/event:dispatcher_includes", "//source/common/event:dispatcher_lib", "//source/common/network:address_lib", From 6244c65a1db24ff7a485db5a61971a75757c1437 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Tue, 3 Nov 2020 00:13:25 +0000 Subject: [PATCH 093/100] clangtidy wellknown names Signed-off-by: Yuchen Dai --- source/extensions/io_socket/well_known_names.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/extensions/io_socket/well_known_names.h b/source/extensions/io_socket/well_known_names.h index 86ab21d36be5..e912d00ad388 100644 --- a/source/extensions/io_socket/well_known_names.h +++ b/source/extensions/io_socket/well_known_names.h @@ -27,7 +27,7 @@ class IoSocketShortNameValues { const std::string BufferedIoSocket = "buffered_io_socket"; }; -using IoSocketShortNameValues = ConstSingleton; +using IoSocketShortNames = ConstSingleton; } // namespace IoSocket } // namespace Extensions From a58a7120438b81a8170e66b6b70a85919eb88414 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Tue, 3 Nov 2020 05:42:18 +0000 Subject: [PATCH 094/100] dup counter Signed-off-by: Yuchen Dai --- .../common/upstream/cluster_manager_impl.cc | 5 +++++ test/integration/ads_integration.cc | 4 ++-- test/integration/ads_integration.h | 2 +- test/integration/ads_integration_test.cc | 22 +++++++++++++++++++ 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/source/common/upstream/cluster_manager_impl.cc b/source/common/upstream/cluster_manager_impl.cc index edb4c5b070d0..ae46754b5bb8 100644 --- a/source/common/upstream/cluster_manager_impl.cc +++ b/source/common/upstream/cluster_manager_impl.cc @@ -67,6 +67,11 @@ void ClusterManagerInitHelper::addCluster(Cluster& cluster) { cluster.initialize(initialize_cb); } else { ASSERT(cluster.initializePhase() == Cluster::InitializePhase::Secondary); + secondary_init_clusters_.remove_if( + [name_to_remove = cluster.info()->name()](Cluster* cluster_iter) { + return cluster_iter->info()->name() == name_to_remove; + }); + secondary_init_clusters_.push_back(&cluster); if (started_secondary_initialize_) { // This can happen if we get a second CDS update that adds new clusters after we have diff --git a/test/integration/ads_integration.cc b/test/integration/ads_integration.cc index 7d81b1de0a1b..ffbd4b90225f 100644 --- a/test/integration/ads_integration.cc +++ b/test/integration/ads_integration.cc @@ -34,8 +34,8 @@ AdsIntegrationTest::AdsIntegrationTest(const envoy::config::core::v3::ApiVersion void AdsIntegrationTest::TearDown() { cleanUpXdsConnection(); } -envoy::config::cluster::v3::Cluster AdsIntegrationTest::buildCluster(const std::string& name) { - return ConfigHelper::buildCluster(name, "ROUND_ROBIN", api_version_); +envoy::config::cluster::v3::Cluster AdsIntegrationTest::buildCluster(const std::string& name, const std::string& lb_policy) { + return ConfigHelper::buildCluster(name, lb_policy, api_version_); } envoy::config::cluster::v3::Cluster AdsIntegrationTest::buildTlsCluster(const std::string& name) { diff --git a/test/integration/ads_integration.h b/test/integration/ads_integration.h index 0da99aea566a..d84afd8d5dbf 100644 --- a/test/integration/ads_integration.h +++ b/test/integration/ads_integration.h @@ -22,7 +22,7 @@ class AdsIntegrationTest : public Grpc::DeltaSotwIntegrationParamTest, public Ht void TearDown() override; - envoy::config::cluster::v3::Cluster buildCluster(const std::string& name); + envoy::config::cluster::v3::Cluster buildCluster(const std::string& name, const std::string& lb_policy = "ROUND_ROBIN"); envoy::config::cluster::v3::Cluster buildTlsCluster(const std::string& name); diff --git a/test/integration/ads_integration_test.cc b/test/integration/ads_integration_test.cc index 01aae9dc9f73..3b5b7303be99 100644 --- a/test/integration/ads_integration_test.cc +++ b/test/integration/ads_integration_test.cc @@ -1152,6 +1152,28 @@ TEST_P(AdsClusterV3Test, BasicClusterInitialWarming) { test_server_->waitForGaugeGe("cluster_manager.active_clusters", 2); } +TEST_P(AdsClusterV3Test, BasicClusterResendWarming) { + initialize(); + const auto cds_type_url = Config::getTypeUrl( + envoy::config::core::v3::ApiVersion::V3); + const auto eds_type_url = Config::getTypeUrl( + envoy::config::core::v3::ApiVersion::V3); + + EXPECT_TRUE(compareDiscoveryRequest(cds_type_url, "", {}, {}, {}, true)); + sendDiscoveryResponse( + cds_type_url, {buildCluster("cluster_0")}, {buildCluster("cluster_0")}, {}, "1", false); + test_server_->waitForGaugeEq("cluster_manager.warming_clusters", 1); + sendDiscoveryResponse( + cds_type_url, {buildCluster("cluster_0", "MAGLEV")}, {buildCluster("cluster_0", "MAGLEV")}, {}, "2", false); + EXPECT_TRUE(compareDiscoveryRequest(eds_type_url, "", {"cluster_0"}, {"cluster_0"}, {})); + sendDiscoveryResponse( + eds_type_url, {buildClusterLoadAssignment("cluster_0")}, + {buildClusterLoadAssignment("cluster_0")}, {}, "1", false); + + test_server_->waitForGaugeEq("cluster_manager.warming_clusters", 0); + test_server_->waitForGaugeGe("cluster_manager.active_clusters", 2); +} + // Verify CDS is paused during cluster warming. TEST_P(AdsClusterV3Test, CdsPausedDuringWarming) { initialize(); From 1269e1e8e4bd54f01c201718a5205a8ebb663904 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 5 Nov 2020 10:23:12 +0000 Subject: [PATCH 095/100] extension and LT Signed-off-by: Yuchen Dai --- source/extensions/io_socket/BUILD | 13 +------------ .../extensions/io_socket/buffered_io_socket/BUILD | 10 +++++++--- .../buffered_io_socket_handle_impl.cc | 2 +- .../buffered_io_socket_handle_impl.h | 2 +- 4 files changed, 10 insertions(+), 17 deletions(-) diff --git a/source/extensions/io_socket/BUILD b/source/extensions/io_socket/BUILD index 40a5e79b39d3..21a78bd7d8c5 100644 --- a/source/extensions/io_socket/BUILD +++ b/source/extensions/io_socket/BUILD @@ -1,19 +1,8 @@ load( "//bazel:envoy_build_system.bzl", - "envoy_cc_library", "envoy_extension_package", ) licenses(["notice"]) # Apache 2 -envoy_extension_package() - -envoy_cc_library( - name = "well_known_names", - hdrs = ["well_known_names.h"], - # well known names files are public as long as they exist. - visibility = ["//visibility:public"], - deps = [ - "//source/common/singleton:const_singleton", - ], -) +envoy_extension_package() \ No newline at end of file diff --git a/source/extensions/io_socket/buffered_io_socket/BUILD b/source/extensions/io_socket/buffered_io_socket/BUILD index 60c746e0c5f8..a2dad3494947 100644 --- a/source/extensions/io_socket/buffered_io_socket/BUILD +++ b/source/extensions/io_socket/buffered_io_socket/BUILD @@ -1,6 +1,6 @@ load( "//bazel:envoy_build_system.bzl", - "envoy_cc_library", + "envoy_cc_extension", "envoy_extension_package", ) @@ -8,9 +8,11 @@ licenses(["notice"]) # Apache 2 envoy_extension_package() -envoy_cc_library( +envoy_cc_extension( name = "peer_buffer_lib", hdrs = ["peer_buffer.h"], + security_posture = "unknown", + status = "alpha", deps = [ "//source/common/buffer:buffer_lib", "//source/common/buffer:watermark_buffer_lib", @@ -18,7 +20,7 @@ envoy_cc_library( ], ) -envoy_cc_library( +envoy_cc_extension( name = "buffered_io_socket_handle_lib", srcs = [ "buffered_io_socket_handle_impl.cc", @@ -28,6 +30,8 @@ envoy_cc_library( "buffered_io_socket_handle_impl.h", "user_space_file_event_impl.h", ], + security_posture = "unknown", + status = "alpha", deps = [ ":peer_buffer_lib", "//source/common/event:dispatcher_includes", diff --git a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc index 5cf5bad161bc..c8d63fb19836 100644 --- a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc +++ b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc @@ -269,7 +269,7 @@ void BufferedIoSocketHandleImpl::initializeFileEvent(Event::Dispatcher& dispatch uint32_t events) { ASSERT(user_file_event_ == nullptr, "Attempting to initialize two `file_event_` for the same " "file descriptor. This is not allowed."); - ASSERT(trigger == Event::FileTriggerType::Edge, "Only support edge type."); + ASSERT(trigger != Event::FileTriggerType::Level, "Native level trigger is not supported yet."); user_file_event_ = std::make_unique(dispatcher, cb, events, *this); } diff --git a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h index cbb9363fdc31..c3730a3bcc73 100644 --- a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h +++ b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h @@ -22,7 +22,7 @@ namespace BufferedIoSocket { /** * Network::IoHandle implementation which provides a buffer as data source. It is designed to used * by Network::ConnectionImpl. Some known limitations include - * 1. It doesn't not include a file descriptor. Do not use "fdDoNotUse". + * 1. It doesn't include a file descriptor. Do not use "fdDoNotUse". * 2. It doesn't support socket options. Wrap this in ConnectionSocket and implement the socket * getter/setter options. * 3. It doesn't support UDP interface. From c7ffacc6d04d55c91652b072a5e1a174d5a8f44e Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 5 Nov 2020 17:19:10 +0000 Subject: [PATCH 096/100] add staging Signed-off-by: Yuchen Dai --- source/extensions/io_socket/BUILD | 2 +- .../extensions/io_socket/well_known_names.h | 34 ------------------- test/integration/ads_integration.cc | 3 +- test/integration/ads_integration.h | 3 +- test/integration/ads_integration_test.cc | 3 +- 5 files changed, 7 insertions(+), 38 deletions(-) delete mode 100644 source/extensions/io_socket/well_known_names.h diff --git a/source/extensions/io_socket/BUILD b/source/extensions/io_socket/BUILD index 21a78bd7d8c5..90e061ad8da3 100644 --- a/source/extensions/io_socket/BUILD +++ b/source/extensions/io_socket/BUILD @@ -5,4 +5,4 @@ load( licenses(["notice"]) # Apache 2 -envoy_extension_package() \ No newline at end of file +envoy_extension_package() diff --git a/source/extensions/io_socket/well_known_names.h b/source/extensions/io_socket/well_known_names.h deleted file mode 100644 index e912d00ad388..000000000000 --- a/source/extensions/io_socket/well_known_names.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -#include - -#include "common/singleton/const_singleton.h" - -namespace Envoy { -namespace Extensions { -namespace IoSocket { - -/** - * Well-known io socket names. - * NOTE: New io sockets should use the well known name: envoy.io_socket.name. - */ -class IoSocketNameValues { -public: - const std::string BufferedIoSocket = "envoy.io_socket.buffered_io_socket"; -}; - -using IoSocketNames = ConstSingleton; - -/** - * Well-known io socket names. - */ -class IoSocketShortNameValues { -public: - const std::string BufferedIoSocket = "buffered_io_socket"; -}; - -using IoSocketShortNames = ConstSingleton; - -} // namespace IoSocket -} // namespace Extensions -} // namespace Envoy diff --git a/test/integration/ads_integration.cc b/test/integration/ads_integration.cc index ffbd4b90225f..6a0db9004244 100644 --- a/test/integration/ads_integration.cc +++ b/test/integration/ads_integration.cc @@ -34,7 +34,8 @@ AdsIntegrationTest::AdsIntegrationTest(const envoy::config::core::v3::ApiVersion void AdsIntegrationTest::TearDown() { cleanUpXdsConnection(); } -envoy::config::cluster::v3::Cluster AdsIntegrationTest::buildCluster(const std::string& name, const std::string& lb_policy) { +envoy::config::cluster::v3::Cluster AdsIntegrationTest::buildCluster(const std::string& name, + const std::string& lb_policy) { return ConfigHelper::buildCluster(name, lb_policy, api_version_); } diff --git a/test/integration/ads_integration.h b/test/integration/ads_integration.h index d84afd8d5dbf..8c9a8e0ab3e6 100644 --- a/test/integration/ads_integration.h +++ b/test/integration/ads_integration.h @@ -22,7 +22,8 @@ class AdsIntegrationTest : public Grpc::DeltaSotwIntegrationParamTest, public Ht void TearDown() override; - envoy::config::cluster::v3::Cluster buildCluster(const std::string& name, const std::string& lb_policy = "ROUND_ROBIN"); + envoy::config::cluster::v3::Cluster buildCluster(const std::string& name, + const std::string& lb_policy = "ROUND_ROBIN"); envoy::config::cluster::v3::Cluster buildTlsCluster(const std::string& name); diff --git a/test/integration/ads_integration_test.cc b/test/integration/ads_integration_test.cc index 3b5b7303be99..3b45663df5a1 100644 --- a/test/integration/ads_integration_test.cc +++ b/test/integration/ads_integration_test.cc @@ -1164,7 +1164,8 @@ TEST_P(AdsClusterV3Test, BasicClusterResendWarming) { cds_type_url, {buildCluster("cluster_0")}, {buildCluster("cluster_0")}, {}, "1", false); test_server_->waitForGaugeEq("cluster_manager.warming_clusters", 1); sendDiscoveryResponse( - cds_type_url, {buildCluster("cluster_0", "MAGLEV")}, {buildCluster("cluster_0", "MAGLEV")}, {}, "2", false); + cds_type_url, {buildCluster("cluster_0", "MAGLEV")}, {buildCluster("cluster_0", "MAGLEV")}, + {}, "2", false); EXPECT_TRUE(compareDiscoveryRequest(eds_type_url, "", {"cluster_0"}, {"cluster_0"}, {})); sendDiscoveryResponse( eds_type_url, {buildClusterLoadAssignment("cluster_0")}, From f2633f452fee86437e4142aaa5625df0e9713ee7 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 5 Nov 2020 17:51:43 +0000 Subject: [PATCH 097/100] revert Signed-off-by: Yuchen Dai --- test/integration/ads_integration.cc | 3 +-- test/integration/ads_integration.h | 3 +-- test/integration/ads_integration_test.cc | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/test/integration/ads_integration.cc b/test/integration/ads_integration.cc index 6a0db9004244..ffbd4b90225f 100644 --- a/test/integration/ads_integration.cc +++ b/test/integration/ads_integration.cc @@ -34,8 +34,7 @@ AdsIntegrationTest::AdsIntegrationTest(const envoy::config::core::v3::ApiVersion void AdsIntegrationTest::TearDown() { cleanUpXdsConnection(); } -envoy::config::cluster::v3::Cluster AdsIntegrationTest::buildCluster(const std::string& name, - const std::string& lb_policy) { +envoy::config::cluster::v3::Cluster AdsIntegrationTest::buildCluster(const std::string& name, const std::string& lb_policy) { return ConfigHelper::buildCluster(name, lb_policy, api_version_); } diff --git a/test/integration/ads_integration.h b/test/integration/ads_integration.h index 8c9a8e0ab3e6..d84afd8d5dbf 100644 --- a/test/integration/ads_integration.h +++ b/test/integration/ads_integration.h @@ -22,8 +22,7 @@ class AdsIntegrationTest : public Grpc::DeltaSotwIntegrationParamTest, public Ht void TearDown() override; - envoy::config::cluster::v3::Cluster buildCluster(const std::string& name, - const std::string& lb_policy = "ROUND_ROBIN"); + envoy::config::cluster::v3::Cluster buildCluster(const std::string& name, const std::string& lb_policy = "ROUND_ROBIN"); envoy::config::cluster::v3::Cluster buildTlsCluster(const std::string& name); diff --git a/test/integration/ads_integration_test.cc b/test/integration/ads_integration_test.cc index 3b45663df5a1..3b5b7303be99 100644 --- a/test/integration/ads_integration_test.cc +++ b/test/integration/ads_integration_test.cc @@ -1164,8 +1164,7 @@ TEST_P(AdsClusterV3Test, BasicClusterResendWarming) { cds_type_url, {buildCluster("cluster_0")}, {buildCluster("cluster_0")}, {}, "1", false); test_server_->waitForGaugeEq("cluster_manager.warming_clusters", 1); sendDiscoveryResponse( - cds_type_url, {buildCluster("cluster_0", "MAGLEV")}, {buildCluster("cluster_0", "MAGLEV")}, - {}, "2", false); + cds_type_url, {buildCluster("cluster_0", "MAGLEV")}, {buildCluster("cluster_0", "MAGLEV")}, {}, "2", false); EXPECT_TRUE(compareDiscoveryRequest(eds_type_url, "", {"cluster_0"}, {"cluster_0"}, {})); sendDiscoveryResponse( eds_type_url, {buildClusterLoadAssignment("cluster_0")}, From 7c81f1883d37c85e37335b2fa004c85fc17772fe Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 5 Nov 2020 17:54:45 +0000 Subject: [PATCH 098/100] revert cont Signed-off-by: Yuchen Dai --- source/common/network/BUILD | 1 - .../common/upstream/cluster_manager_impl.cc | 5 ----- test/integration/ads_integration.cc | 4 ++-- test/integration/ads_integration.h | 2 +- test/integration/ads_integration_test.cc | 22 ------------------- 5 files changed, 3 insertions(+), 31 deletions(-) diff --git a/source/common/network/BUILD b/source/common/network/BUILD index bf41cdb70df6..969e49f20673 100644 --- a/source/common/network/BUILD +++ b/source/common/network/BUILD @@ -167,7 +167,6 @@ envoy_cc_library( hdrs = ["io_socket_error_impl.h"], deps = [ "//include/envoy/api:io_error_interface", - "//include/envoy/api:os_sys_calls_interface", "//source/common/common:assert_lib", "//source/common/common:utility_lib", ], diff --git a/source/common/upstream/cluster_manager_impl.cc b/source/common/upstream/cluster_manager_impl.cc index 982bad8efd76..5a2fb1328c36 100644 --- a/source/common/upstream/cluster_manager_impl.cc +++ b/source/common/upstream/cluster_manager_impl.cc @@ -67,11 +67,6 @@ void ClusterManagerInitHelper::addCluster(Cluster& cluster) { cluster.initialize(initialize_cb); } else { ASSERT(cluster.initializePhase() == Cluster::InitializePhase::Secondary); - secondary_init_clusters_.remove_if( - [name_to_remove = cluster.info()->name()](Cluster* cluster_iter) { - return cluster_iter->info()->name() == name_to_remove; - }); - secondary_init_clusters_.push_back(&cluster); if (started_secondary_initialize_) { // This can happen if we get a second CDS update that adds new clusters after we have diff --git a/test/integration/ads_integration.cc b/test/integration/ads_integration.cc index ffbd4b90225f..7d81b1de0a1b 100644 --- a/test/integration/ads_integration.cc +++ b/test/integration/ads_integration.cc @@ -34,8 +34,8 @@ AdsIntegrationTest::AdsIntegrationTest(const envoy::config::core::v3::ApiVersion void AdsIntegrationTest::TearDown() { cleanUpXdsConnection(); } -envoy::config::cluster::v3::Cluster AdsIntegrationTest::buildCluster(const std::string& name, const std::string& lb_policy) { - return ConfigHelper::buildCluster(name, lb_policy, api_version_); +envoy::config::cluster::v3::Cluster AdsIntegrationTest::buildCluster(const std::string& name) { + return ConfigHelper::buildCluster(name, "ROUND_ROBIN", api_version_); } envoy::config::cluster::v3::Cluster AdsIntegrationTest::buildTlsCluster(const std::string& name) { diff --git a/test/integration/ads_integration.h b/test/integration/ads_integration.h index d84afd8d5dbf..0da99aea566a 100644 --- a/test/integration/ads_integration.h +++ b/test/integration/ads_integration.h @@ -22,7 +22,7 @@ class AdsIntegrationTest : public Grpc::DeltaSotwIntegrationParamTest, public Ht void TearDown() override; - envoy::config::cluster::v3::Cluster buildCluster(const std::string& name, const std::string& lb_policy = "ROUND_ROBIN"); + envoy::config::cluster::v3::Cluster buildCluster(const std::string& name); envoy::config::cluster::v3::Cluster buildTlsCluster(const std::string& name); diff --git a/test/integration/ads_integration_test.cc b/test/integration/ads_integration_test.cc index 3b5b7303be99..01aae9dc9f73 100644 --- a/test/integration/ads_integration_test.cc +++ b/test/integration/ads_integration_test.cc @@ -1152,28 +1152,6 @@ TEST_P(AdsClusterV3Test, BasicClusterInitialWarming) { test_server_->waitForGaugeGe("cluster_manager.active_clusters", 2); } -TEST_P(AdsClusterV3Test, BasicClusterResendWarming) { - initialize(); - const auto cds_type_url = Config::getTypeUrl( - envoy::config::core::v3::ApiVersion::V3); - const auto eds_type_url = Config::getTypeUrl( - envoy::config::core::v3::ApiVersion::V3); - - EXPECT_TRUE(compareDiscoveryRequest(cds_type_url, "", {}, {}, {}, true)); - sendDiscoveryResponse( - cds_type_url, {buildCluster("cluster_0")}, {buildCluster("cluster_0")}, {}, "1", false); - test_server_->waitForGaugeEq("cluster_manager.warming_clusters", 1); - sendDiscoveryResponse( - cds_type_url, {buildCluster("cluster_0", "MAGLEV")}, {buildCluster("cluster_0", "MAGLEV")}, {}, "2", false); - EXPECT_TRUE(compareDiscoveryRequest(eds_type_url, "", {"cluster_0"}, {"cluster_0"}, {})); - sendDiscoveryResponse( - eds_type_url, {buildClusterLoadAssignment("cluster_0")}, - {buildClusterLoadAssignment("cluster_0")}, {}, "1", false); - - test_server_->waitForGaugeEq("cluster_manager.warming_clusters", 0); - test_server_->waitForGaugeGe("cluster_manager.active_clusters", 2); -} - // Verify CDS is paused during cluster warming. TEST_P(AdsClusterV3Test, CdsPausedDuringWarming) { initialize(); From e0b7fe56f90be8d95bd47a126dc7f53145e821ae Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Fri, 6 Nov 2020 10:03:53 +0000 Subject: [PATCH 099/100] add internal related factory Signed-off-by: Yuchen Dai --- include/envoy/network/address.h | 4 ++ source/extensions/io_socket/BUILD | 27 ++++++++++ source/extensions/io_socket/address_map.h | 27 ++++++++++ .../io_socket/buffered_io_socket/BUILD | 14 ++++++ .../io_socket/buffered_io_socket/b_factory.cc | 1 + .../io_socket/buffered_io_socket/b_factory.h | 24 +++++++++ source/extensions/io_socket/config.h | 49 +++++++++++++++++++ .../io_socket/buffered_io_socket/BUILD | 9 ++++ .../buffered_io_socket/b_factory_test.cc | 38 ++++++++++++++ 9 files changed, 193 insertions(+) create mode 100644 source/extensions/io_socket/address_map.h create mode 100644 source/extensions/io_socket/buffered_io_socket/b_factory.cc create mode 100644 source/extensions/io_socket/buffered_io_socket/b_factory.h create mode 100644 source/extensions/io_socket/config.h create mode 100644 test/extensions/io_socket/buffered_io_socket/b_factory_test.cc diff --git a/include/envoy/network/address.h b/include/envoy/network/address.h index bd28205bd630..ff49ea8841b2 100644 --- a/include/envoy/network/address.h +++ b/include/envoy/network/address.h @@ -134,6 +134,10 @@ class EnvoyInternalAddress { enum class Type { Ip, Pipe, EnvoyInternal }; +constexpr absl::string_view IpName = "Ip"; +constexpr absl::string_view PipeName = "Pipe"; +constexpr absl::string_view EnvoyInternalName = "EnvoyInternal"; + /** * Interface for all network addresses. */ diff --git a/source/extensions/io_socket/BUILD b/source/extensions/io_socket/BUILD index 90e061ad8da3..3c5ca2e172f7 100644 --- a/source/extensions/io_socket/BUILD +++ b/source/extensions/io_socket/BUILD @@ -1,8 +1,35 @@ load( "//bazel:envoy_build_system.bzl", + "envoy_cc_extension", + "envoy_cc_library", "envoy_extension_package", ) licenses(["notice"]) # Apache 2 envoy_extension_package() + +envoy_cc_extension( + name = "address_map", + hdrs = [ + "address_map.h", + ], + security_posture = "unknown", + status = "alpha", + deps = [ + "//include/envoy/network:address_interface", + ], +) + +envoy_cc_library( + name = "client_connection_factory", + hdrs = ["config.h"], + deps = [ + ":address_map", + "//include/envoy/config:typed_config_interface", + "//include/envoy/network:connection_interface", + "//include/envoy/registry", + "//source/common/common:assert_lib", + "//source/common/singleton:const_singleton", + ], +) diff --git a/source/extensions/io_socket/address_map.h b/source/extensions/io_socket/address_map.h new file mode 100644 index 000000000000..1892715ab6d1 --- /dev/null +++ b/source/extensions/io_socket/address_map.h @@ -0,0 +1,27 @@ +#pragma once + +#include "envoy/network/address.h" + +namespace Envoy { +namespace Network { +namespace Address { + +class AddressMap { +public: + constexpr absl::string_view operator[](Type address_type) const { + switch (address_type) { + case Type::Ip: + return IpName; + case Type::Pipe: + return PipeName; + case Type::EnvoyInternal: + return EnvoyInternalName; + } + } +}; + +constexpr AddressMap addressMap; + +} // namespace Address +} // namespace Network +} // namespace Envoy \ No newline at end of file diff --git a/source/extensions/io_socket/buffered_io_socket/BUILD b/source/extensions/io_socket/buffered_io_socket/BUILD index a2dad3494947..f97aaee61f66 100644 --- a/source/extensions/io_socket/buffered_io_socket/BUILD +++ b/source/extensions/io_socket/buffered_io_socket/BUILD @@ -1,6 +1,7 @@ load( "//bazel:envoy_build_system.bzl", "envoy_cc_extension", + "envoy_cc_library", "envoy_extension_package", ) @@ -38,3 +39,16 @@ envoy_cc_extension( "//source/common/network:default_socket_interface_lib", ], ) + +envoy_cc_library( + name = "b_factory", + srcs = [ + "b_factory.cc", + ], + hdrs = [ + "b_factory.h", + ], + deps = [ + "//source/extensions/io_socket:client_connection_factory", + ], +) diff --git a/source/extensions/io_socket/buffered_io_socket/b_factory.cc b/source/extensions/io_socket/buffered_io_socket/b_factory.cc new file mode 100644 index 000000000000..395e9d86b7e4 --- /dev/null +++ b/source/extensions/io_socket/buffered_io_socket/b_factory.cc @@ -0,0 +1 @@ +#include "extensions/io_socket/buffered_io_socket/b_factory.h" diff --git a/source/extensions/io_socket/buffered_io_socket/b_factory.h b/source/extensions/io_socket/buffered_io_socket/b_factory.h new file mode 100644 index 000000000000..f6eb40f554cc --- /dev/null +++ b/source/extensions/io_socket/buffered_io_socket/b_factory.h @@ -0,0 +1,24 @@ +#pragma once + +#include "envoy/network/address.h" +#include "extensions/io_socket/config.h" + +namespace Envoy { +namespace Extensions { +namespace IoSocket { + +class BioClientConnectionFactory : public ClientConnectionFactory { +public: + ~BioClientConnectionFactory() override = default; + + /** + * Create a particular client connection. + * @return ClientConnectionPtr the client connection. + */ + Network::ClientConnectionPtr createClientConnection() override { return nullptr; } + + std::string name() const override { return std::string(Network::Address::EnvoyInternalName); } +}; +} // namespace IoSocket +} // namespace Extensions +} // namespace Envoy \ No newline at end of file diff --git a/source/extensions/io_socket/config.h b/source/extensions/io_socket/config.h new file mode 100644 index 000000000000..cb8153d71ef3 --- /dev/null +++ b/source/extensions/io_socket/config.h @@ -0,0 +1,49 @@ +#pragma once + +#include +#include + +#include "envoy/buffer/buffer.h" +#include "envoy/config/typed_config.h" +#include "envoy/registry/registry.h" +#include "envoy/network/connection.h" + +#include "extensions/io_socket/address_map.h" + +#include "common/common/assert.h" +#include "common/singleton/const_singleton.h" + +namespace Envoy { +namespace Extensions { +namespace IoSocket { + +class ClientConnectionFactory : public Envoy::Config::UntypedFactory { +public: + ~ClientConnectionFactory() override = default; + + /** + * Create a particular client connection. + * @return ClientConnectionPtr the client connection. + */ + virtual Network::ClientConnectionPtr createClientConnection() PURE; + + std::string category() const override { return "envoy.connection"; } + + /** + * Convenience method to lookup a factory by destination address type. + * @return ClientConnectionFactory& for the destiantion address. + */ + static ClientConnectionFactory* + getFactoryByAddress(Network::Address::InstanceConstSharedPtr& destination_address) { + if (destination_address == nullptr) { + return nullptr; + } + + return Registry::FactoryRegistry::getFactory( + Network::Address::addressMap[destination_address->type()]); + } +}; + +} // namespace IoSocket +} // namespace Extensions +} // namespace Envoy \ No newline at end of file diff --git a/test/extensions/io_socket/buffered_io_socket/BUILD b/test/extensions/io_socket/buffered_io_socket/BUILD index 82b16c32c7d0..8a89b462acf2 100644 --- a/test/extensions/io_socket/buffered_io_socket/BUILD +++ b/test/extensions/io_socket/buffered_io_socket/BUILD @@ -46,3 +46,12 @@ envoy_cc_test( "//test/test_common:utility_lib", ], ) + +envoy_cc_test( + name = "b_factory_test", + srcs = ["b_factory_test.cc"], + deps = [ + "//source/extensions/io_socket/buffered_io_socket:b_factory", + "//test/test_common:registry_lib", + ], +) diff --git a/test/extensions/io_socket/buffered_io_socket/b_factory_test.cc b/test/extensions/io_socket/buffered_io_socket/b_factory_test.cc new file mode 100644 index 000000000000..65eeaaec1a27 --- /dev/null +++ b/test/extensions/io_socket/buffered_io_socket/b_factory_test.cc @@ -0,0 +1,38 @@ + +#include "common/network/address_impl.h" + +#include "extensions/io_socket/buffered_io_socket/b_factory.h" +#include "test/test_common/registry.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using testing::_; +using testing::NiceMock; + +namespace Envoy { +namespace Extensions { +namespace IoSocket { +namespace BufferedIoSocket { +namespace { + +class FactoryTest : public testing::Test {}; + +TEST_F(FactoryTest, TestCreate) { + BioClientConnectionFactory factory; + Registry::InjectFactory registration(factory); + // TODO(lambdai): share_ptr covariance + auto address = std::dynamic_pointer_cast( + std::make_shared("abc")); + auto* f = ClientConnectionFactory::getFactoryByAddress(address); + // Registered. + ASSERT_NE(nullptr, f); + auto connection = f->createClientConnection(); + // Naive implemention. + ASSERT_EQ(nullptr, connection); +} +} // namespace +} // namespace BufferedIoSocket +} // namespace IoSocket +} // namespace Extensions +} // namespace Envoy \ No newline at end of file From c1d3655e18b61df75a2b709877936a5833ec7db6 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Wed, 11 Nov 2020 09:07:33 +0000 Subject: [PATCH 100/100] merge and fix all build issue Signed-off-by: Yuchen Dai --- .../filters/listener/http_inspector/http_inspector_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/extensions/filters/listener/http_inspector/http_inspector_test.cc b/test/extensions/filters/listener/http_inspector/http_inspector_test.cc index 33206635489d..e36889b86a85 100644 --- a/test/extensions/filters/listener/http_inspector/http_inspector_test.cc +++ b/test/extensions/filters/listener/http_inspector/http_inspector_test.cc @@ -721,7 +721,7 @@ TEST_F(HttpInspectorTestWithBufferIoSocket, InlineRecv) { "a52df4a0-ed00-4a19-86a7-80e5049c6c84\r\nx-envoy-expected-rq-timeout-ms: " "15000\r\ncontent-length: 0\r\n\r\n"; - io_handle_->getBufferForTest().add(header); + io_handle_->getWriteBuffer()->add(header); const std::vector alpn_protos{Http::Utility::AlpnNames::get().Http10}; EXPECT_CALL(socket_, setRequestedApplicationProtocols(alpn_protos));