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

            
3
#include "envoy/common/exception.h"
4
#include "envoy/network/socket_interface.h"
5

            
6
#include "source/common/api/os_sys_calls_impl.h"
7
#include "source/common/common/utility.h"
8

            
9
namespace Envoy {
10
namespace Network {
11

            
12
SocketImpl::SocketImpl(Socket::Type sock_type,
13
                       const Address::InstanceConstSharedPtr& address_for_io_handle,
14
                       const Address::InstanceConstSharedPtr& remote_address,
15
                       const SocketCreationOptions& options)
16
3344
    : io_handle_(ioHandleForAddr(sock_type, address_for_io_handle, options)),
17
      connection_info_provider_(
18
3344
          std::make_shared<ConnectionInfoSetterImpl>(nullptr, remote_address)),
19
3344
      sock_type_(sock_type), addr_type_(address_for_io_handle->type()) {}
20

            
21
SocketImpl::SocketImpl(IoHandlePtr&& io_handle,
22
                       const Address::InstanceConstSharedPtr& local_address,
23
                       const Address::InstanceConstSharedPtr& remote_address)
24
156478
    : io_handle_(std::move(io_handle)),
25
      connection_info_provider_(
26
156478
          std::make_shared<ConnectionInfoSetterImpl>(local_address, remote_address)),
27
156478
      sock_type_(Network::Socket::Type::Stream) {
28

            
29
156478
  if (connection_info_provider_->localAddress() != nullptr) {
30
102789
    addr_type_ = connection_info_provider_->localAddress()->type();
31
102789
    return;
32
102789
  }
33

            
34
53689
  if (connection_info_provider_->remoteAddress() != nullptr) {
35
53640
    addr_type_ = connection_info_provider_->remoteAddress()->type();
36
53640
    return;
37
53640
  }
38

            
39
49
  if (!io_handle_) {
40
    // This can happen iff system socket creation fails.
41
    ENVOY_LOG_MISC(warn, "Created socket with null io handle");
42
    return;
43
  }
44

            
45
  // Should not happen but some tests inject -1 fds
46
49
  if (!io_handle_->isOpen()) {
47
2
    return;
48
2
  }
49

            
50
47
  auto domain = io_handle_->domain();
51
  // This should never happen in practice but too many tests inject fake fds ...
52
47
  if (!domain.has_value()) {
53
47
    return;
54
47
  }
55

            
56
  addr_type_ = *domain == AF_UNIX ? Address::Type::Pipe : Address::Type::Ip;
57
}
58

            
59
42400
Api::SysCallIntResult SocketImpl::bind(Network::Address::InstanceConstSharedPtr address) {
60
42400
  Api::SysCallIntResult bind_result;
61

            
62
42400
  if (address->type() == Address::Type::Pipe) {
63
53
    const Address::Pipe* pipe = address->pipe();
64
53
    const auto* pipe_sa = reinterpret_cast<const sockaddr_un*>(address->sockAddr());
65
53
    bool abstract_namespace = address->pipe()->abstractNamespace();
66
53
    if (!abstract_namespace) {
67
      // Try to unlink an existing filesystem object at the requested path. Ignore
68
      // errors -- it's fine if the path doesn't exist, and if it exists but can't
69
      // be unlinked then `::bind()` will generate a reasonable errno.
70
37
      unlink(pipe_sa->sun_path);
71
37
    }
72
    // Not storing a reference to syscalls singleton because of unit test mocks
73
53
    bind_result = io_handle_->bind(address);
74
53
    if (pipe->mode() != 0 && !abstract_namespace && bind_result.return_value_ == 0) {
75
9
      auto set_permissions = Api::OsSysCallsSingleton::get().chmod(pipe_sa->sun_path, pipe->mode());
76
9
      if (set_permissions.return_value_ != 0) {
77
1
        return set_permissions;
78
1
      }
79
9
    }
80
52
    return bind_result;
81
53
  }
82

            
83
42347
  bind_result = io_handle_->bind(address);
84
42347
  if (bind_result.return_value_ == 0 && address->ip()->port() == 0) {
85
41898
    auto address_or_error = io_handle_->localAddress();
86
41898
    if (!address_or_error.status().ok()) {
87
      return Api::SysCallIntResult{-1, HANDLE_ERROR_INVALID};
88
    }
89
41898
    connection_info_provider_->setLocalAddress(*address_or_error);
90
41898
  }
91
42347
  return bind_result;
92
42347
}
93

            
94
32
Api::SysCallIntResult SocketImpl::listen(int backlog) { return io_handle_->listen(backlog); }
95

            
96
56794
Api::SysCallIntResult SocketImpl::connect(const Network::Address::InstanceConstSharedPtr address) {
97
56794
  auto result = io_handle_->connect(address);
98
56794
  if (address->type() == Address::Type::Ip) {
99
56741
    auto address_or_error = io_handle_->localAddress();
100
56741
    if (!address_or_error.status().ok()) {
101
      return Api::SysCallIntResult{-1, HANDLE_ERROR_INVALID};
102
    }
103
56741
    connection_info_provider_->setLocalAddress(*address_or_error);
104
56741
  }
105
56794
  return result;
106
56794
}
107

            
108
Api::SysCallIntResult SocketImpl::setSocketOption(int level, int optname, const void* optval,
109
178168
                                                  socklen_t optlen) {
110
178168
  return io_handle_->setOption(level, optname, optval, optlen);
111
178168
}
112

            
113
Api::SysCallIntResult SocketImpl::getSocketOption(int level, int optname, void* optval,
114
53604
                                                  socklen_t* optlen) const {
115
53604
  return io_handle_->getOption(level, optname, optval, optlen);
116
53604
}
117

            
118
Api::SysCallIntResult SocketImpl::ioctl(unsigned long control_code, void* in_buffer,
119
                                        unsigned long in_buffer_len, void* out_buffer,
120
                                        unsigned long out_buffer_len,
121
                                        unsigned long* bytes_returned) {
122
  return io_handle_->ioctl(control_code, in_buffer, in_buffer_len, out_buffer, out_buffer_len,
123
                           bytes_returned);
124
}
125

            
126
159
Api::SysCallIntResult SocketImpl::setBlockingForTest(bool blocking) {
127
159
  return io_handle_->setBlocking(blocking);
128
159
}
129

            
130
43957
absl::optional<Address::IpVersion> SocketImpl::ipVersion() const {
131
43957
  if (addr_type_ == Address::Type::Ip) {
132
    // Always hit after socket is initialized, i.e., accepted or connected
133
43957
    if (connection_info_provider_->localAddress() != nullptr) {
134
43955
      return connection_info_provider_->localAddress()->ip()->version();
135
43956
    } else {
136
2
      auto domain = io_handle_->domain();
137
2
      if (!domain.has_value()) {
138
        return absl::nullopt;
139
      }
140
2
      if (*domain == AF_INET) {
141
2
        return Address::IpVersion::v4;
142
2
      } else if (*domain == AF_INET6) {
143
        return Address::IpVersion::v6;
144
      } else {
145
        return absl::nullopt;
146
      }
147
2
    }
148
43957
  }
149
  return absl::nullopt;
150
43957
}
151

            
152
} // namespace Network
153
} // namespace Envoy