Skip to content

Commit

Permalink
Add socket type in SocketOption
Browse files Browse the repository at this point in the history
Signed-off-by: Fredy Wijaya <[email protected]>
  • Loading branch information
fredyw committed Jul 19, 2024
1 parent 7b8baff commit b64c697
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 3 deletions.
18 changes: 17 additions & 1 deletion api/envoy/config/core/v3/socket_option.proto
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE;
// :ref:`admin's <envoy_v3_api_field_config.bootstrap.v3.Admin.socket_options>` socket_options etc.
//
// It should be noted that the name or level may have different values on different platforms.
// [#next-free-field: 7]
// [#next-free-field: 8]
message SocketOption {
option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.core.SocketOption";

Expand All @@ -51,6 +51,17 @@ message SocketOption {
STATE_LISTENING = 2;
}

enum SocketType {
// Apply the socket option irrespective of the socket type.
NONE = 0;

// Apply the socket option to the sequenced connection-oriented socket type.
STREAM = 1;

// Apply the socket type to the datagram connectionless socket type.
DATAGRAM = 2;
}

// An optional name to give this socket option for debugging, etc.
// Uniqueness is not required and no special meaning is assumed.
string description = 1;
Expand All @@ -74,6 +85,11 @@ message SocketOption {
// The state in which the option will be applied. When used in BindConfig
// STATE_PREBIND is currently the only valid value.
SocketState state = 6 [(validate.rules).enum = {defined_only: true}];

// The socket type (see man 2 socket) to apply the socket option to. If
// this field is not specified, the option will be applied irrespective
// of the socket type.
SocketType type = 7 [(validate.rules).enum = {defined_only: true}];
}

message SocketOptionsOverride {
Expand Down
4 changes: 4 additions & 0 deletions changelogs/current.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,10 @@ new_features:
QUIC stream reset error code will be added to transport failure reason.
This behavior can be reverted by setting the runtime flag ``envoy.reloadable_features.report_stream_reset_error_code``
to ``false``.
- area: sockets
change: |
Added socket ``type`` field for specifying a socket type to apply the socket option to under :ref:`SocketOption
<envoy.config.core.v3.SocketOption>`.
deprecated:
- area: tracing
Expand Down
9 changes: 8 additions & 1 deletion source/common/network/socket_option_factory.cc
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,19 @@ std::unique_ptr<Socket::Options> SocketOptionFactory::buildLiteralOptions(
socket_option.DebugString());
continue;
}

absl::optional<Network::Socket::Type> socket_type = absl::nullopt;
if (socket_option.type() == envoy::config::core::v3::SocketOption::STREAM) {
socket_type = Network::Socket::Type::Stream;
} else if (socket_option.type() == envoy::config::core::v3::SocketOption::DATAGRAM) {
socket_type = Network::Socket::Type::Datagram;
}
options->emplace_back(std::make_shared<Network::SocketOptionImpl>(
socket_option.state(),
Network::SocketOptionName(
socket_option.level(), socket_option.name(),
fmt::format("{}/{}", socket_option.level(), socket_option.name())),
buf));
buf, socket_type));
}
return options;
}
Expand Down
2 changes: 2 additions & 0 deletions source/common/network/socket_option_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ SocketOptionImpl::getOptionDetails(const Socket&,

bool SocketOptionImpl::isSupported() const { return optname_.hasValue(); }

absl::optional<Socket::Type> SocketOptionImpl::socketType() const { return socket_type_; }

Api::SysCallIntResult SocketOptionImpl::setSocketOption(Socket& socket,
const Network::SocketOptionName& optname,
const void* value, size_t size) {
Expand Down
8 changes: 8 additions & 0 deletions source/common/network/socket_option_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ class SocketOptionImpl : public Socket::Option, Logger::Loggable<Logger::Id::con
envoy::config::core::v3::SocketOption::SocketState state) const override;
bool isSupported() const override;

/**
* Gets the socket type for this socket option. Empty means, the socket option is not specific to
* a particular socket type.
*
* @return the socket type
*/
absl::optional<Network::Socket::Type> socketType() const;

/**
* Set the option on the given socket.
* @param socket the socket on which to apply the option.
Expand Down
50 changes: 49 additions & 1 deletion test/common/network/socket_option_factory_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ TEST_F(SocketOptionFactoryTest, TestBuildLiteralOptions) {
auto linger_option =
absl::StrFormat(linger_option_format, SOL_SOCKET, SO_LINGER, linger_bstr_formatted);
ASSERT_TRUE(parser.ParseFromString(linger_option, &socket_option_proto));

*socket_options_proto.Add() = socket_option_proto;
static const char keepalive_option_format[] = R"proto(
state: STATE_PREBIND
Expand All @@ -159,8 +160,44 @@ TEST_F(SocketOptionFactoryTest, TestBuildLiteralOptions) {
ASSERT_TRUE(parser.ParseFromString(keepalive_option, &socket_option_proto));
*socket_options_proto.Add() = socket_option_proto;

static const char all_socket_type_option_format[] = R"proto(
state: STATE_PREBIND
level: %d
name: %d
int_value: 1
type: ALL
)proto";
auto all_socket_type_option =
absl::StrFormat(all_socket_type_option_format, SOL_SOCKET, SO_KEEPALIVE);
ASSERT_TRUE(parser.ParseFromString(all_socket_type_option, &socket_option_proto));
*socket_options_proto.Add() = socket_option_proto;

static const char stream_socket_type_option_format[] = R"proto(
state: STATE_PREBIND
level: %d
name: %d
int_value: 1
type: STREAM
)proto";
auto stream_socket_type_option =
absl::StrFormat(stream_socket_type_option_format, SOL_SOCKET, SO_KEEPALIVE);
ASSERT_TRUE(parser.ParseFromString(stream_socket_type_option, &socket_option_proto));
*socket_options_proto.Add() = socket_option_proto;

static const char datagram_socket_type_option_format[] = R"proto(
state: STATE_PREBIND
level: %d
name: %d
int_value: 1
type: DATAGRAM
)proto";
auto datagram_socket_type_option =
absl::StrFormat(datagram_socket_type_option_format, SOL_SOCKET, SO_KEEPALIVE);
ASSERT_TRUE(parser.ParseFromString(datagram_socket_type_option, &socket_option_proto));
*socket_options_proto.Add() = socket_option_proto;

auto socket_options = SocketOptionFactory::buildLiteralOptions(socket_options_proto);
EXPECT_EQ(2, socket_options->size());
EXPECT_EQ(5, socket_options->size());
auto option_details = socket_options->at(0)->getOptionDetails(
socket_mock_, envoy::config::core::v3::SocketOption::STATE_PREBIND);
EXPECT_TRUE(option_details.has_value());
Expand All @@ -176,6 +213,17 @@ TEST_F(SocketOptionFactoryTest, TestBuildLiteralOptions) {
int value = 1;
absl::string_view value_bstr{reinterpret_cast<const char*>(&value), sizeof(int)};
EXPECT_EQ(value_bstr, option_details->value_);

auto none_socket_option = dynamic_pointer_cast<const SocketOptionImpl>(socket_options->at(2));
EXPECT_FALSE(none_socket_option->socketType().has_value());

auto stream_socket_option = dynamic_pointer_cast<const SocketOptionImpl>(socket_options->at(3));
EXPECT_TRUE(stream_socket_option->socketType().has_value());
EXPECT_EQ(Socket::Type::Stream, *stream_socket_option->socketType());

auto datagram_socket_option = dynamic_pointer_cast<const SocketOptionImpl>(socket_options->at(4));
EXPECT_TRUE(datagram_socket_option->socketType().has_value());
EXPECT_EQ(Socket::Type::Datagram, *datagram_socket_option->socketType());
}

TEST_F(SocketOptionFactoryTest, TestBuildZeroSoLingerOptions) {
Expand Down
20 changes: 20 additions & 0 deletions test/common/network/socket_option_impl_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ namespace Envoy {
namespace Network {
namespace {

using ::testing::Return;

class SocketOptionImplTest : public SocketOptionTest {};

TEST_F(SocketOptionImplTest, BadFd) {
Expand Down Expand Up @@ -59,6 +61,24 @@ TEST_F(SocketOptionImplTest, SetOptionSuccessTrue) {
socket_option.setOption(socket_, envoy::config::core::v3::SocketOption::STATE_PREBIND));
}

TEST_F(SocketOptionImplTest, SetDatagramOptionOnStreamSocketType) {
ON_CALL(socket_, socketType()).WillByDefault(Return(Socket::Type::Stream));
SocketOptionImpl socket_option{envoy::config::core::v3::SocketOption::STATE_PREBIND,
ENVOY_MAKE_SOCKET_OPTION_NAME(5, 10), 1, Socket::Type::Datagram};
EXPECT_CALL(socket_, setSocketOption(_, _, _, _)).Times(0);
EXPECT_TRUE(
socket_option.setOption(socket_, envoy::config::core::v3::SocketOption::STATE_PREBIND));
}

TEST_F(SocketOptionImplTest, SetStreamOptionOnDatagramSocketType) {
ON_CALL(socket_, socketType()).WillByDefault(Return(Socket::Type::Datagram));
SocketOptionImpl socket_option{envoy::config::core::v3::SocketOption::STATE_PREBIND,
ENVOY_MAKE_SOCKET_OPTION_NAME(5, 10), 1, Socket::Type::Stream};
EXPECT_CALL(socket_, setSocketOption(_, _, _, _)).Times(0);
EXPECT_TRUE(
socket_option.setOption(socket_, envoy::config::core::v3::SocketOption::STATE_PREBIND));
}

TEST_F(SocketOptionImplTest, GetOptionDetailsCorrectState) {
SocketOptionImpl socket_option{envoy::config::core::v3::SocketOption::STATE_PREBIND,
ENVOY_MAKE_SOCKET_OPTION_NAME(5, 10), 1};
Expand Down

0 comments on commit b64c697

Please sign in to comment.