diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2021-04-26 21:16:21 +0100 |
---|---|---|
committer | Jonathan Wakely <jwakely@redhat.com> | 2021-04-26 21:16:21 +0100 |
commit | 06c86a4f210c76a157512a2963e6c31302d161cb (patch) | |
tree | 53e2126bff13e0a82f5f78dbe9018a11831c6bf2 /libstdc++-v3 | |
parent | 49adc066729bda093b0658e3926bbf64cd4628b3 (diff) | |
download | gcc-06c86a4f210c76a157512a2963e6c31302d161cb.zip gcc-06c86a4f210c76a157512a2963e6c31302d161cb.tar.gz gcc-06c86a4f210c76a157512a2963e6c31302d161cb.tar.bz2 |
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.
Diffstat (limited to 'libstdc++-v3')
-rw-r--r-- | libstdc++-v3/include/experimental/bits/net.h | 35 | ||||
-rw-r--r-- | libstdc++-v3/include/experimental/socket | 66 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/experimental/net/socket/socket_base.cc | 148 |
3 files changed, 228 insertions, 21 deletions
diff --git a/libstdc++-v3/include/experimental/bits/net.h b/libstdc++-v3/include/experimental/bits/net.h index 0ac9ca7..3087f89 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 09c3b72..538dc78 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 b0b02b4..95cd815 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(); +} |