[committed] libstdc++: Better preprocessor conditions in net::ip [PR 100286]

Jonathan Wakely jwakely@redhat.com
Tue Apr 27 13:10:19 GMT 2021


This improves the use of preprocessor conditionas to enable/disable
members of namespace net::ip according to what is supported by the
target. This fixes PR 100286 by ensuring that the to_string member
functions are always defined for the address_v4 and address_v6 classes.
On the other hand, the IP protocol classes and internet socket option
classes aren't useful at all if the corresponding constants (such as
IPPROTO_TCP or IPV6_MULTICAST_HOPS) aren't define. So those types are
not defined at all if they can't be used.

The net/internet/socket/opt.cc test uses __has_include to check whether
or not to expect the types to be available.

libstdc++-v3/ChangeLog:

	PR libstdc++/100286
	* include/experimental/internet (resolver_errc, resolver_category())
	(make_error_code, make_error_condition): Define unconditionally,
	only make enumerators and use of gai_strerror depend on the
	availability of <netdb.h>.
	(address_v4::to_string): Use correct constant for string length.
	(address_v4::to_string, address_v6::to_string): Define
	unconditionally, throw if unsupported.
	(make_address_v4, make_address_v6): Define unconditionally.
	Return an error if unsupported.
	(tcp, udp, v6_only, unicast::hops, multicast::*): Define
	conditionally,
	* testsuite/experimental/net/internet/socket/opt.cc: Check for
	<netinet/in.h> and <netinet/tcp.h> before using types from
	namespace net::ip.

Tested x86_64-linux. Committed to trunk.

-------------- next part --------------
commit 9ee35a8685ee174c6914059143aceb7009d3e920
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Tue Apr 27 13:06:43 2021

    libstdc++: Better preprocessor conditions in net::ip [PR 100286]
    
    This improves the use of preprocessor conditionas to enable/disable
    members of namespace net::ip according to what is supported by the
    target. This fixes PR 100286 by ensuring that the to_string member
    functions are always defined for the address_v4 and address_v6 classes.
    On the other hand, the IP protocol classes and internet socket option
    classes aren't useful at all if the corresponding constants (such as
    IPPROTO_TCP or IPV6_MULTICAST_HOPS) aren't define. So those types are
    not defined at all if they can't be used.
    
    The net/internet/socket/opt.cc test uses __has_include to check whether
    or not to expect the types to be available.
    
    libstdc++-v3/ChangeLog:
    
            PR libstdc++/100286
            * include/experimental/internet (resolver_errc, resolver_category())
            (make_error_code, make_error_condition): Define unconditionally,
            only make enumerators and use of gai_strerror depend on the
            availability of <netdb.h>.
            (address_v4::to_string): Use correct constant for string length.
            (address_v4::to_string, address_v6::to_string): Define
            unconditionally, throw if unsupported.
            (make_address_v4, make_address_v6): Define unconditionally.
            Return an error if unsupported.
            (tcp, udp, v6_only, unicast::hops, multicast::*): Define
            conditionally,
            * testsuite/experimental/net/internet/socket/opt.cc: Check for
            <netinet/in.h> and <netinet/tcp.h> before using types from
            namespace net::ip.

