Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-17 08:39:19

0001 //
0002 // Copyright (c) 2025 Klemens Morgenstern (klemens.morgenstern@gmx.net)
0003 //
0004 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0005 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
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   // for the asio acceptor
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 //BOOST_COBALT_IO_ENDPOINT_HPP