Commit e3eec8a1 by Jonathan Wakely

libstdc++: Fix net::basic_socket::close(error_code&)

Also add some missing member functions, nodiscard attributes, and
noexcept-specifiers.

Backport from mainline
2020-05-21  Jonathan Wakely  <jwakely@redhat.com>

	* 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.
parent 566ba721
...@@ -3,6 +3,31 @@ ...@@ -3,6 +3,31 @@
Backport from mainline Backport from mainline
2020-05-21 Jonathan Wakely <jwakely@redhat.com> 2020-05-21 Jonathan Wakely <jwakely@redhat.com>
* 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.
2020-05-21 Jonathan Wakely <jwakely@redhat.com>
Backport from mainline
2020-05-21 Jonathan Wakely <jwakely@redhat.com>
PR libstdc++/93983 PR libstdc++/93983
* include/bits/iterator_concepts.h (__detail::__cpp17_iterator): * include/bits/iterator_concepts.h (__detail::__cpp17_iterator):
Reorder constraints to avoid recursion when constructors use Reorder constraints to avoid recursion when constructors use
......
...@@ -1601,7 +1601,10 @@ inline namespace v1 ...@@ -1601,7 +1601,10 @@ inline namespace v1
using allocator_type = _ProtoAllocator; using allocator_type = _ProtoAllocator;
// use_future_t members: // 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 explicit
use_future_t(const _ProtoAllocator& __a) noexcept : _M_alloc(__a) { } use_future_t(const _ProtoAllocator& __a) noexcept : _M_alloc(__a) { }
......
...@@ -1726,7 +1726,9 @@ namespace ip ...@@ -1726,7 +1726,9 @@ namespace ip
// size: // size:
size_type size() const noexcept { return _M_size; } size_type size() const noexcept { return _M_size; }
size_type max_size() const noexcept { return _M_results.max_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: // element access:
const_iterator begin() const { return _M_results.begin(); } const_iterator begin() const { return _M_results.begin(); }
......
...@@ -153,8 +153,8 @@ inline namespace v1 ...@@ -153,8 +153,8 @@ inline namespace v1
// TODO SettableSocket reqs // TODO SettableSocket reqs
// TODO BooleanSocketOption reqs // TODO BooleanSocketOption reqs
// TODO IntegerSocketOption reqs // TODO IntegerSocketOption reqs
// TODO _IoControlCommand reqs // TODO IoControlCommand reqs
// TODO _ConnectCondition reqs // TODO ConnectCondition reqs
/** @brief Sockets /** @brief Sockets
* @{ * @{
...@@ -598,6 +598,13 @@ inline namespace v1 ...@@ -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<typename _SettableSocketOption> template<typename _SettableSocketOption>
void void
set_option(const _SettableSocketOption& __option, error_code& __ec) set_option(const _SettableSocketOption& __option, error_code& __ec)
...@@ -649,7 +656,7 @@ inline namespace v1 ...@@ -649,7 +656,7 @@ inline namespace v1
#ifdef _GLIBCXX_HAVE_SYS_SOCKET_H #ifdef _GLIBCXX_HAVE_SYS_SOCKET_H
socklen_t __endpoint_len = __endpoint.capacity(); socklen_t __endpoint_len = __endpoint.capacity();
if (::getsockname(_M_sockfd, (sockaddr*)__endpoint.data(), if (::getsockname(_M_sockfd, (sockaddr*)__endpoint.data(),
&__endpoint_len) == -1) &__endpoint_len) == -1)
{ {
__ec.assign(errno, generic_category()); __ec.assign(errno, generic_category());
return endpoint_type{}; return endpoint_type{};
...@@ -735,11 +742,18 @@ inline namespace v1 ...@@ -735,11 +742,18 @@ inline namespace v1
error_code& __ec) error_code& __ec)
{ __base::assign(__protocol, __native_socket, __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); }
_GLIBCXX_NODISCARD bool
is_open() const noexcept { return __base::is_open(); }
void close() { close(__throw_on_error{"basic_socket::close"}); } 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"}); } void cancel() { cancel(__throw_on_error{"basic_socket::cancel"}); }
...@@ -898,7 +912,7 @@ inline namespace v1 ...@@ -898,7 +912,7 @@ inline namespace v1
#ifdef _GLIBCXX_HAVE_SYS_SOCKET_H #ifdef _GLIBCXX_HAVE_SYS_SOCKET_H
socklen_t __endpoint_len = __endpoint.capacity(); socklen_t __endpoint_len = __endpoint.capacity();
if (::getpeername(this->_M_sockfd, (sockaddr*)__endpoint.data(), if (::getpeername(this->_M_sockfd, (sockaddr*)__endpoint.data(),
&__endpoint_len) &__endpoint_len)
== -1) == -1)
{ {
__ec.assign(errno, generic_category()); __ec.assign(errno, generic_category());
...@@ -921,13 +935,13 @@ inline namespace v1 ...@@ -921,13 +935,13 @@ inline namespace v1
void void
connect(const endpoint_type& __endpoint, error_code& __ec) connect(const endpoint_type& __endpoint, error_code& __ec)
{ {
#ifdef _GLIBCXX_HAVE_SYS_SOCKET_H
if (!is_open()) if (!is_open())
{ {
open(__endpoint.protocol(), __ec); open(__endpoint.protocol(), __ec);
if (__ec) if (__ec)
return; return;
} }
#ifdef _GLIBCXX_HAVE_SYS_SOCKET_H
if (::connect(native_handle(), (const sockaddr*)__endpoint.data(), if (::connect(native_handle(), (const sockaddr*)__endpoint.data(),
__endpoint.size()) == -1) __endpoint.size()) == -1)
__ec.assign(errno, generic_category()); __ec.assign(errno, generic_category());
...@@ -956,7 +970,7 @@ inline namespace v1 ...@@ -956,7 +970,7 @@ inline namespace v1
auto __a = get_associated_allocator( auto __a = get_associated_allocator(
__init.completion_handler, std::allocator<void>()); __init.completion_handler, std::allocator<void>());
__ex.post( __ex.post(
[__h=std::move(__init.completion_handler), __ec] [__h = std::move(__init.completion_handler), __ec]
() mutable () mutable
{ __h(__ec); }, __a); { __h(__ec); }, __a);
return __init.result.get(); return __init.result.get();
...@@ -1029,7 +1043,7 @@ inline namespace v1 ...@@ -1029,7 +1043,7 @@ inline namespace v1
{ open(__protocol); } { open(__protocol); }
basic_socket(io_context& __ctx, const endpoint_type& __endpoint) basic_socket(io_context& __ctx, const endpoint_type& __endpoint)
: basic_socket(std::addressof(__ctx), __endpoint.protocol()) : basic_socket(__ctx, __endpoint.protocol())
{ bind(__endpoint); } { bind(__endpoint); }
basic_socket(io_context& __ctx, const protocol_type& __protocol, basic_socket(io_context& __ctx, const protocol_type& __protocol,
...@@ -1918,7 +1932,13 @@ inline namespace v1 ...@@ -1918,7 +1932,13 @@ inline namespace v1
error_code& __ec) error_code& __ec)
{ __base::assign(__protocol, __native_acceptor, __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); }
_GLIBCXX_NODISCARD bool
is_open() const noexcept { return __base::is_open(); } is_open() const noexcept { return __base::is_open(); }
void void
...@@ -2313,7 +2333,8 @@ inline namespace v1 ...@@ -2313,7 +2333,8 @@ inline namespace v1
basic_socket_streambuf* close(); // TODO basic_socket_streambuf* close(); // TODO
basic_socket<protocol_type>& socket() { return _M_socket; } basic_socket<protocol_type>& 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; } time_point expiry() const { return _M_expiry; }
...@@ -2425,7 +2446,7 @@ inline namespace v1 ...@@ -2425,7 +2446,7 @@ inline namespace v1
{ return const_cast<__streambuf_type*>(std::addressof(_M_sb)); } { return const_cast<__streambuf_type*>(std::addressof(_M_sb)); }
basic_socket<protocol_type>& socket() { return rdbuf()->socket(); } basic_socket<protocol_type>& 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(); } time_point expiry() const { return rdbuf()->expiry(); }
void expires_at(const time_point& __t) { rdbuf()->expires_at(__t); } void expires_at(const time_point& __t) { rdbuf()->expires_at(__t); }
......
// 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
// <http://www.gnu.org/licenses/>.
// { dg-do compile { target c++14 } }
#include <experimental/socket>
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<net::basic_socket<proto>>::value,
"no default ctor" );
static_assert( ! is_copy_constructible<net::basic_socket<proto>>::value,
"copy ctor is deleted" );
static_assert( ! is_move_constructible<net::basic_socket<proto>>::value,
"move ctor is protected" );
static_assert( ! is_move_assignable<net::basic_socket<proto>>::value,
"move assignment op is protected" );
struct socket : net::basic_socket<proto>
{
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<socket>::value, "deleted" );
static_assert( is_move_constructible<socket>::value, "" );
static_assert( is_move_assignable<socket>::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<decltype(s.get_executor()),
net::io_context::executor_type>::value, "" );
static_assert( noexcept(s.get_executor()), "" );
static_assert( is_same<decltype(s.native_handle()),
socket::native_handle_type>::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<decltype(const_cast<const socket&>(s).is_open()),
bool>::value, "" );
static_assert( noexcept(const_cast<const socket&>(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);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment