* [committed 1/2] libstdc++: Fix socket option classes
@ 2021-04-26 20:20 Jonathan Wakely
2021-04-26 20:22 ` [committed 2/2] libstdc++: Fix internet " Jonathan Wakely
0 siblings, 1 reply; 2+ messages in thread
From: Jonathan Wakely @ 2021-04-26 20:20 UTC (permalink / raw)
To: libstdc++, gcc-patches
[-- Attachment #1: Type: text/plain, Size: 1488 bytes --]
This fixes some flaws in the socket option types defined in
net::socket_base:
- The constructors were not noexcept.
- The __sockopt_base<T>::value() member function was present
unconditionally (so was defined for socket_base::linger which is
incorrect).
- The __socket_crtp<C, T>::operator=(T) assignment operator was not
noexcept, and was hidden in the derived classes.
Also:
- Use class instead of struct for the socket option types.
- Define the _S_level and _S_name constants as private.
- Declare the __socket_crtp base as a friend.
libstdc++-v3/ChangeLog:
* include/experimental/bits/net.h (__socket_base): Add
bool template parameter to allow BooleanSocketOption and
IntegerSocketOption to have different __socket_base<int>
base classes.
(__socket_base<bool>): Adjust base class.
(__socket_base<int>): Add partial specialization.
(__socket_crtp::operator=(_Tp)): Add noexcept-specifier.
* include/experimental/socket (socket_base::broadcast)
(socket_base::debug, socket_base::do_not_route)
(socket_base::keep_alive, socket_base::linger)
(socket_base::out_of_band_inline)
(socket_base::receive_buffer_size)
(socket_base::receive_low_watermark)
(socket_base::reuse_address, socket_base::send_buffer_size)
(socket_base::send_low_watermark): Add using-declaration for
__socket_crtp::operator=(_Tp).
* testsuite/experimental/net/socket/socket_base.cc: Check
properties of socket option types.
Tested powerpc64le-linux and powerpc-aix. Committed to trunk.
[-- Attachment #2: patch.txt --]
[-- Type: text/plain, Size: 15263 bytes --]
commit 06c86a4f210c76a157512a2963e6c31302d161cb
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Mon Apr 26 21:16:21 2021
libstdc++: Fix socket option classes
This fixes some flaws in the socket option types defined in
net::socket_base:
- The constructors were not noexcept.
- The __sockopt_base<T>::value() member function was present
unconditionally (so was defined for socket_base::linger which is
incorrect).
- The __socket_crtp<C, T>::operator=(T) assignment operator was not
noexcept, and was hidden in the derived classes.
Also:
- Use class instead of struct for the socket option types.
- Define the _S_level and _S_name constants as private.
- Declare the __socket_crtp base as a friend.
libstdc++-v3/ChangeLog:
* include/experimental/bits/net.h (__socket_base): Add
bool template parameter to allow BooleanSocketOption and
IntegerSocketOption to have different __socket_base<int>
base classes.
(__socket_base<bool>): Adjust base class.
(__socket_base<int>): Add partial specialization.
(__socket_crtp::operator=(_Tp)): Add noexcept-specifier.
* include/experimental/socket (socket_base::broadcast)
(socket_base::debug, socket_base::do_not_route)
(socket_base::keep_alive, socket_base::linger)
(socket_base::out_of_band_inline)
(socket_base::receive_buffer_size)
(socket_base::receive_low_watermark)
(socket_base::reuse_address, socket_base::send_buffer_size)
(socket_base::send_low_watermark): Add using-declaration for
__socket_crtp::operator=(_Tp).
* testsuite/experimental/net/socket/socket_base.cc: Check
properties of socket option types.
diff --git a/libstdc++-v3/include/experimental/bits/net.h b/libstdc++-v3/include/experimental/bits/net.h
index 0ac9ca7ddc6..3087f8957da 100644
--- a/libstdc++-v3/include/experimental/bits/net.h
+++ b/libstdc++-v3/include/experimental/bits/net.h
@@ -95,15 +95,20 @@ inline namespace v1
/// @endcond
- // Base class for types meeting IntegerSocketOption requirements.
- template<typename _Tp>
+ // Base class for types meeting both GettableSocketOption and
+ // SettableSocketOption requirements.
+ // The bool parameter allows __sockopt_base<bool> to have a
+ // __sockopt_base<int, B> base class (so that its _M_value is an int)
+ // but to have that be a distinct type from __sockopt_base<int>.
+ template<typename _Tp, bool = true>
struct __sockopt_base
{
__sockopt_base() = default;
- explicit __sockopt_base(int __val) : _M_value(__val) { }
-
- int value() const noexcept { return _M_value; }
+ explicit
+ __sockopt_base(_Tp __val) noexcept(noexcept(_Tp(std::declval<_Tp&>())))
+ : _M_value(__val)
+ { }
template<typename _Protocol>
void*
@@ -134,24 +139,36 @@ inline namespace v1
// Base class for types meeting BooleanSocketOption requirements.
template<>
- struct __sockopt_base<bool> : __sockopt_base<int>
+ struct __sockopt_base<bool> : __sockopt_base<int, false>
{
__sockopt_base() = default;
- explicit __sockopt_base(bool __val) : __sockopt_base<int>(__val) { }
+ explicit
+ __sockopt_base(bool __val) noexcept
+ : __sockopt_base<int, false>(__val)
+ { }
- bool value() const noexcept { return __sockopt_base<int>::_M_value; }
+ bool value() const noexcept { return this->_M_value; }
explicit operator bool() const noexcept { return value(); }
bool operator!() const noexcept { return !value(); }
};
+ // Base class for types meeting IntegerSocketOption requirements.
+ template<>
+ struct __sockopt_base<int> : __sockopt_base<int, false>
+ {
+ using __sockopt_base<int, false>::__sockopt_base;
+
+ int value() const noexcept { return this->_M_value; }
+ };
+
template<typename _Derived, typename _Tp = int>
struct __sockopt_crtp : __sockopt_base<_Tp>
{
using __sockopt_base<_Tp>::__sockopt_base;
_Derived&
- operator=(_Tp __value)
+ operator=(_Tp __value) noexcept(noexcept(__value = __value))
{
__sockopt_base<_Tp>::_M_value = __value;
return static_cast<_Derived&>(*this);
diff --git a/libstdc++-v3/include/experimental/socket b/libstdc++-v3/include/experimental/socket
index 09c3b729607..538dc78e72c 100644
--- a/libstdc++-v3/include/experimental/socket
+++ b/libstdc++-v3/include/experimental/socket
@@ -138,41 +138,59 @@ inline namespace v1
{
public:
#ifdef _GLIBCXX_HAVE_SYS_SOCKET_H
- struct broadcast : __sockopt_crtp<broadcast, bool>
+ class broadcast : public __sockopt_crtp<broadcast, bool>
{
+ public:
using __sockopt_crtp::__sockopt_crtp;
+ using __sockopt_crtp::operator=;
+ private:
+ friend __sockopt_crtp<broadcast, bool>;
static const int _S_level = SOL_SOCKET;
static const int _S_name = SO_BROADCAST;
};
- struct debug : __sockopt_crtp<debug, bool>
+ class debug : public __sockopt_crtp<debug, bool>
{
+ public:
+ friend __sockopt_crtp<debug, bool>;
using __sockopt_crtp::__sockopt_crtp;
+ using __sockopt_crtp::operator=;
+ private:
static const int _S_level = SOL_SOCKET;
static const int _S_name = SO_DEBUG;
};
- struct do_not_route : __sockopt_crtp<do_not_route, bool>
+ class do_not_route : public __sockopt_crtp<do_not_route, bool>
{
+ public:
using __sockopt_crtp::__sockopt_crtp;
+ using __sockopt_crtp::operator=;
+ private:
+ friend __sockopt_crtp<do_not_route, bool>;
static const int _S_level = SOL_SOCKET;
static const int _S_name = SO_DONTROUTE;
};
- struct keep_alive : __sockopt_crtp<keep_alive, bool>
+ class keep_alive : public __sockopt_crtp<keep_alive, bool>
{
+ public:
using __sockopt_crtp::__sockopt_crtp;
+ using __sockopt_crtp::operator=;
+ private:
+ friend __sockopt_crtp<keep_alive, bool>;
static const int _S_level = SOL_SOCKET;
static const int _S_name = SO_KEEPALIVE;
};
- struct linger : __sockopt_crtp<linger, ::linger>
+ class linger : public __sockopt_crtp<linger, ::linger>
{
+ public:
using __sockopt_crtp::__sockopt_crtp;
+ using __sockopt_crtp::operator=;
linger() noexcept = default;
@@ -198,54 +216,80 @@ inline namespace v1
timeout(chrono::seconds __t) noexcept
{ _M_value.l_linger = __t.count(); }
+ private:
+ friend __sockopt_crtp<linger, ::linger>;
static const int _S_level = SOL_SOCKET;
static const int _S_name = SO_LINGER;
};
- struct out_of_band_inline : __sockopt_crtp<out_of_band_inline, bool>
+ class out_of_band_inline : public __sockopt_crtp<out_of_band_inline, bool>
{
+ public:
using __sockopt_crtp::__sockopt_crtp;
+ using __sockopt_crtp::operator=;
+ private:
+ friend __sockopt_crtp<out_of_band_inline, bool>;
static const int _S_level = SOL_SOCKET;
static const int _S_name = SO_OOBINLINE;
};
- struct receive_buffer_size : __sockopt_crtp<receive_buffer_size>
+ class receive_buffer_size : public __sockopt_crtp<receive_buffer_size>
{
+ public:
using __sockopt_crtp::__sockopt_crtp;
+ using __sockopt_crtp::operator=;
+ private:
+ friend __sockopt_crtp<receive_buffer_size>;
static const int _S_level = SOL_SOCKET;
static const int _S_name = SO_RCVBUF;
};
- struct receive_low_watermark : __sockopt_crtp<receive_low_watermark>
+ class receive_low_watermark : public __sockopt_crtp<receive_low_watermark>
{
+ public:
using __sockopt_crtp::__sockopt_crtp;
+ using __sockopt_crtp::operator=;
+ private:
+ friend __sockopt_crtp<receive_low_watermark>;
static const int _S_level = SOL_SOCKET;
static const int _S_name = SO_RCVLOWAT;
};
- struct reuse_address : __sockopt_crtp<reuse_address, bool>
+ class reuse_address : public __sockopt_crtp<reuse_address, bool>
{
+ public:
using __sockopt_crtp::__sockopt_crtp;
+ using __sockopt_crtp::operator=;
+ private:
+ friend __sockopt_crtp<reuse_address, bool>;
static const int _S_level = SOL_SOCKET;
static const int _S_name = SO_REUSEADDR;
};
- struct send_buffer_size : __sockopt_crtp<send_buffer_size>
+ class send_buffer_size : public __sockopt_crtp<send_buffer_size>
{
+ public:
using __sockopt_crtp::__sockopt_crtp;
+ using __sockopt_crtp::operator=;
+ private:
+ friend __sockopt_crtp<send_buffer_size>;
static const int _S_level = SOL_SOCKET;
static const int _S_name = SO_SNDBUF;
};
- struct send_low_watermark : __sockopt_crtp<send_low_watermark>
+ class send_low_watermark : public __sockopt_crtp<send_low_watermark>
{
+ public:
using __sockopt_crtp::__sockopt_crtp;
+ using __sockopt_crtp::operator=;
+ private:
+ friend __sockopt_crtp<send_low_watermark>;
static const int _S_level = SOL_SOCKET;
static const int _S_name = SO_SNDLOWAT;
};
diff --git a/libstdc++-v3/testsuite/experimental/net/socket/socket_base.cc b/libstdc++-v3/testsuite/experimental/net/socket/socket_base.cc
index b0b02b4e560..95cd8151840 100644
--- a/libstdc++-v3/testsuite/experimental/net/socket/socket_base.cc
+++ b/libstdc++-v3/testsuite/experimental/net/socket/socket_base.cc
@@ -15,14 +15,156 @@
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-do compile { target c++14 } }
+// { dg-do run { target c++14 } }
#include <experimental/socket>
#include <testsuite_common_types.h>
+#include <testsuite_hooks.h>
using S = std::experimental::net::socket_base;
using namespace std;
+// Dummy protocol
+struct P
+{
+ struct endpoint
+ {
+ using protocol_type = P;
+ P protocol() const;
+ };
+};
+
+static_assert( ! is_default_constructible<S>(), "" );
+static_assert( ! is_destructible<S>(), "" );
+
+template<typename C, typename T>
+void check_gettable_sockopt()
+{
+ P p;
+ static_assert( is_same<decltype(declval<const C&>().level(p)), int>(), "" );
+ static_assert( noexcept(declval<const C&>().level(p)), "" );
+
+ static_assert( is_same<decltype(declval<const C&>().name(p)), int>(), "" );
+ static_assert( noexcept(declval<const C&>().name(p)), "" );
+
+ static_assert( is_same<decltype(declval<C&>().data(p)), void*>(), "" );
+ static_assert( noexcept(declval<C&>().data(p)), "" );
+
+ static_assert( is_same<decltype(declval<const C&>().size(p)), size_t>(), "" );
+ static_assert( noexcept(declval<const C&>().size(p)), "" );
+
+ static_assert( is_same<decltype(declval<C&>().resize(p, 0)), void>(), "" );
+ static_assert( ! noexcept(declval<C&>().resize(p, 0)), "" );
+
+ C opt;
+ VERIFY(opt.size(p) == sizeof(T));
+}
+
+template<typename C, typename T>
+void check_settable_sockopt()
+{
+ P p;
+ static_assert( is_same<decltype(declval<const C&>().level(p)), int>(), "" );
+ static_assert( noexcept(declval<const C&>().level(p)), "" );
+
+ static_assert( is_same<decltype(declval<const C&>().name(p)), int>(), "" );
+ static_assert( noexcept(declval<const C&>().name(p)), "" );
+
+ static_assert( is_same<decltype(declval<const C&>().data(p)), const void*>(), "" );
+ static_assert( noexcept(declval<const C&>().data(p)), "" );
+
+ static_assert( is_same<decltype(declval<C&>().size(p)), size_t>(), "" );
+ static_assert( noexcept(declval<C&>().size(p)), "" );
+
+ C opt;
+ VERIFY(opt.size(p) == sizeof(T));
+}
+
+template<typename C, typename T = int>
+void check_boolean_sockopt()
+{
+ check_gettable_sockopt<C, T>();
+ check_settable_sockopt<C, T>();
+
+ static_assert( is_destructible<C>(), "" );
+ static_assert( is_nothrow_default_constructible<C>(), "" );
+ static_assert( is_nothrow_copy_constructible<C>(), "" );
+ static_assert( is_nothrow_copy_assignable<C>(), "" );
+
+ static_assert( is_nothrow_constructible<C, bool>(), "" );
+ static_assert( is_nothrow_assignable<C&, bool>(), "" );
+
+ static_assert( is_same<decltype(declval<const C&>().value()), bool>(), "" );
+ static_assert( noexcept(declval<const C&>().value()), "" );
+
+ static_assert( is_same<decltype(static_cast<bool>(declval<const C&>())), bool>(), "" );
+ static_assert( noexcept(static_cast<bool>(declval<const C&>())), "" );
+
+ static_assert( is_same<decltype(!declval<const C&>()), bool>(), "" );
+ static_assert( noexcept(!declval<const C&>()), "" );
+}
+
+template<typename C, typename T = int>
+void check_integer_sockopt()
+{
+ check_gettable_sockopt<C, T>();
+ check_settable_sockopt<C, T>();
+
+ static_assert( is_destructible<C>(), "" );
+ static_assert( is_nothrow_default_constructible<C>(), "" );
+ static_assert( is_nothrow_copy_constructible<C>(), "" );
+ static_assert( is_nothrow_copy_assignable<C>(), "" );
+
+ static_assert( is_nothrow_constructible<C, int>(), "" );
+ static_assert( is_nothrow_assignable<C&, int>(), "" );
+
+ static_assert( is_same<decltype(declval<const C&>().value()), int>(), "" );
+ static_assert( noexcept(declval<const C&>().value()), "" );
+}
+
+void test_option_types()
+{
+ check_boolean_sockopt<S::broadcast>();
+
+ check_boolean_sockopt<S::debug>();
+
+ check_boolean_sockopt<S::do_not_route>();
+
+ check_boolean_sockopt<S::keep_alive>();
+
+ check_gettable_sockopt<S::linger, ::linger>();
+ check_settable_sockopt<S::linger, ::linger>();
+ static_assert( is_destructible<S::linger>(), "" );
+ static_assert( is_nothrow_default_constructible<S::linger>(), "" );
+ static_assert( is_nothrow_copy_constructible<S::linger>(), "" );
+ static_assert( is_nothrow_copy_assignable<S::linger>(), "" );
+ static_assert( is_nothrow_constructible<S::linger, bool, chrono::seconds>(), "" );
+
+ static_assert( is_same<decltype(declval<const S::linger&>().enabled()), bool>(), "" );
+ static_assert( noexcept(declval<const S::linger&>().enabled()), "" );
+
+ static_assert( is_void<decltype(declval<S::linger&>().enabled(true))>(), "" );
+ static_assert( noexcept(declval<S::linger&>().enabled(true)), "" );
+
+ static_assert( is_same<decltype(declval<const S::linger&>().timeout()), chrono::seconds>(), "" );
+ static_assert( noexcept(declval<const S::linger&>().timeout()), "" );
+
+ static_assert( is_void<decltype(declval<S::linger&>().timeout(chrono::seconds()))>(), "" );
+ static_assert( noexcept(declval<S::linger&>().timeout(chrono::seconds())), "" );
+
+ check_boolean_sockopt<S::out_of_band_inline>();
+
+ check_integer_sockopt<S::receive_buffer_size>();
+
+ check_integer_sockopt<S::receive_low_watermark>();
+
+ check_boolean_sockopt<S::reuse_address>();
+
+ check_integer_sockopt<S::send_buffer_size>();
+
+ check_integer_sockopt<S::send_low_watermark>();
+}
+
void test_constants()
{
static_assert( is_enum<S::shutdown_type>::value, "" );
@@ -43,3 +185,7 @@ void test_constants()
static_assert( is_same<decltype(m), const int*>::value, "" );
}
+int main()
+{
+ test_option_types();
+}
^ permalink raw reply [flat|nested] 2+ messages in thread
* [committed 2/2] libstdc++: Fix internet socket option classes
2021-04-26 20:20 [committed 1/2] libstdc++: Fix socket option classes Jonathan Wakely
@ 2021-04-26 20:22 ` Jonathan Wakely
0 siblings, 0 replies; 2+ messages in thread
From: Jonathan Wakely @ 2021-04-26 20:22 UTC (permalink / raw)
To: libstdc++, gcc-patches
[-- Attachment #1: Type: text/plain, Size: 1615 bytes --]
Similar to the previous commit, this fixes various problems with the
socket options classes in the <internet> header:
- The constructors were not noexcept.
- The __sockopt_base<T>::value() member function was present
unconditionally (so was defined for socket_base::linger which is
incorrect).
- The __socket_crtp<C, T>::operator=(T) assignment operator was not
noexcept, and was hidden in the derived classes.
- The MulticastSocketOptions incorrectly used a union, incorrectly
defined resize and const data() member functions, and their
constructors were unimplemented.
Also, where appropriate:
- Use class instead of struct for the socket option types.
- Define the _S_level and _S_name constants as private.
- Declare the __socket_crtp base as a friend.
libstdc++-v3/ChangeLog:
* include/experimental/internet (tcp::no_delay, v6_only)
(unicast::hops, multicast::hops, multicast::enable_loopback):
Change access of base class and static data members. Add
using-declaration for __socket_crtp::operator=(_Tp).
(multicast::__mcastopt): New type.
(multicast::join_group, multicast::leave_group): Derive from
__mcastopt for common implementation.
* include/experimental/socket: Add comment.
* testsuite/experimental/net/internet/socket/opt.cc: New test.
* testsuite/experimental/net/socket/socket_base.cc: Check for
protected constructor/destructor of socket_base. Check for
explicit constructors of socket option classes.
Tested powerpc64le-linux and powerpc-aix. Committed to trunk.
[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 19190 bytes --]
commit 2e0b1c6ce3afe0670b96444c6b955ce184ed0046
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Mon Apr 26 21:16:21 2021
libstdc++: Fix internet socket option classes
Similar to the previous commit, this fixes various problems with the
socket options classes in the <internet> header:
- The constructors were not noexcept.
- The __sockopt_base<T>::value() member function was present
unconditionally (so was defined for socket_base::linger which is
incorrect).
- The __socket_crtp<C, T>::operator=(T) assignment operator was not
noexcept, and was hidden in the derived classes.
- The MulticastSocketOptions incorrectly used a union, incorrectly
defined resize and const data() member functions, and their
constructors were unimplemented.
Also, where appropriate:
- Use class instead of struct for the socket option types.
- Define the _S_level and _S_name constants as private.
- Declare the __socket_crtp base as a friend.
libstdc++-v3/ChangeLog:
* include/experimental/internet (tcp::no_delay, v6_only)
(unicast::hops, multicast::hops, multicast::enable_loopback):
Change access of base class and static data members. Add
using-declaration for __socket_crtp::operator=(_Tp).
(multicast::__mcastopt): New type.
(multicast::join_group, multicast::leave_group): Derive from
__mcastopt for common implementation.
* include/experimental/socket: Add comment.
* testsuite/experimental/net/internet/socket/opt.cc: New test.
* testsuite/experimental/net/socket/socket_base.cc: Check for
protected constructor/destructor of socket_base. Check for
explicit constructors of socket option classes.
diff --git a/libstdc++-v3/include/experimental/internet b/libstdc++-v3/include/experimental/internet
index d3321afb9c6..2e3fd06ead2 100644
--- a/libstdc++-v3/include/experimental/internet
+++ b/libstdc++-v3/include/experimental/internet
@@ -52,7 +52,7 @@
# include <arpa/inet.h> // inet_ntop
#endif
#ifdef _GLIBCXX_HAVE_NETINET_IN_H
-# include <netinet/in.h> // IPPROTO_IP
+# include <netinet/in.h> // IPPROTO_IP, IPPROTO_IPV6, in_addr, in6_addr
#endif
#ifdef _GLIBCXX_HAVE_NETINET_TCP_H
# include <netinet/tcp.h> // TCP_NODELAY
@@ -2078,6 +2078,7 @@ namespace ip
struct no_delay : __sockopt_crtp<no_delay, bool>
{
using __sockopt_crtp::__sockopt_crtp;
+ using __sockopt_crtp::operator=;
static const int _S_level = IPPROTO_TCP;
static const int _S_name = TCP_NODELAY;
@@ -2157,10 +2158,14 @@ namespace ip
/// @}
/// Restrict a socket created for an IPv6 protocol to IPv6 only.
- struct v6_only : __sockopt_crtp<v6_only, bool>
+ class v6_only : public __sockopt_crtp<v6_only, bool>
{
+ public:
using __sockopt_crtp::__sockopt_crtp;
+ using __sockopt_crtp::operator=;
+ private:
+ friend __sockopt_crtp<v6_only, bool>;
static const int _S_level = IPPROTO_IPV6;
static const int _S_name = IPV6_V6ONLY;
};
@@ -2168,9 +2173,11 @@ namespace ip
namespace unicast
{
/// Set the default number of hops (TTL) for outbound datagrams.
- struct hops : __sockopt_crtp<hops>
+ class hops : public __sockopt_crtp<hops>
{
+ public:
using __sockopt_crtp::__sockopt_crtp;
+ using __sockopt_crtp::operator=;
template<typename _Protocol>
int
@@ -2186,130 +2193,111 @@ namespace ip
namespace multicast
{
- /// Request that a socket joins a multicast group.
- struct join_group
+ class __mcastopt
{
+ public:
explicit
- join_group(const address&);
+ __mcastopt(const address& __grp) noexcept
+ : __mcastopt(__grp.is_v4() ? __mcastopt(__grp.to_v4()) : __mcastopt(__grp.to_v6()))
+ { }
explicit
- join_group(const address_v4&, const address_v4& = address_v4::any());
+ __mcastopt(const address_v4& __grp,
+ const address_v4& __iface = address_v4::any()) noexcept
+ {
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ _M_v4.imr_multiaddr.s_addr = __grp.to_uint();
+ _M_v4.imr_interface.s_addr = __iface.to_uint();
+#else
+ _M_v4.imr_multiaddr.s_addr = __builtin_bswap32(__grp.to_uint());
+ _M_v4.imr_interface.s_addr = __builtin_bswap32(__iface.to_uint());
+#endif
+ }
explicit
- join_group(const address_v6&, unsigned int = 0);
+ __mcastopt(const address_v6& __grp, unsigned int __iface = 0) noexcept
+ {
+ const auto __addr = __grp.to_bytes();
+ __builtin_memcpy(_M_v6.ipv6mr_multiaddr.s6_addr, __addr.data(), 16);
+ _M_v6.ipv6mr_interface = __iface;
+ }
template<typename _Protocol>
int
level(const _Protocol& __p) const noexcept
{ return __p.family() == AF_INET6 ? IPPROTO_IPV6 : IPPROTO_IP; }
- template<typename _Protocol>
- int
- name(const _Protocol& __p) const noexcept
- {
- return __p.family() == AF_INET6
- ? IPV6_JOIN_GROUP : IP_ADD_MEMBERSHIP;
- }
- template<typename _Protocol>
- void*
- data(const _Protocol&) noexcept
- { return std::addressof(_M_value); }
-
template<typename _Protocol>
const void*
- data(const _Protocol&) const noexcept
- { return std::addressof(_M_value); }
+ data(const _Protocol& __p) const noexcept
+ { return __p.family() == AF_INET6 ? &_M_v6 : &_M_v4; }
template<typename _Protocol>
size_t
size(const _Protocol& __p) const noexcept
- {
- return __p.family() == AF_INET6
- ? sizeof(_M_value._M_v6) : sizeof(_M_value._M_v4);
- }
+ { return __p.family() == AF_INET6 ? sizeof(_M_v6) : sizeof(_M_v4); }
+
+ private:
+ ipv6_mreq _M_v6 = {};
+ ip_mreq _M_v4 = {};
+ };
+
+ /// Request that a socket joins a multicast group.
+ class join_group : private __mcastopt
+ {
+ public:
+ using __mcastopt::__mcastopt;
+ using __mcastopt::level;
+ using __mcastopt::data;
+ using __mcastopt::size;
template<typename _Protocol>
- void
- resize(const _Protocol& __p, size_t __s)
+ int
+ name(const _Protocol& __p) const noexcept
{
- if (__s != size(__p))
- __throw_length_error("invalid value for socket option resize");
+ if (__p.family() == AF_INET6)
+ return IPV6_JOIN_GROUP;
+ return IP_ADD_MEMBERSHIP;
}
-
- protected:
- union
- {
- ipv6_mreq _M_v6;
- ip_mreq _M_v4;
- } _M_value;
};
/// Request that a socket leaves a multicast group.
- struct leave_group
+ class leave_group : private __mcastopt
{
- explicit
- leave_group(const address&);
-
- explicit
- leave_group(const address_v4&, const address_v4& = address_v4::any());
-
- explicit
- leave_group(const address_v6&, unsigned int = 0);
-
- template<typename _Protocol>
- int
- level(const _Protocol& __p) const noexcept
- { return __p.family() == AF_INET6 ? IPPROTO_IPV6 : IPPROTO_IP; }
+ public:
+ using __mcastopt::__mcastopt;
+ using __mcastopt::level;
+ using __mcastopt::data;
+ using __mcastopt::size;
template<typename _Protocol>
int
name(const _Protocol& __p) const noexcept
{
- return __p.family() == AF_INET6
- ? IPV6_LEAVE_GROUP : IP_DROP_MEMBERSHIP;
+ if (__p.family() == AF_INET6)
+ return IPV6_LEAVE_GROUP;
+ return IP_DROP_MEMBERSHIP;
}
- template<typename _Protocol>
- void*
- data(const _Protocol&) noexcept
- { return std::addressof(_M_value); }
-
- template<typename _Protocol>
- const void*
- data(const _Protocol&) const noexcept
- { return std::addressof(_M_value); }
-
- template<typename _Protocol>
- size_t
- size(const _Protocol& __p) const noexcept
- {
- return __p.family() == AF_INET6
- ? sizeof(_M_value._M_v6) : sizeof(_M_value._M_v4);
- }
-
- template<typename _Protocol>
- void
- resize(const _Protocol& __p, size_t __s)
- {
- if (__s != size(__p))
- __throw_length_error("invalid value for socket option resize");
- }
-
- protected:
- union
- {
- ipv6_mreq _M_v6;
- ip_mreq _M_v4;
- } _M_value;
};
/// Specify the network interface for outgoing multicast datagrams.
class outbound_interface
{
+ public:
explicit
- outbound_interface(const address_v4&);
+ outbound_interface(const address_v4& __v4) noexcept
+ {
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ _M_v4.s_addr = __v4.to_uint();
+#else
+ _M_v4.s_addr = __builtin_bswap32(__v4.to_uint());
+#endif
+ }
explicit
- outbound_interface(unsigned int);
+ outbound_interface(unsigned int __v6) noexcept
+ : _M_v4(), _M_v6(__v6)
+ { }
template<typename _Protocol>
int
@@ -2326,28 +2314,25 @@ namespace ip
template<typename _Protocol>
const void*
- data(const _Protocol&) const noexcept
- { return std::addressof(_M_value); }
+ data(const _Protocol& __p) const noexcept
+ { return __p.family() == AF_INET6 ? &_M_v6 : &_M_v4; }
template<typename _Protocol>
size_t
size(const _Protocol& __p) const noexcept
- {
- return __p.family() == AF_INET6
- ? sizeof(_M_value._M_v6) : sizeof(_M_value._M_v4);
- }
+ { return __p.family() == AF_INET6 ? sizeof(_M_v6) : sizeof(_M_v4); }
- protected:
- union {
- unsigned _M_v6;
- in_addr _M_v4;
- } _M_value;
+ private:
+ in_addr _M_v4;
+ unsigned _M_v6 = 0;
};
/// Set the default number of hops (TTL) for outbound datagrams.
- struct hops : __sockopt_crtp<hops>
+ class hops : public __sockopt_crtp<hops>
{
+ public:
using __sockopt_crtp::__sockopt_crtp;
+ using __sockopt_crtp::operator=;
template<typename _Protocol>
int
@@ -2364,9 +2349,11 @@ namespace ip
};
/// Set whether datagrams are delivered back to the local application.
- struct enable_loopback : __sockopt_crtp<enable_loopback>
+ class enable_loopback : public __sockopt_crtp<enable_loopback, bool>
{
+ public:
using __sockopt_crtp::__sockopt_crtp;
+ using __sockopt_crtp::operator=;
template<typename _Protocol>
int
diff --git a/libstdc++-v3/include/experimental/socket b/libstdc++-v3/include/experimental/socket
index 538dc78e72c..18849f607f8 100644
--- a/libstdc++-v3/include/experimental/socket
+++ b/libstdc++-v3/include/experimental/socket
@@ -419,6 +419,8 @@ inline namespace v1
noexcept
{ return __f1 = (__f1 ^ __f2); }
+ // TODO define socket_base static constants in .so for C++14 mode
+
#if _GLIBCXX_HAVE_UNISTD_H
class __socket_impl
diff --git a/libstdc++-v3/testsuite/experimental/net/internet/socket/opt.cc b/libstdc++-v3/testsuite/experimental/net/internet/socket/opt.cc
new file mode 100644
index 00000000000..68bac84a8b1
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/net/internet/socket/opt.cc
@@ -0,0 +1,151 @@
+// { dg-do run { target c++14 } }
+
+#include <experimental/internet>
+#include <testsuite_common_types.h>
+#include <testsuite_hooks.h>
+
+using namespace std;
+
+template<typename C, typename T, typename P>
+void check_gettable_sockopt(P p, C c = C())
+{
+ static_assert( is_same<decltype(declval<const C&>().level(p)), int>(), "" );
+ static_assert( noexcept(declval<const C&>().level(p)), "" );
+
+ static_assert( is_same<decltype(declval<const C&>().name(p)), int>(), "" );
+ static_assert( noexcept(declval<const C&>().name(p)), "" );
+
+ static_assert( is_same<decltype(declval<C&>().data(p)), void*>(), "" );
+ static_assert( noexcept(declval<C&>().data(p)), "" );
+
+ static_assert( is_same<decltype(declval<const C&>().size(p)), size_t>(), "" );
+ static_assert( noexcept(declval<const C&>().size(p)), "" );
+
+ static_assert( is_same<decltype(declval<C&>().resize(p, 0)), void>(), "" );
+ static_assert( ! noexcept(declval<C&>().resize(p, 0)), "" );
+
+ VERIFY(c.size(p) == sizeof(T));
+}
+
+template<typename C, typename T, typename P>
+void check_settable_sockopt(P p, C c = C())
+{
+ static_assert( is_same<decltype(declval<const C&>().level(p)), int>(), "" );
+ static_assert( noexcept(declval<const C&>().level(p)), "" );
+
+ static_assert( is_same<decltype(declval<const C&>().name(p)), int>(), "" );
+ static_assert( noexcept(declval<const C&>().name(p)), "" );
+
+ static_assert( is_same<decltype(declval<const C&>().data(p)), const void*>(), "" );
+ static_assert( noexcept(declval<const C&>().data(p)), "" );
+
+ static_assert( is_same<decltype(declval<C&>().size(p)), size_t>(), "" );
+ static_assert( noexcept(declval<C&>().size(p)), "" );
+
+ VERIFY(c.size(p) == sizeof(T));
+}
+
+template<typename C, typename T = int>
+void check_boolean_sockopt()
+{
+ namespace ip = std::experimental::net::ip;
+ check_gettable_sockopt<C, T>(ip::tcp::v4());
+ check_settable_sockopt<C, T>(ip::tcp::v4());
+
+ static_assert( is_destructible<C>(), "" );
+ static_assert( is_nothrow_default_constructible<C>(), "" );
+ static_assert( is_nothrow_copy_constructible<C>(), "" );
+ static_assert( is_nothrow_copy_assignable<C>(), "" );
+
+ static_assert( is_nothrow_constructible<C, bool>(), "" );
+ static_assert( is_nothrow_assignable<C&, bool>(), "" );
+
+ static_assert( is_same<decltype(declval<const C&>().value()), bool>(), "" );
+ static_assert( noexcept(declval<const C&>().value()), "" );
+
+ static_assert( is_same<decltype(static_cast<bool>(declval<const C&>())), bool>(), "" );
+ static_assert( noexcept(static_cast<bool>(declval<const C&>())), "" );
+
+ static_assert( is_same<decltype(!declval<const C&>()), bool>(), "" );
+ static_assert( noexcept(!declval<const C&>()), "" );
+}
+
+template<typename C, typename T = int>
+void check_integer_sockopt()
+{
+ namespace ip = std::experimental::net::ip;
+ check_gettable_sockopt<C, T>(ip::tcp::v4());
+ check_settable_sockopt<C, T>(ip::tcp::v4());
+
+ static_assert( is_destructible<C>(), "" );
+ static_assert( is_nothrow_default_constructible<C>(), "" );
+ static_assert( is_nothrow_copy_constructible<C>(), "" );
+ static_assert( is_nothrow_copy_assignable<C>(), "" );
+
+ static_assert( is_nothrow_constructible<C, int>(), "" );
+ static_assert( is_nothrow_assignable<C&, int>(), "" );
+
+ static_assert( is_same<decltype(declval<const C&>().value()), int>(), "" );
+ static_assert( noexcept(declval<const C&>().value()), "" );
+}
+
+template<typename C>
+void check_mcast_sockopt(C& c)
+{
+ namespace ip = std::experimental::net::ip;
+ static_assert( is_destructible<C>(), "" );
+ static_assert( is_copy_constructible<C>(), "" );
+ static_assert( is_copy_assignable<C>(), "" );
+
+ check_settable_sockopt<C, ipv6_mreq>(ip::tcp::v6(), c);
+ check_settable_sockopt<C, ip_mreq>(ip::tcp::v4(), c);
+
+ static_assert( is_nothrow_constructible<C, const ip::address&>(), "" );
+ static_assert( ! is_convertible<const ip::address&, C>(), "explicit" );
+ static_assert( is_nothrow_constructible<C, const ip::address_v4&>(), "" );
+ static_assert( ! is_convertible<const ip::address_v4&, C>(), "explicit" );
+ static_assert( is_nothrow_constructible<C, const ip::address_v4&, const ip::address_v4&>(), "" );
+ static_assert( is_nothrow_constructible<C, const ip::address_v6&>(), "" );
+ static_assert( ! is_convertible<const ip::address_v6&, C>(), "explicit" );
+ static_assert( is_nothrow_constructible<C, const ip::address_v6&, unsigned>(), "" );
+}
+
+void test_option_types()
+{
+ namespace ip = std::experimental::net::ip;
+#if __has_include(<netinet/in.h>)
+ check_boolean_sockopt<ip::tcp::no_delay>();
+
+ check_boolean_sockopt<ip::v6_only>();
+
+ check_integer_sockopt<ip::unicast::hops>();
+
+ ip::multicast::join_group join(ip::address_v4::any());
+ check_mcast_sockopt(join);
+
+ ip::multicast::leave_group leave(ip::address_v4::any());
+ check_mcast_sockopt(leave);
+
+ using outbound_if = ip::multicast::outbound_interface;
+ outbound_if oif(ip::address_v4::any());
+ check_settable_sockopt<outbound_if, unsigned>(ip::tcp::v6(), oif);
+ check_settable_sockopt<outbound_if, ::in_addr>(ip::tcp::v4(), oif);
+ static_assert( is_destructible<outbound_if>(), "" );
+ static_assert( ! is_default_constructible<outbound_if>(), "" );
+ static_assert( is_nothrow_copy_constructible<outbound_if>(), "" );
+ static_assert( is_nothrow_copy_assignable<outbound_if>(), "" );
+ static_assert( is_nothrow_constructible<outbound_if, const ip::address_v4&>(), "" );
+ static_assert( ! is_convertible<const ip::address_v4&, outbound_if>(), "explicit" );
+ static_assert( is_nothrow_constructible<outbound_if, unsigned>(), "" );
+ static_assert( ! is_convertible<unsigned, outbound_if>(), "explicit" );
+
+ check_integer_sockopt<ip::multicast::hops>();
+
+ check_boolean_sockopt<ip::multicast::enable_loopback>();
+#endif
+}
+
+int main()
+{
+ test_option_types();
+}
diff --git a/libstdc++-v3/testsuite/experimental/net/socket/socket_base.cc b/libstdc++-v3/testsuite/experimental/net/socket/socket_base.cc
index 95cd8151840..1c02c5a09da 100644
--- a/libstdc++-v3/testsuite/experimental/net/socket/socket_base.cc
+++ b/libstdc++-v3/testsuite/experimental/net/socket/socket_base.cc
@@ -24,6 +24,12 @@
using S = std::experimental::net::socket_base;
using namespace std;
+static_assert( ! is_default_constructible<S>(), "protected" );
+static_assert( ! is_destructible<S>(), "protected" );
+struct Sock : S { };
+static_assert( is_default_constructible<Sock>(), "" );
+static_assert( is_destructible<Sock>(), "" );
+
// Dummy protocol
struct P
{
@@ -34,9 +40,6 @@ struct P
};
};
-static_assert( ! is_default_constructible<S>(), "" );
-static_assert( ! is_destructible<S>(), "" );
-
template<typename C, typename T>
void check_gettable_sockopt()
{
@@ -92,6 +95,7 @@ void check_boolean_sockopt()
static_assert( is_nothrow_copy_assignable<C>(), "" );
static_assert( is_nothrow_constructible<C, bool>(), "" );
+ static_assert( ! is_convertible<bool, C>(), "constructor is explicit" );
static_assert( is_nothrow_assignable<C&, bool>(), "" );
static_assert( is_same<decltype(declval<const C&>().value()), bool>(), "" );
@@ -116,6 +120,7 @@ void check_integer_sockopt()
static_assert( is_nothrow_copy_assignable<C>(), "" );
static_assert( is_nothrow_constructible<C, int>(), "" );
+ static_assert( ! is_convertible<int, C>(), "constructor is explicit" );
static_assert( is_nothrow_assignable<C&, int>(), "" );
static_assert( is_same<decltype(declval<const C&>().value()), int>(), "" );
@@ -124,6 +129,7 @@ void check_integer_sockopt()
void test_option_types()
{
+#if __has_include(<socket.h>)
check_boolean_sockopt<S::broadcast>();
check_boolean_sockopt<S::debug>();
@@ -163,10 +169,12 @@ void test_option_types()
check_integer_sockopt<S::send_buffer_size>();
check_integer_sockopt<S::send_low_watermark>();
+#endif
}
void test_constants()
{
+#if __has_include(<socket.h>)
static_assert( is_enum<S::shutdown_type>::value, "" );
static_assert( S::shutdown_receive != S::shutdown_send, "" );
static_assert( S::shutdown_receive != S::shutdown_both, "" );
@@ -183,6 +191,7 @@ void test_constants()
auto m = &S::max_listen_connections;
static_assert( is_same<decltype(m), const int*>::value, "" );
+#endif
}
int main()
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2021-04-26 20:22 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-04-26 20:20 [committed 1/2] libstdc++: Fix socket option classes Jonathan Wakely
2021-04-26 20:22 ` [committed 2/2] libstdc++: Fix internet " Jonathan Wakely
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).