From: Jonathan Wakely Date: Wed, 20 May 2020 23:59:55 +0000 (+0100) Subject: libstdc++: Fix net::basic_socket::close(error_code&) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=d9d34449bbde21f6092153828d1b6ee73bd6c4c3;p=gcc.git libstdc++: Fix net::basic_socket::close(error_code&) Also add some missing member functions, nodiscard attributes, and noexcept-specifiers. * include/experimental/executor (use_future_t::use_future_t()): Fix incorrect noexcept-specifier. * include/experimental/internet (basic_resolver_results): Adjust whitespace. * include/experimental/socket (__basic_socket_impl::release): Add member function. (basic_socket(io_context&, const endpoint_type&)): Fix argument to target constructor. (basic_socket::release(), basic_socket::release(error_code&)): Add missing member functions. (basic_socket::is_open()): Add nodiscard attribute. (basic_socket::close(error_code&)): Pass argument to base function. (basic_socket_acceptor::release()) (basic_socket_acceptor::release(error_code&)): Add missing member functions. (basic_socket_acceptor::is_open()): Add nodiscard attribute. (basic_socket_streambuf::error()): Add noexcept. (basic_socket_iostream::error()): Likewise. * testsuite/experimental/net/socket/basic_socket.cc: New test. --- diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 0ecfde4a9a6..dec84f03da6 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,25 @@ 2020-05-21 Jonathan Wakely + * include/experimental/executor (use_future_t::use_future_t()): Fix + incorrect noexcept-specifier. + * include/experimental/internet (basic_resolver_results): Adjust + whitespace. + * include/experimental/socket (__basic_socket_impl::release): Add + member function. + (basic_socket(io_context&, const endpoint_type&)): Fix argument to + target constructor. + (basic_socket::release(), basic_socket::release(error_code&)): Add + missing member functions. + (basic_socket::is_open()): Add nodiscard attribute. + (basic_socket::close(error_code&)): Pass argument to base function. + (basic_socket_acceptor::release()) + (basic_socket_acceptor::release(error_code&)): Add missing member + functions. + (basic_socket_acceptor::is_open()): Add nodiscard attribute. + (basic_socket_streambuf::error()): Add noexcept. + (basic_socket_iostream::error()): Likewise. + * testsuite/experimental/net/socket/basic_socket.cc: New test. + * include/experimental/buffer: Replace typedefs with alias-declarations. * include/experimental/executor: Likewise. diff --git a/libstdc++-v3/include/experimental/executor b/libstdc++-v3/include/experimental/executor index f55414c9360..763f4ce0e17 100644 --- a/libstdc++-v3/include/experimental/executor +++ b/libstdc++-v3/include/experimental/executor @@ -1601,7 +1601,10 @@ inline namespace v1 using allocator_type = _ProtoAllocator; // use_future_t members: - constexpr use_future_t() noexcept : _M_alloc() { } + constexpr + use_future_t() + noexcept(is_nothrow_default_constructible<_ProtoAllocator>::value) + : _M_alloc() { } explicit use_future_t(const _ProtoAllocator& __a) noexcept : _M_alloc(__a) { } diff --git a/libstdc++-v3/include/experimental/internet b/libstdc++-v3/include/experimental/internet index 71e40d83a7e..f1153b8ff6a 100644 --- a/libstdc++-v3/include/experimental/internet +++ b/libstdc++-v3/include/experimental/internet @@ -1726,7 +1726,9 @@ namespace ip // size: size_type size() const noexcept { return _M_size; } size_type max_size() const noexcept { return _M_results.max_size(); } - _GLIBCXX_NODISCARD bool empty() const noexcept { return _M_results.empty(); } + + _GLIBCXX_NODISCARD bool + empty() const noexcept { return _M_results.empty(); } // element access: const_iterator begin() const { return _M_results.begin(); } diff --git a/libstdc++-v3/include/experimental/socket b/libstdc++-v3/include/experimental/socket index 837965cb3c0..80fb21da95c 100644 --- a/libstdc++-v3/include/experimental/socket +++ b/libstdc++-v3/include/experimental/socket @@ -153,8 +153,8 @@ inline namespace v1 // TODO SettableSocket reqs // TODO BooleanSocketOption reqs // TODO IntegerSocketOption reqs - // TODO _IoControlCommand reqs - // TODO _ConnectCondition reqs + // TODO IoControlCommand reqs + // TODO ConnectCondition reqs /** @brief Sockets * @{ @@ -598,6 +598,13 @@ inline namespace v1 } } + native_handle_type release(error_code& __ec) + { + __glibcxx_assert(is_open()); + cancel(__ec); + return std::exchange(_M_sockfd, -1); + } + template void set_option(const _SettableSocketOption& __option, error_code& __ec) @@ -649,7 +656,7 @@ inline namespace v1 #ifdef _GLIBCXX_HAVE_SYS_SOCKET_H socklen_t __endpoint_len = __endpoint.capacity(); if (::getsockname(_M_sockfd, (sockaddr*)__endpoint.data(), - &__endpoint_len) == -1) + &__endpoint_len) == -1) { __ec.assign(errno, generic_category()); return endpoint_type{}; @@ -735,11 +742,18 @@ inline namespace v1 error_code& __ec) { __base::assign(__protocol, __native_socket, __ec); } - bool is_open() const noexcept { return __base::is_open(); } + native_handle_type release() + { return release(__throw_on_error{"basic_socket::release"}); } + + native_handle_type release(error_code& __ec) + { return __base::release(__ec); } + + [[__nodiscard__]] bool + is_open() const noexcept { return __base::is_open(); } void close() { close(__throw_on_error{"basic_socket::close"}); } - void close(error_code& __ec) { __base::close(); } + void close(error_code& __ec) { __base::close(__ec); } void cancel() { cancel(__throw_on_error{"basic_socket::cancel"}); } @@ -898,7 +912,7 @@ inline namespace v1 #ifdef _GLIBCXX_HAVE_SYS_SOCKET_H socklen_t __endpoint_len = __endpoint.capacity(); if (::getpeername(this->_M_sockfd, (sockaddr*)__endpoint.data(), - &__endpoint_len) + &__endpoint_len) == -1) { __ec.assign(errno, generic_category()); @@ -921,13 +935,13 @@ inline namespace v1 void connect(const endpoint_type& __endpoint, error_code& __ec) { +#ifdef _GLIBCXX_HAVE_SYS_SOCKET_H if (!is_open()) { open(__endpoint.protocol(), __ec); if (__ec) return; } -#ifdef _GLIBCXX_HAVE_SYS_SOCKET_H if (::connect(native_handle(), (const sockaddr*)__endpoint.data(), __endpoint.size()) == -1) __ec.assign(errno, generic_category()); @@ -956,7 +970,7 @@ inline namespace v1 auto __a = get_associated_allocator( __init.completion_handler, std::allocator()); __ex.post( - [__h=std::move(__init.completion_handler), __ec] + [__h = std::move(__init.completion_handler), __ec] () mutable { __h(__ec); }, __a); return __init.result.get(); @@ -1029,7 +1043,7 @@ inline namespace v1 { open(__protocol); } basic_socket(io_context& __ctx, const endpoint_type& __endpoint) - : basic_socket(std::addressof(__ctx), __endpoint.protocol()) + : basic_socket(__ctx, __endpoint.protocol()) { bind(__endpoint); } basic_socket(io_context& __ctx, const protocol_type& __protocol, @@ -1918,7 +1932,13 @@ inline namespace v1 error_code& __ec) { __base::assign(__protocol, __native_acceptor, __ec); } - bool + native_handle_type release() + { return release(__throw_on_error{"basic_socket_acceptor::release"}); } + + native_handle_type release(error_code& __ec) + { return __base::release(__ec); } + + [[__nodiscard__]] bool is_open() const noexcept { return __base::is_open(); } void @@ -2313,7 +2333,8 @@ inline namespace v1 basic_socket_streambuf* close(); // TODO basic_socket& socket() { return _M_socket; } - error_code error() const { return _M_ec; } + + error_code error() const noexcept { return _M_ec; } time_point expiry() const { return _M_expiry; } @@ -2425,7 +2446,7 @@ inline namespace v1 { return const_cast<__streambuf_type*>(std::addressof(_M_sb)); } basic_socket& socket() { return rdbuf()->socket(); } - error_code error() const { return rdbuf()->error(); } + error_code error() const noexcept { return rdbuf()->error(); } time_point expiry() const { return rdbuf()->expiry(); } void expires_at(const time_point& __t) { rdbuf()->expires_at(__t); } diff --git a/libstdc++-v3/testsuite/experimental/net/socket/basic_socket.cc b/libstdc++-v3/testsuite/experimental/net/socket/basic_socket.cc new file mode 100644 index 00000000000..14dbff6659d --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/net/socket/basic_socket.cc @@ -0,0 +1,129 @@ +// Copyright (C) 2020 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-do compile { target c++14 } } + +#include + +namespace net = std::experimental::net; +using namespace std; + +namespace test +{ +} + +void +test01(net::io_context& io) +{ + struct proto + { + struct endpoint + { + using protocol_type = proto; + protocol_type protocol() const { return {}; } + + void* data() { return nullptr; } + const void* data() const { return nullptr; } + std::size_t size() const { return 0; } + void resize(std::size_t) { } + std::size_t capacity() const { return 0; } + }; + + int family() const { return 0; } + int type() const { return 0; } + int protocol() const { return 0; } + }; + + static_assert( ! is_default_constructible>::value, + "no default ctor" ); + static_assert( ! is_copy_constructible>::value, + "copy ctor is deleted" ); + static_assert( ! is_move_constructible>::value, + "move ctor is protected" ); + static_assert( ! is_move_assignable>::value, + "move assignment op is protected" ); + + struct socket : net::basic_socket + { + explicit + socket(net::io_context& io) + : basic_socket(io) { } + + socket(net::io_context& io, const proto& p) + : basic_socket(io, p) { } + + socket(net::io_context& io, const proto::endpoint& e) + : basic_socket(io, e) { } + + socket(net::io_context& io, const proto& p, int n) + : basic_socket(io, p, n) { } + }; + + static_assert( ! is_copy_constructible::value, "deleted" ); + static_assert( is_move_constructible::value, "" ); + static_assert( is_move_assignable::value, "" ); + + error_code ec; + proto p; + proto::endpoint e; + + socket s(io); + s = socket(io, p); + s = socket(io, e); + s = socket(io, p, s.release()); + + static_assert( is_same::value, "" ); + static_assert( noexcept(s.get_executor()), "" ); + static_assert( is_same::value, "" ); + static_assert( noexcept(s.native_handle()), "GNU extension" ); + + s.open(); + s.open(p); + s.open(p, ec); + + s.assign(p, s.release()); + s.assign(p, s.release(ec), ec); + + static_assert( is_same(s).is_open()), + bool>::value, "" ); + static_assert( noexcept(const_cast(s).is_open()), "" ); + + s.close(); + s.close(ec); + + s.cancel(); + s.cancel(ec); + + s.bind(e); + s.bind(e, ec); + + s.shutdown(net::socket_base::shutdown_both); + s.shutdown(net::socket_base::shutdown_both, ec); + + e = s.local_endpoint(); + e = s.local_endpoint(ec); + e = s.remote_endpoint(); + e = s.remote_endpoint(ec); + + s.connect(e); + s.connect(e, ec); + + s.wait(net::socket_base::wait_read); + s.wait(net::socket_base::wait_read, ec); +}