Line data Source code
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 : : io_handle_(ioHandleForAddr(sock_type, address_for_io_handle, options)), 17 : connection_info_provider_( 18 : std::make_shared<ConnectionInfoSetterImpl>(nullptr, remote_address)), 19 515 : 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 : : io_handle_(std::move(io_handle)), 25 : connection_info_provider_( 26 : std::make_shared<ConnectionInfoSetterImpl>(local_address, remote_address)), 27 3504 : sock_type_(Network::Socket::Type::Stream) { 28 : 29 3504 : if (connection_info_provider_->localAddress() != nullptr) { 30 2176 : addr_type_ = connection_info_provider_->localAddress()->type(); 31 2176 : return; 32 2176 : } 33 : 34 1328 : if (connection_info_provider_->remoteAddress() != nullptr) { 35 1328 : addr_type_ = connection_info_provider_->remoteAddress()->type(); 36 1328 : return; 37 1328 : } 38 : 39 : // Should not happen but some tests inject -1 fds 40 0 : if (!io_handle_->isOpen()) { 41 0 : return; 42 0 : } 43 : 44 0 : auto domain = io_handle_->domain(); 45 : // This should never happen in practice but too many tests inject fake fds ... 46 0 : if (!domain.has_value()) { 47 0 : return; 48 0 : } 49 : 50 0 : addr_type_ = *domain == AF_UNIX ? Address::Type::Pipe : Address::Type::Ip; 51 0 : } 52 : 53 1317 : Api::SysCallIntResult SocketImpl::bind(Network::Address::InstanceConstSharedPtr address) { 54 1317 : Api::SysCallIntResult bind_result; 55 : 56 1317 : if (address->type() == Address::Type::Pipe) { 57 5 : const Address::Pipe* pipe = address->pipe(); 58 5 : const auto* pipe_sa = reinterpret_cast<const sockaddr_un*>(address->sockAddr()); 59 5 : bool abstract_namespace = address->pipe()->abstractNamespace(); 60 5 : if (!abstract_namespace) { 61 : // Try to unlink an existing filesystem object at the requested path. Ignore 62 : // errors -- it's fine if the path doesn't exist, and if it exists but can't 63 : // be unlinked then `::bind()` will generate a reasonable errno. 64 0 : unlink(pipe_sa->sun_path); 65 0 : } 66 : // Not storing a reference to syscalls singleton because of unit test mocks 67 5 : bind_result = io_handle_->bind(address); 68 5 : if (pipe->mode() != 0 && !abstract_namespace && bind_result.return_value_ == 0) { 69 0 : auto set_permissions = Api::OsSysCallsSingleton::get().chmod(pipe_sa->sun_path, pipe->mode()); 70 0 : if (set_permissions.return_value_ != 0) { 71 0 : throwEnvoyExceptionOrPanic(fmt::format("Failed to create socket with mode {}: {}", 72 0 : std::to_string(pipe->mode()), 73 0 : errorDetails(set_permissions.errno_))); 74 0 : } 75 0 : } 76 5 : return bind_result; 77 5 : } 78 : 79 1312 : bind_result = io_handle_->bind(address); 80 1312 : if (bind_result.return_value_ == 0 && address->ip()->port() == 0) { 81 797 : connection_info_provider_->setLocalAddress(io_handle_->localAddress()); 82 797 : } 83 1312 : return bind_result; 84 1317 : } 85 : 86 0 : Api::SysCallIntResult SocketImpl::listen(int backlog) { return io_handle_->listen(backlog); } 87 : 88 1328 : Api::SysCallIntResult SocketImpl::connect(const Network::Address::InstanceConstSharedPtr address) { 89 1328 : auto result = io_handle_->connect(address); 90 1328 : if (address->type() == Address::Type::Ip) { 91 1328 : connection_info_provider_->setLocalAddress(io_handle_->localAddress()); 92 1328 : } 93 1328 : return result; 94 1328 : } 95 : 96 : Api::SysCallIntResult SocketImpl::setSocketOption(int level, int optname, const void* optval, 97 3443 : socklen_t optlen) { 98 3443 : return io_handle_->setOption(level, optname, optval, optlen); 99 3443 : } 100 : 101 : Api::SysCallIntResult SocketImpl::getSocketOption(int level, int optname, void* optval, 102 1178 : socklen_t* optlen) const { 103 1178 : return io_handle_->getOption(level, optname, optval, optlen); 104 1178 : } 105 : 106 : Api::SysCallIntResult SocketImpl::ioctl(unsigned long control_code, void* in_buffer, 107 : unsigned long in_buffer_len, void* out_buffer, 108 : unsigned long out_buffer_len, 109 0 : unsigned long* bytes_returned) { 110 0 : return io_handle_->ioctl(control_code, in_buffer, in_buffer_len, out_buffer, out_buffer_len, 111 0 : bytes_returned); 112 0 : } 113 : 114 91 : Api::SysCallIntResult SocketImpl::setBlockingForTest(bool blocking) { 115 91 : return io_handle_->setBlocking(blocking); 116 91 : } 117 : 118 1212 : absl::optional<Address::IpVersion> SocketImpl::ipVersion() const { 119 1212 : if (addr_type_ == Address::Type::Ip) { 120 : // Always hit after socket is initialized, i.e., accepted or connected 121 1212 : if (connection_info_provider_->localAddress() != nullptr) { 122 1212 : return connection_info_provider_->localAddress()->ip()->version(); 123 1212 : } else { 124 0 : auto domain = io_handle_->domain(); 125 0 : if (!domain.has_value()) { 126 0 : return absl::nullopt; 127 0 : } 128 0 : if (*domain == AF_INET) { 129 0 : return Address::IpVersion::v4; 130 0 : } else if (*domain == AF_INET6) { 131 0 : return Address::IpVersion::v6; 132 0 : } else { 133 0 : return absl::nullopt; 134 0 : } 135 0 : } 136 1212 : } 137 0 : return absl::nullopt; 138 1212 : } 139 : 140 : } // namespace Network 141 : } // namespace Envoy