diff --git a/libstdc++-v3/include/experimental/internet b/libstdc++-v3/include/experimental/internet
index 11961762880..6c3fad6d2aa 100644
--- a/libstdc++-v3/include/experimental/internet
+++ b/libstdc++-v3/include/experimental/internet
@@ -72,20 +72,20 @@ inline namespace v1
 {
 namespace ip
 {
-
   /** @addtogroup networking-ts
    *  @{
    */
 
-#ifdef _GLIBCXX_HAVE_NETDB_H
   /** Error codes for resolver errors.
    * @{
    */
 
   enum class resolver_errc : int {
+#ifdef _GLIBCXX_HAVE_NETDB_H
     host_not_found = EAI_NONAME,
     host_not_found_try_again = EAI_AGAIN,
     service_not_found = EAI_SERVICE
+#endif
   };
 
   /// Error category for resolver errors.
@@ -94,7 +94,13 @@ namespace ip
     struct __cat : error_category
     {
       const char* name() const noexcept { return "resolver"; }
-      std::string message(int __e) const { return ::gai_strerror(__e); }
+      std::string message(int __e) const {
+#ifdef _GLIBCXX_HAVE_NETDB_H
+	  return ::gai_strerror(__e);
+#else
+	  return "name resolution requires <netdb.h>";
+#endif
+      }
       virtual void __message(int) { } // TODO dual ABI XXX
     };
     static __cat __c;
@@ -108,7 +114,6 @@ namespace ip
   { return error_condition(static_cast<int>(__e), resolver_category()); }
 
   /// @}
-#endif
 
   using port_type = uint_least16_t;	///< Type used for port numbers.
   using scope_id_type = uint_least32_t;	///< Type used for IPv6 scope IDs.
@@ -119,6 +124,16 @@ namespace ip
       = enable_if_t<std::is_same<typename _Alloc::value_type, char>::value,
 		    std::basic_string<char, std::char_traits<char>, _Alloc>>;
 
+  constexpr errc
+  __unsupported_err() noexcept
+  {
+#if defined EAFNOSUPPORT
+    return std::errc::address_family_not_supported;
+#else
+    return std::errc::operation_not_supported;
+#endif
+  }
+
   /** Tag indicating conversion between IPv4 and IPv4-mapped IPv6 addresses.
    * @{
    */
@@ -197,20 +212,22 @@ namespace ip
     constexpr uint_type
     to_uint() const noexcept { return _S_ntoh_32(_M_addr); }
 
-#ifdef _GLIBCXX_HAVE_ARPA_INET_H
     template<typename _Allocator = allocator<char>>
       __string_with<_Allocator>
       to_string(const _Allocator& __a = _Allocator()) const
       {
+#ifdef _GLIBCXX_HAVE_ARPA_INET_H
 	__string_with<_Allocator> __str(__a);
-	__str.resize(INET6_ADDRSTRLEN);
+	__str.resize(INET_ADDRSTRLEN);
 	if (inet_ntop(AF_INET, &_M_addr, &__str.front(), __str.size()))
 	  __str.erase(__str.find('\0'));
 	else
 	  __str.resize(0);
 	return __str;
-      }
+#else
+	std::__throw_system_error((int)__unsupported_err());
 #endif
+      }
 
     // static members:
     static constexpr address_v4 any() noexcept { return address_v4{}; }
@@ -338,11 +355,11 @@ namespace ip
 
     constexpr bytes_type to_bytes() const noexcept { return _M_bytes; }
 
-#ifdef _GLIBCXX_HAVE_ARPA_INET_H
     template<typename _Allocator = allocator<char>>
       __string_with<_Allocator>
       to_string(const _Allocator& __a = _Allocator()) const
       {
+#ifdef _GLIBCXX_HAVE_ARPA_INET_H
 	__string_with<_Allocator> __str(__a);
 	__str.resize(INET6_ADDRSTRLEN + (_M_scope_id ? 11 : 0));
 	char* const __p = &__str.front();
@@ -364,8 +381,10 @@ namespace ip
 	else
 	  __str.resize(0);
 	return __str;
-      }
+#else
+	std::__throw_system_error((int)__unsupported_err());
 #endif
+      }
 
     // static members:
 
@@ -650,6 +669,7 @@ namespace ip
   inline address_v4
   make_address_v4(const char* __str, error_code& __ec) noexcept
   {
+#ifdef _GLIBCXX_HAVE_ARPA_INET_H
     address_v4 __a;
     const int __res = ::inet_pton(AF_INET, __str, &__a._M_addr);
     if (__res == 1)
@@ -661,6 +681,9 @@ namespace ip
       __ec = std::make_error_code(std::errc::invalid_argument);
     else
       __ec.assign(errno, generic_category());
+#else
+    __ec = std::make_error_code(__unsupported_err());
+#endif
     return {};
   }
 
