1
#pragma once
2

            
3
#include "envoy/common/platform.h"
4
#include "envoy/config/core/v3/base.pb.h"
5
#include "envoy/network/listen_socket.h"
6

            
7
#include "source/common/common/logger.h"
8
#include "source/common/network/socket_option_impl.h"
9

            
10
#include "absl/types/optional.h"
11

            
12
namespace Envoy {
13
namespace Network {
14

            
15
class AddrFamilyAwareSocketOptionImpl : public Socket::Option,
16
                                        Logger::Loggable<Logger::Id::connection> {
17
public:
18
  AddrFamilyAwareSocketOptionImpl(envoy::config::core::v3::SocketOption::SocketState in_state,
19
                                  SocketOptionName ipv4_optname, SocketOptionName ipv6_optname,
20
                                  int value)
21
8810
      : AddrFamilyAwareSocketOptionImpl(in_state, ipv4_optname, value, ipv6_optname, value) {}
22
  AddrFamilyAwareSocketOptionImpl(envoy::config::core::v3::SocketOption::SocketState in_state,
23
                                  SocketOptionName ipv4_optname, int ipv4_value,
24
                                  SocketOptionName ipv6_optname, int ipv6_value)
25
13170
      : ipv4_option_(std::make_unique<SocketOptionImpl>(in_state, ipv4_optname, ipv4_value)),
26
13170
        ipv6_option_(std::make_unique<SocketOptionImpl>(in_state, ipv6_optname, ipv6_value)) {}
27
  AddrFamilyAwareSocketOptionImpl(envoy::config::core::v3::SocketOption::SocketState in_state,
28
                                  SocketOptionName ipv4_optname, absl::string_view ipv4_value,
29
                                  SocketOptionName ipv6_optname, absl::string_view ipv6_value)
30
1
      : ipv4_option_(std::make_unique<SocketOptionImpl>(in_state, ipv4_optname, ipv4_value)),
31
1
        ipv6_option_(std::make_unique<SocketOptionImpl>(in_state, ipv6_optname, ipv6_value)) {}
32
  AddrFamilyAwareSocketOptionImpl(Socket::OptionConstPtr&& ipv4_option,
33
                                  Socket::OptionConstPtr&& ipv6_option)
34
1
      : ipv4_option_(std::move(ipv4_option)), ipv6_option_(std::move(ipv6_option)) {}
35

            
36
  // Socket::Option
37
  bool setOption(Socket& socket,
38
                 envoy::config::core::v3::SocketOption::SocketState state) const override;
39
8
  void hashKey(std::vector<uint8_t>& hash_key) const override {
40
    // Add both sub-options to the hash.
41
8
    ipv4_option_->hashKey(hash_key);
42
8
    ipv6_option_->hashKey(hash_key);
43
8
  }
44
  absl::optional<Details>
45
  getOptionDetails(const Socket& socket,
46
                   envoy::config::core::v3::SocketOption::SocketState state) const override;
47
1
  bool isSupported() const override { return true; }
48

            
49
  /**
50
   * Set a socket option that applies at both IPv4 and IPv6 socket levels. When the underlying FD
51
   * is IPv6, this function will attempt to set at IPv6 unless the platform only supports the
52
   * option at the IPv4 level.
53
   * @param socket.
54
   * @param ipv4_optname SocketOptionName for IPv4 level. Set to empty if not supported on
55
   * platform.
56
   * @param ipv6_optname SocketOptionName for IPv6 level. Set to empty if not supported on
57
   * platform.
58
   * @param optval as per setsockopt(2).
59
   * @param optlen as per setsockopt(2).
60
   * @return int as per setsockopt(2). `ENOTSUP` is returned if the option is not supported on the
61
   * platform for fd after the above option level fallback semantics are taken into account or the
62
   *         socket is non-IP.
63
   */
64
  static bool setIpSocketOption(Socket& socket,
65
                                envoy::config::core::v3::SocketOption::SocketState state,
66
                                const Socket::Option& ipv4_option,
67
                                const Socket::Option& ipv6_option);
68

            
69
private:
70
  const Socket::OptionConstPtr ipv4_option_;
71
  const Socket::OptionConstPtr ipv6_option_;
72
};
73

            
74
} // namespace Network
75
} // namespace Envoy