1
#include "source/common/network/addr_family_aware_socket_option_impl.h"
2

            
3
#include "envoy/common/exception.h"
4
#include "envoy/common/optref.h"
5
#include "envoy/config/core/v3/base.pb.h"
6

            
7
#include "source/common/api/os_sys_calls_impl.h"
8
#include "source/common/common/assert.h"
9
#include "source/common/network/address_impl.h"
10
#include "source/common/network/socket_option_impl.h"
11

            
12
namespace Envoy {
13
namespace Network {
14

            
15
namespace {
16

            
17
OptRef<const Socket::Option> getOptionForSocket(const Socket& socket,
18
                                                const Socket::Option& ipv4_option,
19
34716
                                                const Socket::Option& ipv6_option) {
20
34716
  auto version = socket.ipVersion();
21
34716
  if (!version.has_value()) {
22
2
    return {};
23
2
  }
24

            
25
  // If the FD is v4, we can only try the IPv4 variant.
26
34714
  if (*version == Network::Address::IpVersion::v4) {
27
34381
    return {ipv4_option};
28
34381
  }
29
  // If the FD is v6, we first try the IPv6 variant if the platform supports it and fallback to the
30
  // IPv4 variant otherwise.
31
333
  ASSERT(*version == Network::Address::IpVersion::v6);
32
333
  if (ipv6_option.isSupported()) {
33
330
    return {ipv6_option};
34
330
  }
35
3
  return {ipv4_option};
36
333
}
37

            
38
} // namespace
39

            
40
bool AddrFamilyAwareSocketOptionImpl::setOption(
41
34696
    Socket& socket, envoy::config::core::v3::SocketOption::SocketState state) const {
42
34696
  return setIpSocketOption(socket, state, *ipv4_option_, *ipv6_option_);
43
34696
}
44

            
45
absl::optional<Socket::Option::Details> AddrFamilyAwareSocketOptionImpl::getOptionDetails(
46
20
    const Socket& socket, envoy::config::core::v3::SocketOption::SocketState state) const {
47
20
  auto option = getOptionForSocket(socket, *ipv4_option_, *ipv6_option_);
48

            
49
20
  if (!option.has_value()) {
50
1
    return absl::nullopt;
51
1
  }
52

            
53
19
  return option.value().get().getOptionDetails(socket, state);
54
20
}
55

            
56
bool AddrFamilyAwareSocketOptionImpl::setIpSocketOption(
57
    Socket& socket, envoy::config::core::v3::SocketOption::SocketState state,
58
34696
    const Socket::Option& ipv4_option, const Socket::Option& ipv6_option) {
59
34696
  auto option = getOptionForSocket(socket, ipv4_option, ipv6_option);
60

            
61
34696
  if (!option.has_value()) {
62
1
    ENVOY_LOG(warn, "Failed to set IP socket option on non-IP socket");
63
1
    return false;
64
1
  }
65

            
66
34695
  return option.value().get().setOption(socket, state);
67
34696
}
68

            
69
} // namespace Network
70
} // namespace Envoy