@@ -718,8 +741,9 @@ namespace ip
   inline address_v6
   __make_address_v6(const char* __addr, const char* __scope, error_code& __ec)
   {
+#ifdef _GLIBCXX_HAVE_ARPA_INET_H
     address_v6::bytes_type __b;
-    int __res = ::inet_pton(AF_INET6, __addr, __b.data());
+    const int __res = ::inet_pton(AF_INET6, __addr, __b.data());
     if (__res == 1)
       {
 	__ec.clear();
@@ -741,6 +765,9 @@ namespace ip
       __ec = std::make_error_code(std::errc::invalid_argument);
     else
       __ec.assign(errno, generic_category());
+#else
+    __ec = std::make_error_code(__unsupported_err());
+#endif
     return {};
   }
 
@@ -2062,6 +2089,7 @@ namespace ip
 
   /// @}
 
+#ifdef IPPROTO_TCP
   /// The TCP byte-stream protocol.
   class tcp
   {
@@ -2073,7 +2101,7 @@ namespace ip
     using acceptor = basic_socket_acceptor<tcp>; ///< A TCP acceptor.
     using iostream = basic_socket_iostream<tcp>; /// A TCP iostream.
 
-#ifdef _GLIBCXX_HAVE_NETINET_TCP_H
+#ifdef TCP_NODELAY
     /// Disable coalescing of small segments (i.e. the Nagle algorithm).
     struct no_delay : __sockopt_crtp<no_delay, bool>
     {
@@ -2117,7 +2145,9 @@ namespace ip
   { return !(__a == __b); }
 
   /// @}
+#endif // IPPROTO_TCP
 
+#ifdef IPPROTO_UDP
   /// The UDP datagram protocol.
   class udp
   {
@@ -2156,6 +2186,9 @@ namespace ip
   { return !(__a == __b); }
 
   /// @}
+#endif // IPPROTO_UDP
+
+#if defined IPPROTO_IP && defined IPPROTO_IPV6
 
   /// Restrict a socket created for an IPv6 protocol to IPv6 only.
   class v6_only : public __sockopt_crtp<v6_only, bool>
@@ -2371,6 +2404,8 @@ namespace ip
 
   } // namespace multicast
 
+#endif // IPPROTO_IP && IPPROTO_IPV6
+
   /// @}
 
 } // namespace ip
diff --git a/libstdc++-v3/testsuite/experimental/net/internet/socket/opt.cc b/libstdc++-v3/testsuite/experimental/net/internet/socket/opt.cc
index 68bac84a8b1..cfbc00f9da8 100644
--- a/libstdc++-v3/testsuite/experimental/net/internet/socket/opt.cc
+++ b/libstdc++-v3/testsuite/experimental/net/internet/socket/opt.cc
@@ -49,8 +49,10 @@ template<typename C, typename T = int>
 void check_boolean_sockopt()
 {
   namespace ip = std::experimental::net::ip;
+#if __has_include(<netinet/in.h>)
   check_gettable_sockopt<C, T>(ip::tcp::v4());
   check_settable_sockopt<C, T>(ip::tcp::v4());
+#endif
 
   static_assert( is_destructible<C>(), "" );
   static_assert( is_nothrow_default_constructible<C>(), "" );
@@ -74,8 +76,10 @@ template<typename C, typename T = int>
 void check_integer_sockopt()
 {
   namespace ip = std::experimental::net::ip;
+#if __has_include(<netinet/in.h>)
   check_gettable_sockopt<C, T>(ip::tcp::v4());
   check_settable_sockopt<C, T>(ip::tcp::v4());
+#endif
 
   static_assert( is_destructible<C>(), "" );
   static_assert( is_nothrow_default_constructible<C>(), "" );
@@ -97,8 +101,10 @@ void check_mcast_sockopt(C& c)
   static_assert( is_copy_constructible<C>(), "" );
   static_assert( is_copy_assignable<C>(), "" );
 
+#if __has_include(<netinet/in.h>)
   check_settable_sockopt<C, ipv6_mreq>(ip::tcp::v6(), c);
   check_settable_sockopt<C, ip_mreq>(ip::tcp::v4(), c);
+#endif
 
   static_assert( is_nothrow_constructible<C, const ip::address&>(), "" );
   static_assert( ! is_convertible<const ip::address&, C>(), "explicit" );
@@ -113,8 +119,11 @@ void check_mcast_sockopt(C& c)
 void test_option_types()
 {
   namespace ip = std::experimental::net::ip;
+
 #if __has_include(<netinet/in.h>)
+#if __has_include(<netinet/tcp.h>)
   check_boolean_sockopt<ip::tcp::no_delay>();
+#endif
 
   check_boolean_sockopt<ip::v6_only>();
 


More information about the Libstdc++ mailing list