// SPDX-License-Identifier: BSD-2-Clause // author: Max Kellermann #pragma once #include "SocketAddress.hxx" #include #include #ifdef _WIN32 #include // IWYU pragma: export #else #include // IWYU pragma: export #endif constexpr struct addrinfo MakeAddrInfo(int flags, int family, int socktype, int protocol=0) noexcept { struct addrinfo ai{}; ai.ai_flags = flags; ai.ai_family = family; ai.ai_socktype = socktype; ai.ai_protocol = protocol; return ai; } class AddressInfo : addrinfo { /* this class cannot be instantiated, it can only be cast from a struct addrinfo pointer */ AddressInfo() = delete; ~AddressInfo() = delete; public: constexpr int GetFamily() const noexcept { return ai_family; } constexpr int GetType() const noexcept { return ai_socktype; } constexpr int GetProtocol() const noexcept { return ai_protocol; } constexpr bool IsInet() const noexcept { return ai_family == AF_INET || ai_family == AF_INET6; } constexpr bool IsTCP() const noexcept { return IsInet() && GetType() == SOCK_STREAM; } constexpr operator SocketAddress() const noexcept { return {ai_addr, (SocketAddress::size_type)ai_addrlen}; } /** * Cast a #addrinfo reference to an #AddressInfo reference. */ static constexpr const AddressInfo &Cast(const struct addrinfo &ai) noexcept { return static_cast(ai); } }; class AddressInfoList { struct addrinfo *value = nullptr; public: AddressInfoList() = default; explicit AddressInfoList(struct addrinfo *_value) noexcept :value(_value) {} AddressInfoList(AddressInfoList &&src) noexcept :value(std::exchange(src.value, nullptr)) {} ~AddressInfoList() noexcept { freeaddrinfo(value); } AddressInfoList &operator=(AddressInfoList &&src) noexcept { std::swap(value, src.value); return *this; } bool empty() const noexcept { return value == nullptr; } const AddressInfo &front() const noexcept { return *(const AddressInfo *)value; } /** * Pick the best address from the list, e.g. prefer IPv6 over * IPv4 (if both are available). We do this because binding * to an IPv6 wildcard address also allows accepting IPv4 * connections. */ [[gnu::pure]] const AddressInfo &GetBest() const noexcept; class const_iterator { struct addrinfo *cursor; public: using iterator_category = std::forward_iterator_tag; using value_type = AddressInfo; using difference_type = std::ptrdiff_t; using pointer = const value_type *; using reference = const value_type &; explicit constexpr const_iterator(struct addrinfo *_cursor) noexcept :cursor(_cursor) {} constexpr bool operator==(const_iterator other) const noexcept { return cursor == other.cursor; } const_iterator &operator++() noexcept { cursor = cursor->ai_next; return *this; } constexpr const AddressInfo &operator*() const noexcept { return *(const AddressInfo *)cursor; } constexpr const AddressInfo *operator->() const noexcept { return (const AddressInfo *)cursor; } }; const_iterator begin() const noexcept { return const_iterator(value); } const_iterator end() const noexcept { return const_iterator(nullptr); } };