File indexing completed on 2026-08-17 08:39:19
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef BOOST_COBALT_IO_ENDPOINT_HPP
0009 #define BOOST_COBALT_IO_ENDPOINT_HPP
0010
0011 #include <boost/cobalt/io/detail/config.hpp>
0012 #include <boost/cobalt/config.hpp>
0013 #include <boost/cobalt/detail/exception.hpp>
0014
0015 #include <boost/asio/detail/socket_types.hpp>
0016 #include <boost/endian/conversion.hpp>
0017 #include <boost/static_string.hpp>
0018 #include <boost/system/result.hpp>
0019
0020 #include <array>
0021 #include <algorithm>
0022
0023 #if defined(BOOST_COBALT_NO_PMR)
0024 #include <boost/container/pmr/vector.hpp>
0025 #else
0026 #include <vector>
0027 #endif
0028
0029 #include <span>
0030
0031 namespace boost::cobalt::detail
0032 {
0033
0034 BOOST_COBALT_IO_DECL BOOST_NORETURN void
0035 throw_bad_endpoint_access(
0036 boost::source_location const& loc);
0037
0038 }
0039
0040 namespace boost::cobalt::io
0041 {
0042
0043 struct endpoint;
0044 struct stream_socket;
0045
0046
0047 #if __GNUC__ && !defined(__clang__)
0048 #pragma GCC diagnostic push
0049 #pragma GCC diagnostic ignored "-Wsubobject-linkage"
0050 #endif
0051
0052 struct protocol_type
0053 {
0054 using family_t = int;
0055 using type_t = int;
0056 using protocol_t = int;
0057
0058 constexpr family_t family() const noexcept {return family_;};
0059 constexpr type_t type() const noexcept {return type_;};
0060 constexpr protocol_t protocol() const noexcept {return protocol_;};
0061
0062 constexpr explicit
0063 protocol_type(family_t family = static_cast<family_t>(0),
0064 type_t type = static_cast<type_t>(0),
0065 protocol_t protocol = static_cast<protocol_t>(0)) noexcept
0066 : family_(family), type_(type), protocol_(protocol)
0067 {}
0068
0069 template<typename OtherProtocol>
0070 requires requires (const OtherProtocol & op)
0071 {
0072 {static_cast<family_t>(op.family())};
0073 {static_cast<type_t>(op.type())};
0074 {static_cast<protocol_t>(op.protocol())};
0075 }
0076 constexpr protocol_type(const OtherProtocol & op) noexcept
0077 : family_(static_cast<family_t>(op.family()))
0078 , type_(static_cast<type_t>(op.type()))
0079 , protocol_(static_cast<protocol_t>(op.protocol()))
0080 {}
0081
0082 friend
0083 constexpr auto operator<=>(const protocol_type & , const protocol_type &) noexcept = default;
0084
0085 using endpoint = io::endpoint;
0086
0087 using socket = stream_socket;
0088 private:
0089 family_t family_ = static_cast<family_t>(0);
0090 type_t type_ = static_cast<type_t>(0);
0091 protocol_t protocol_ = static_cast<protocol_t>(0);
0092 };
0093
0094 template<protocol_type::family_t Family = static_cast<protocol_type::family_t>(0),
0095 protocol_type::type_t Type = static_cast<protocol_type::type_t>(0),
0096 protocol_type::protocol_t Protocol = static_cast<protocol_type::protocol_t>(0)>
0097 struct static_protocol
0098 {
0099 using family_t = protocol_type::family_t ;
0100 using type_t = protocol_type::type_t ;
0101 using protocol_t = protocol_type::protocol_t;
0102
0103 constexpr family_t family() const noexcept {return family_t(Family); };
0104 constexpr type_t type() const noexcept {return type_t(Type); };
0105 constexpr protocol_t protocol() const noexcept {return protocol_t(Protocol); };
0106
0107 using endpoint = io::endpoint;
0108 };
0109
0110
0111 constexpr static_protocol<BOOST_ASIO_OS_DEF(AF_UNSPEC), static_cast<protocol_type::type_t>(0), BOOST_ASIO_OS_DEF(IPPROTO_IP)> ip {};
0112 constexpr static_protocol<BOOST_ASIO_OS_DEF(AF_INET), static_cast<protocol_type::type_t>(0), BOOST_ASIO_OS_DEF(IPPROTO_IP)> ip_v4 {};
0113 constexpr static_protocol<BOOST_ASIO_OS_DEF(AF_INET6), static_cast<protocol_type::type_t>(0), BOOST_ASIO_OS_DEF(IPPROTO_IP)> ip_v6 {};
0114 constexpr static_protocol<BOOST_ASIO_OS_DEF(AF_UNSPEC), BOOST_ASIO_OS_DEF(SOCK_STREAM), BOOST_ASIO_OS_DEF(IPPROTO_TCP)> tcp {};
0115 constexpr static_protocol<BOOST_ASIO_OS_DEF(AF_INET), BOOST_ASIO_OS_DEF(SOCK_STREAM), BOOST_ASIO_OS_DEF(IPPROTO_TCP)> tcp_v4{};
0116 constexpr static_protocol<BOOST_ASIO_OS_DEF(AF_INET6), BOOST_ASIO_OS_DEF(SOCK_STREAM), BOOST_ASIO_OS_DEF(IPPROTO_TCP)> tcp_v6{};
0117 constexpr static_protocol<BOOST_ASIO_OS_DEF(AF_UNSPEC), BOOST_ASIO_OS_DEF(SOCK_DGRAM), BOOST_ASIO_OS_DEF(IPPROTO_UDP)> udp {};
0118 constexpr static_protocol<BOOST_ASIO_OS_DEF(AF_INET), BOOST_ASIO_OS_DEF(SOCK_DGRAM), BOOST_ASIO_OS_DEF(IPPROTO_UDP)> udp_v4{};
0119 constexpr static_protocol<BOOST_ASIO_OS_DEF(AF_INET6), BOOST_ASIO_OS_DEF(SOCK_DGRAM), BOOST_ASIO_OS_DEF(IPPROTO_ICMP)> udp_v6{};
0120 constexpr static_protocol<BOOST_ASIO_OS_DEF(AF_UNSPEC), BOOST_ASIO_OS_DEF(SOCK_DGRAM), BOOST_ASIO_OS_DEF(IPPROTO_ICMP)> icmp {};
0121 constexpr static_protocol<AF_UNIX, BOOST_ASIO_OS_DEF(SOCK_STREAM)> local_stream {};
0122 constexpr static_protocol<AF_UNIX, BOOST_ASIO_OS_DEF(SOCK_DGRAM)> local_datagram {};
0123 constexpr static_protocol<AF_UNIX, BOOST_ASIO_OS_DEF(SOCK_SEQPACKET)> local_seqpacket{};
0124 constexpr static_protocol<AF_UNIX> local_protocol {};
0125
0126 #if defined(IPPROTO_SCTP)
0127 constexpr static_protocol<BOOST_ASIO_OS_DEF(AF_UNSPEC), BOOST_ASIO_OS_DEF(SOCK_SEQPACKET), IPPROTO_SCTP> sctp {};
0128 constexpr static_protocol<BOOST_ASIO_OS_DEF(AF_INET), BOOST_ASIO_OS_DEF(SOCK_SEQPACKET), IPPROTO_SCTP> sctp_v4{};
0129 constexpr static_protocol<BOOST_ASIO_OS_DEF(AF_INET6), BOOST_ASIO_OS_DEF(SOCK_SEQPACKET), IPPROTO_SCTP> sctp_v6{};
0130 #endif
0131
0132 template<protocol_type::family_t Family>
0133 struct make_endpoint_tag {};
0134
0135 template<protocol_type::family_t Family>
0136 struct get_endpoint_tag {};
0137
0138 struct endpoint
0139 {
0140 using storage_type = asio::detail::sockaddr_storage_type;
0141 using addr_type = asio::detail::socket_addr_type;
0142 void resize(std::size_t size)
0143 {
0144 BOOST_ASSERT(size < sizeof(storage_));
0145 size_ = size;
0146 }
0147
0148 void * data() {return &storage_; }
0149 const void * data() const {return &storage_; }
0150 std::size_t size() const {return size_;}
0151 std::size_t capacity() const {return sizeof(storage_);}
0152
0153 void set_type (protocol_type::type_t type) { type_ = type;}
0154 void set_protocol(protocol_type::protocol_t protocol) { protocol_ = protocol;}
0155
0156 protocol_type protocol() const
0157 {
0158 return protocol_type{static_cast<protocol_type::family_t>(base_.sa_family), type_, protocol_};
0159 }
0160
0161 endpoint() = default;
0162 endpoint(const endpoint & ep) : storage_(ep.storage_), size_(ep.size_), protocol_(ep.protocol_), type_(ep.type_)
0163 {
0164 }
0165
0166 template<protocol_type::family_t Family,
0167 protocol_type::type_t Type,
0168 protocol_type::protocol_t Protocol,
0169 typename ... Args>
0170 requires requires (make_endpoint_tag<Family> proto,
0171 addr_type* addr, Args && ... args)
0172 {
0173 {tag_invoke(proto, addr, std::forward<Args>(args)...)} -> std::convertible_to<std::size_t>;
0174 }
0175 endpoint(static_protocol<Family, Type, Protocol> proto, Args && ... args)
0176 : base_{},
0177 protocol_(Protocol), type_(Type)
0178 {
0179 size_ = tag_invoke(make_endpoint_tag<Family>{}, &base_, std::forward<Args>(args)...);
0180 }
0181
0182 template<typename OtherEndpoint>
0183 requires requires (OtherEndpoint oe)
0184 {
0185 {oe.protocol()} -> std::convertible_to<protocol_type>;
0186 {oe.data()} -> std::convertible_to<void*>;
0187 {oe.size()} -> std::convertible_to<std::size_t>;
0188 }
0189 endpoint(OtherEndpoint && oe) :
0190 base_{},
0191 protocol_(static_cast<protocol_type::protocol_t>(oe.protocol().protocol())),
0192 type_(static_cast<protocol_type::type_t>(oe.protocol().type()))
0193 {
0194 resize(oe.size());
0195 memcpy(data(), oe.data(), size());
0196 }
0197
0198 template<static_protocol Protocol>
0199 requires requires (get_endpoint_tag<Protocol.family()> tag,
0200 protocol_type actual,
0201 const addr_type * addr) {{tag_invoke(tag, actual, addr)};}
0202 friend auto get_if(const endpoint * ep)
0203 -> decltype(tag_invoke(get_endpoint_tag<Protocol.family()>{}, protocol_type{},
0204 static_cast<const addr_type *>(nullptr)))
0205 {
0206 const auto actual = ep->protocol();
0207 if (Protocol.type() != 0 && actual.type() != 0 && actual.type() != Protocol.type())
0208 return nullptr;
0209 if (Protocol.protocol() != 0 && actual.protocol() != 0 && actual.protocol() != Protocol.protocol())
0210 return nullptr;
0211 return tag_invoke(get_endpoint_tag<Protocol.family()>{}, ep->protocol(), &ep->base_);
0212 }
0213
0214 private:
0215 union {
0216 asio::detail::socket_addr_type base_{};
0217 storage_type storage_;
0218 };
0219 std::size_t size_{sizeof(base_)};
0220 protocol_type::protocol_t protocol_ = static_cast<protocol_type::protocol_t>(0);
0221 protocol_type::type_t type_ = static_cast<protocol_type::type_t>(0);
0222 };
0223
0224 #if __GNUC__ && !defined(__clang__)
0225 #pragma GCC diagnostic pop
0226 #endif
0227
0228 #if defined(BOOST_COBALT_NO_PMR)
0229 using endpoint_sequence = std::vector<endpoint>;
0230 #else
0231 using endpoint_sequence = pmr::vector<endpoint>;
0232 #endif
0233
0234
0235 class bad_endpoint_access : public std::exception
0236 {
0237 public:
0238
0239 bad_endpoint_access() noexcept = default;
0240
0241 char const * what() const noexcept
0242 {
0243 return "bad_endpoint_access";
0244 }
0245 };
0246
0247 template<static_protocol Protocol>
0248 requires requires (get_endpoint_tag<Protocol.family()> tag,
0249 protocol_type actual,
0250 endpoint::addr_type * addr) {{tag_invoke(tag, actual, addr)};}
0251 auto get(const endpoint & ep, const boost::source_location & loc = BOOST_CURRENT_LOCATION)
0252 {
0253 auto e = get_if<Protocol>(&ep);
0254 if (!e)
0255 cobalt::detail::throw_bad_endpoint_access(loc);
0256 return *e;
0257 }
0258
0259 struct local_endpoint
0260 {
0261 std::string_view path() const { return unix_.sun_path;}
0262 private:
0263 union {
0264 asio::detail::sockaddr_storage_type addr_;
0265 asio::detail::sockaddr_un_type unix_;
0266 };
0267 };
0268
0269 BOOST_COBALT_IO_DECL
0270 std::size_t tag_invoke(make_endpoint_tag<AF_UNIX>,
0271 asio::detail::socket_addr_type* base,
0272 std::string_view sv);
0273
0274 BOOST_COBALT_IO_DECL
0275 const local_endpoint* tag_invoke(get_endpoint_tag<AF_UNIX>,
0276 protocol_type actual,
0277 const endpoint::addr_type * addr);
0278
0279 struct ip_address_v4
0280 {
0281 std::uint16_t port() const {return boost::endian::big_to_native(in_.sin_port);}
0282 std::uint32_t addr() const {return in_.sin_addr.s_addr;}
0283 BOOST_COBALT_IO_DECL boost::static_string<15> addr_str() const;
0284 private:
0285 union {
0286 asio::detail::sockaddr_storage_type addr_{};
0287 asio::detail::sockaddr_in4_type in_;
0288 };
0289 };
0290
0291 BOOST_COBALT_IO_DECL
0292 std::size_t tag_invoke(make_endpoint_tag<AF_INET>,
0293 asio::detail::socket_addr_type* base,
0294 std::uint32_t address,
0295 std::uint16_t port);
0296
0297 BOOST_COBALT_IO_DECL
0298 std::size_t tag_invoke(make_endpoint_tag<AF_INET>,
0299 asio::detail::socket_addr_type* base,
0300 std::string_view address,
0301 std::uint16_t port);
0302
0303 BOOST_COBALT_IO_DECL
0304 const ip_address_v4* tag_invoke(get_endpoint_tag<AF_INET>,
0305 protocol_type actual,
0306 const endpoint::addr_type * addr);
0307
0308
0309 struct ip_address_v6
0310 {
0311 std::uint16_t port() const {return boost::endian::big_to_native(in_.sin6_port);}
0312 std::array<std::uint8_t, 16u> addr() const
0313 {
0314 std::array<std::uint8_t, 16u> res;
0315 const auto & in = in_.sin6_addr.s6_addr;
0316 std::copy(std::begin(in), std::end(in), res.begin());
0317 return res;
0318 }
0319 BOOST_COBALT_IO_DECL boost::static_string<45> addr_str() const;
0320 private:
0321 union {
0322 asio::detail::sockaddr_storage_type addr_{};
0323 asio::detail::sockaddr_in6_type in_;
0324 };
0325 };
0326
0327 BOOST_COBALT_IO_DECL
0328 std::size_t tag_invoke(make_endpoint_tag<AF_INET6>,
0329 asio::detail::socket_addr_type* base,
0330 std::span<std::uint8_t, 16> address,
0331 std::uint16_t port);
0332
0333 BOOST_COBALT_IO_DECL
0334 std::size_t tag_invoke(make_endpoint_tag<AF_INET6>,
0335 asio::detail::socket_addr_type* base,
0336 std::string_view address,
0337 std::uint16_t port);
0338
0339 BOOST_COBALT_IO_DECL
0340 const ip_address_v6* tag_invoke(get_endpoint_tag<AF_INET6>,
0341 protocol_type actual,
0342 const endpoint::addr_type * addr);
0343
0344
0345 struct BOOST_SYMBOL_VISIBLE ip_address
0346 {
0347
0348 bool is_ipv6() const { return addr_.ss_family == BOOST_ASIO_OS_DEF(AF_INET6); }
0349 bool is_ipv4() const { return addr_.ss_family == BOOST_ASIO_OS_DEF(AF_INET); }
0350
0351 std::uint16_t port() const {return boost::endian::big_to_native(addr_.ss_family == AF_INET ? in_.sin_port : in6_.sin6_port);}
0352
0353 BOOST_COBALT_IO_DECL std::array<std::uint8_t, 16u> addr() const;
0354 BOOST_COBALT_IO_DECL boost::static_string<45> addr_str() const;
0355 private:
0356 union {
0357 asio::detail::sockaddr_storage_type addr_{};
0358 asio::detail::sockaddr_in4_type in_;
0359 asio::detail::sockaddr_in6_type in6_;
0360 };
0361 };
0362
0363 BOOST_COBALT_IO_DECL
0364 std::size_t tag_invoke(make_endpoint_tag<AF_UNSPEC>,
0365 asio::detail::socket_addr_type* base,
0366 std::string_view address,
0367 std::uint16_t port);
0368
0369 BOOST_COBALT_IO_DECL
0370 const ip_address* tag_invoke(get_endpoint_tag<AF_UNSPEC>,
0371 protocol_type actual,
0372 const endpoint::addr_type * addr);
0373
0374
0375 }
0376
0377 #endif