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

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

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

            
13
namespace Envoy {
14
namespace Network {
15

            
16
// Socket::Option
17
bool SocketOptionImpl::setOption(Socket& socket,
18
92447
                                 envoy::config::core::v3::SocketOption::SocketState state) const {
19
92447
  if (!in_state_.has_value() || in_state_ == state) {
20
34990
    if (!optname_.hasValue()) {
21
2
      ENVOY_LOG(warn, "Failed to set unsupported option on socket");
22
2
      return false;
23
2
    }
24

            
25
34988
    if (socket_type_.has_value() && *socket_type_ != socket.socketType()) {
26
6
      ENVOY_LOG(info, "Skipping inapplicable socket option {}", optname_.name());
27
6
      return true;
28
6
    }
29

            
30
34982
    if (socket_ip_version_.has_value() && socket.ipVersion().has_value() &&
31
34982
        *socket_ip_version_ != *socket.ipVersion()) {
32
1
      ENVOY_LOG(info, "Skipping inapplicable socket option {}, because of IP version mismatch",
33
1
                optname_.name());
34
1
      return true;
35
1
    }
36

            
37
34981
    const Api::SysCallIntResult result =
38
34981
        SocketOptionImpl::setSocketOption(socket, optname_, value_.data(), value_.size());
39
34981
    if (result.return_value_ != 0) {
40
9
      ENVOY_LOG(warn, "Setting {} option on socket failed: {}", optname_.name(),
41
9
                errorDetails(result.errno_));
42
9
      return false;
43
9
    }
44
34981
  }
45

            
46
92429
  return true;
47
92447
}
48

            
49
26
void SocketOptionImpl::hashKey(std::vector<uint8_t>& hash_key) const {
50
26
  if (optname_.hasValue()) {
51
26
    pushScalarToByteVector(optname_.level(), hash_key);
52
26
    pushScalarToByteVector(optname_.option(), hash_key);
53
26
    hash_key.insert(hash_key.end(), value_.begin(), value_.end());
54
26
  }
55
26
}
56

            
57
absl::optional<Socket::Option::Details>
58
SocketOptionImpl::getOptionDetails(const Socket&,
59
35
                                   envoy::config::core::v3::SocketOption::SocketState state) const {
60
35
  if ((in_state_.has_value() && state != in_state_) || !isSupported()) {
61
9
    return absl::nullopt;
62
9
  }
63

            
64
26
  Socket::Option::Details info;
65
26
  info.name_ = optname_;
66
26
  info.value_ = {value_.begin(), value_.end()};
67
26
  return absl::make_optional(std::move(info));
68
35
}
69

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

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

            
74
4
absl::optional<Address::IpVersion> SocketOptionImpl::socketIpVersion() const {
75
4
  return socket_ip_version_;
76
4
}
77

            
78
Api::SysCallIntResult SocketOptionImpl::setSocketOption(Socket& socket,
79
                                                        const Network::SocketOptionName& optname,
80
34984
                                                        const void* value, size_t size) {
81
34984
  if (!optname.hasValue()) {
82
1
    return {-1, SOCKET_ERROR_NOT_SUP};
83
1
  }
84

            
85
34983
  return socket.setSocketOption(optname.level(), optname.option(), value, size);
86
34984
}
87

            
88
} // namespace Network
89
} // namespace Envoy