[gcc/devel/c++-modules] libstdc++: Fix net::basic_socket::close(error_code&)

Nathan Sidwell nathan@gcc.gnu.org
Thu May 21 18:34:07 GMT 2020


https://gcc.gnu.org/g:d9d34449bbde21f6092153828d1b6ee73bd6c4c3

commit d9d34449bbde21f6092153828d1b6ee73bd6c4c3
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Thu May 21 00:59:55 2020 +0100

    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:
---
 libstdc++-v3/ChangeLog                             |  20 ++++
 libstdc++-v3/include/experimental/executor         |   5 +-
 libstdc++-v3/include/experimental/internet         |   4 +-
 libstdc++-v3/include/experimental/socket           |  45 +++++--
 .../experimental/net/socket/basic_socket.cc        | 129 +++++++++++++++++++++
 5 files changed, 189 insertions(+), 14 deletions(-)

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  <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.
+
 	* 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<typename _SettableSocketOption>
 	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<void>());
                   __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<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; }
 
@@ -2425,7 +2446,7 @@ inline namespace v1
       { return const_cast<__streambuf_type*>(std::addressof(_M_sb)); }
 
       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(); }
       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
+// <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);
+}


More information about the Libstdc++-cvs mailing list