mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			2475 lines
		
	
	
		
			71 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			2475 lines
		
	
	
		
			71 KiB
		
	
	
	
		
			C++
		
	
	
	
| // <experimental/socket> -*- C++ -*-
 | |
| 
 | |
| // Copyright (C) 2015-2018 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.
 | |
| 
 | |
| // Under Section 7 of GPL version 3, you are granted additional
 | |
| // permissions described in the GCC Runtime Library Exception, version
 | |
| // 3.1, as published by the Free Software Foundation.
 | |
| 
 | |
| // You should have received a copy of the GNU General Public License and
 | |
| // a copy of the GCC Runtime Library Exception along with this program;
 | |
| // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 | |
| // <http://www.gnu.org/licenses/>.
 | |
| 
 | |
| /** @file experimental/socket
 | |
|  *  This is a TS C++ Library header.
 | |
|  */
 | |
| 
 | |
| #ifndef _GLIBCXX_EXPERIMENTAL_SOCKET
 | |
| #define _GLIBCXX_EXPERIMENTAL_SOCKET
 | |
| 
 | |
| #pragma GCC system_header
 | |
| 
 | |
| #if __cplusplus >= 201402L
 | |
| 
 | |
| #include <experimental/netfwd>
 | |
| #include <experimental/buffer>
 | |
| #include <experimental/io_context>
 | |
| #include <experimental/bits/net.h>
 | |
| #include <streambuf>
 | |
| #include <istream>
 | |
| #include <bits/unique_ptr.h>
 | |
| #if _GLIBCXX_HAVE_UNISTD_H
 | |
| # include <unistd.h>
 | |
| # include <sys/socket.h>
 | |
| # include <sys/ioctl.h>
 | |
| # include <sys/fcntl.h>
 | |
| # include <sys/uio.h>
 | |
| # include <poll.h>
 | |
| #endif
 | |
| 
 | |
| namespace std _GLIBCXX_VISIBILITY(default)
 | |
| {
 | |
| namespace experimental
 | |
| {
 | |
| namespace net
 | |
| {
 | |
| inline namespace v1
 | |
| {
 | |
| _GLIBCXX_BEGIN_NAMESPACE_VERSION
 | |
| 
 | |
|   /**
 | |
|    * @ingroup networking
 | |
|    * @{
 | |
|    */
 | |
| 
 | |
|   enum class socket_errc {  // TODO decide values
 | |
|     already_open = 3,
 | |
|     not_found = 4
 | |
|   };
 | |
| 
 | |
|   const error_category& socket_category() noexcept
 | |
|   {
 | |
|     struct __cat : error_category
 | |
|     {
 | |
|       const char* name() const noexcept { return "socket"; }
 | |
| 
 | |
|       std::string message(int __e) const
 | |
|       {
 | |
| 	if (__e == (int)socket_errc::already_open)
 | |
| 	  return "already open";
 | |
| 	else if (__e == (int)socket_errc::not_found)
 | |
| 	  return "endpoint not found";
 | |
| 	return "socket error";
 | |
|       }
 | |
| 
 | |
|       virtual void __message(int) { } // TODO dual ABI XXX
 | |
|     };
 | |
|     static __cat __c;
 | |
|     return __c;
 | |
|   }
 | |
| 
 | |
|   inline error_code
 | |
|   make_error_code(socket_errc __e) noexcept
 | |
|   { return error_code(static_cast<int>(__e), socket_category()); }
 | |
| 
 | |
|   inline error_condition
 | |
|   make_error_condition(socket_errc __e) noexcept
 | |
|   { return error_condition(static_cast<int>(__e), socket_category()); }
 | |
| 
 | |
|   template<typename _Tp, typename = __void_t<>>
 | |
|     struct __is_endpoint_impl : false_type
 | |
|     { };
 | |
| 
 | |
|   // Check Endpoint requirements.
 | |
|   template<typename _Tp>
 | |
|     auto
 | |
|     __endpoint_reqs(const _Tp* __a = 0)
 | |
|     -> enable_if_t<__and_<
 | |
|       is_default_constructible<_Tp>,
 | |
|       __is_value_constructible<_Tp>,
 | |
|       is_same<decltype(__a->__protocol()), typename _Tp::protocol_type>
 | |
|       >::value,
 | |
|     __void_t< typename _Tp::protocol_type::endpoint >>;
 | |
| 
 | |
|   template<typename _Tp>
 | |
|     struct __is_endpoint_impl<_Tp, decltype(__endpoint_reqs<_Tp>())>
 | |
|     : true_type
 | |
|     { };
 | |
| 
 | |
|   template<typename _Tp>
 | |
|     struct __is_endpoint : __is_endpoint_impl<_Tp>
 | |
|     { };
 | |
| 
 | |
|   // TODO Endpoint reqs for extensible implementations
 | |
|   // TODO _Protocol reqs
 | |
|   // TODO AcceptableProtocol reqs
 | |
|   // TODO GettableSocket reqs
 | |
|   // TODO SettableSocket reqs
 | |
|   // TODO BooleanSocketOption reqs
 | |
|   // TODO IntegerSocketOption reqs
 | |
|   // TODO _IoControlCommand reqs
 | |
|   // TODO _ConnectCondition reqs
 | |
| 
 | |
|   /** @brief Sockets
 | |
|    * @{
 | |
|    */
 | |
| 
 | |
|   class socket_base
 | |
|   {
 | |
|   public:
 | |
|     struct broadcast : __sockopt_crtp<broadcast, bool>
 | |
|     {
 | |
|       using __sockopt_crtp::__sockopt_crtp;
 | |
| 
 | |
|       static const int _S_level = SOL_SOCKET;
 | |
|       static const int _S_name = SO_BROADCAST;
 | |
|     };
 | |
| 
 | |
|     struct debug : __sockopt_crtp<debug, bool>
 | |
|     {
 | |
|       using __sockopt_crtp::__sockopt_crtp;
 | |
| 
 | |
|       static const int _S_level = SOL_SOCKET;
 | |
|       static const int _S_name = SO_DEBUG;
 | |
|     };
 | |
| 
 | |
|     struct do_not_route : __sockopt_crtp<do_not_route, bool>
 | |
|     {
 | |
|       using __sockopt_crtp::__sockopt_crtp;
 | |
| 
 | |
|       static const int _S_level = SOL_SOCKET;
 | |
|       static const int _S_name = SO_DONTROUTE;
 | |
|     };
 | |
| 
 | |
|     struct keep_alive : __sockopt_crtp<keep_alive, bool>
 | |
|     {
 | |
|       using __sockopt_crtp::__sockopt_crtp;
 | |
| 
 | |
|       static const int _S_level = SOL_SOCKET;
 | |
|       static const int _S_name = SO_KEEPALIVE;
 | |
|     };
 | |
| 
 | |
|     struct linger : __sockopt_crtp<linger, ::linger>
 | |
|     {
 | |
|       using __sockopt_crtp::__sockopt_crtp;
 | |
| 
 | |
|       linger() noexcept = default;
 | |
| 
 | |
|       linger(bool __e, chrono::seconds __t) noexcept
 | |
|       {
 | |
| 	enabled(__e);
 | |
| 	timeout(__t);
 | |
|       }
 | |
| 
 | |
|       bool
 | |
|       enabled() const noexcept
 | |
|       { return _M_value.l_onoff != 0; }
 | |
| 
 | |
|       void
 | |
|       enabled(bool __e) noexcept
 | |
|       { _M_value.l_onoff = int(__e); }
 | |
| 
 | |
|       chrono::seconds
 | |
|       timeout() const noexcept
 | |
|       { return chrono::seconds(_M_value.l_linger); }
 | |
| 
 | |
|       void
 | |
|       timeout(chrono::seconds __t) noexcept
 | |
|       { _M_value.l_linger = __t.count(); }
 | |
| 
 | |
|       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>
 | |
|     {
 | |
|       using __sockopt_crtp::__sockopt_crtp;
 | |
| 
 | |
|       static const int _S_level = SOL_SOCKET;
 | |
|       static const int _S_name = SO_OOBINLINE;
 | |
|     };
 | |
| 
 | |
|     struct receive_buffer_size : __sockopt_crtp<receive_buffer_size>
 | |
|     {
 | |
|       using __sockopt_crtp::__sockopt_crtp;
 | |
| 
 | |
|       static const int _S_level = SOL_SOCKET;
 | |
|       static const int _S_name = SO_RCVBUF;
 | |
|     };
 | |
| 
 | |
|     struct receive_low_watermark : __sockopt_crtp<receive_low_watermark>
 | |
|     {
 | |
|       using __sockopt_crtp::__sockopt_crtp;
 | |
| 
 | |
|       static const int _S_level = SOL_SOCKET;
 | |
|       static const int _S_name = SO_RCVLOWAT;
 | |
|     };
 | |
| 
 | |
|     struct reuse_address : __sockopt_crtp<reuse_address, bool>
 | |
|     {
 | |
|       using __sockopt_crtp::__sockopt_crtp;
 | |
| 
 | |
|       static const int _S_level = SOL_SOCKET;
 | |
|       static const int _S_name = SO_REUSEADDR;
 | |
|     };
 | |
| 
 | |
|     struct send_buffer_size : __sockopt_crtp<send_buffer_size>
 | |
|     {
 | |
|       using __sockopt_crtp::__sockopt_crtp;
 | |
| 
 | |
|       static const int _S_level = SOL_SOCKET;
 | |
|       static const int _S_name = SO_SNDBUF;
 | |
|     };
 | |
| 
 | |
|     struct send_low_watermark : __sockopt_crtp<send_low_watermark>
 | |
|     {
 | |
|       using __sockopt_crtp::__sockopt_crtp;
 | |
| 
 | |
|       static const int _S_level = SOL_SOCKET;
 | |
|       static const int _S_name = SO_SNDLOWAT;
 | |
|     };
 | |
| 
 | |
|     enum shutdown_type : int
 | |
|     {
 | |
|       __shutdown_receive	= SHUT_RD,
 | |
|       __shutdown_send		= SHUT_WR,
 | |
|       __shutdown_both		= SHUT_RDWR
 | |
|     };
 | |
|     static constexpr shutdown_type shutdown_receive	= __shutdown_receive;
 | |
|     static constexpr shutdown_type shutdown_send	= __shutdown_send;
 | |
|     static constexpr shutdown_type shutdown_both	= __shutdown_both;
 | |
| 
 | |
|     enum wait_type : int
 | |
|     {
 | |
|       __wait_read		= POLLIN,
 | |
|       __wait_write		= POLLOUT,
 | |
|       __wait_error		= POLLERR
 | |
|     };
 | |
|     static constexpr wait_type wait_read		= __wait_read;
 | |
|     static constexpr wait_type wait_write		= __wait_write;
 | |
|     static constexpr wait_type wait_error		= __wait_error;
 | |
| 
 | |
|     enum message_flags : int
 | |
|     {
 | |
|       __message_peek		= MSG_PEEK,
 | |
|       __message_oob		= MSG_OOB,
 | |
|       __message_dontroute	= MSG_DONTROUTE
 | |
|     };
 | |
|     static constexpr message_flags message_peek		= __message_peek;
 | |
|     static constexpr message_flags message_out_of_band	= __message_oob;
 | |
|     static constexpr message_flags message_do_not_route	= __message_dontroute;
 | |
| 
 | |
|     static const int max_listen_connections = SOMAXCONN;
 | |
| 
 | |
|   protected:
 | |
|     socket_base() = default;
 | |
|     ~socket_base() = default;
 | |
| 
 | |
|     struct __msg_hdr : ::msghdr
 | |
|     {
 | |
| #ifdef IOV_MAX
 | |
|       using __iovec_array = array<::iovec, IOV_MAX>;
 | |
| #elif _GLIBCXX_HAVE_UNISTD_H
 | |
|       struct __iovec_array
 | |
|       {
 | |
| 	__iovec_array() : _M_ptr(new ::iovec[size()]) { }
 | |
| 
 | |
| 	::iovec& operator[](size_t __n) noexcept { return _M_ptr[__n]; }
 | |
| 
 | |
| 	::iovec* data() noexcept { return _M_ptr.get(); }
 | |
| 
 | |
| 	static size_t size()
 | |
| 	{
 | |
| 	  static const size_t __iov_max = ::sysconf(_SC_IOV_MAX);
 | |
| 	  return __iov_max;
 | |
| 	}
 | |
| 
 | |
|       private:
 | |
| 	unique_ptr<::iovec[]> _M_ptr;
 | |
|       };
 | |
| #else
 | |
|       using __iovec_array = array<::iovec, 16>;
 | |
| #endif
 | |
| 
 | |
|       __iovec_array _M_iov;
 | |
| 
 | |
|       template<typename _BufferSequence>
 | |
| 	explicit
 | |
| 	__msg_hdr(const _BufferSequence& __buffers)
 | |
| 	: msghdr()
 | |
| 	{
 | |
| 	  auto __buf = net::buffer_sequence_begin(__buffers);
 | |
| 	  const auto __bufend = net::buffer_sequence_end(__buffers);
 | |
| 	  size_t __len = 0;
 | |
| 	  while (__buf != __bufend && __len != _M_iov.size())
 | |
| 	    {
 | |
| 	      _M_iov[__len].iov_base = (void*)__buf->data();
 | |
| 	      _M_iov[__len].iov_len = __buf->size();
 | |
| 	      ++__buf;
 | |
| 	      ++__len;
 | |
| 	    }
 | |
| 	  this->msg_iovlen = __len;
 | |
| 	  this->msg_iov = _M_iov.data();
 | |
| 	}
 | |
| 
 | |
|       template<typename _BufferSequence, typename _Endpoint>
 | |
| 	__msg_hdr(const _BufferSequence& __buffers, const _Endpoint& __ep)
 | |
| 	: __msg_hdr(__buffers)
 | |
| 	{
 | |
| 	  this->msg_name = __ep.data();
 | |
| 	  this->msg_namelen = __ep.size();
 | |
| 	}
 | |
|     };
 | |
|   };
 | |
| 
 | |
|   constexpr socket_base::message_flags
 | |
|   operator&(socket_base::message_flags __f1, socket_base::message_flags __f2)
 | |
|   { return socket_base::message_flags( int(__f1) & int(__f2) ); }
 | |
| 
 | |
|   constexpr socket_base::message_flags
 | |
|   operator|(socket_base::message_flags __f1, socket_base::message_flags __f2)
 | |
|   { return socket_base::message_flags( int(__f1) | int(__f2) ); }
 | |
| 
 | |
|   constexpr socket_base::message_flags
 | |
|   operator^(socket_base::message_flags __f1, socket_base::message_flags __f2)
 | |
|   { return socket_base::message_flags( int(__f1) ^ int(__f2) ); }
 | |
| 
 | |
|   constexpr socket_base::message_flags
 | |
|   operator~(socket_base::message_flags __f)
 | |
|   { return socket_base::message_flags( ~int(__f) ); }
 | |
| 
 | |
|   inline socket_base::message_flags&
 | |
|   operator&=(socket_base::message_flags& __f1, socket_base::message_flags __f2)
 | |
|   { return __f1 = (__f1 & __f2); }
 | |
| 
 | |
|   inline socket_base::message_flags&
 | |
|   operator|=(socket_base::message_flags& __f1, socket_base::message_flags __f2)
 | |
|   { return __f1 = (__f1 | __f2); }
 | |
| 
 | |
|   inline socket_base::message_flags&
 | |
|   operator^=(socket_base::message_flags& __f1, socket_base::message_flags __f2)
 | |
|   { return __f1 = (__f1 ^ __f2); }
 | |
| 
 | |
| #if _GLIBCXX_HAVE_UNISTD_H
 | |
| 
 | |
|   class __socket_impl
 | |
|   {
 | |
|   protected:
 | |
| 
 | |
|     using executor_type = io_context::executor_type;
 | |
|     using native_handle_type = int;
 | |
| 
 | |
|     explicit
 | |
|     __socket_impl(io_context& __ctx) : _M_ctx(std::addressof(__ctx)) { }
 | |
| 
 | |
|     __socket_impl(__socket_impl&& __rhs)
 | |
|     : _M_ctx(__rhs._M_ctx),
 | |
|       _M_sockfd(std::exchange(__rhs._M_sockfd, -1)),
 | |
|       _M_bits(std::exchange(__rhs._M_bits, {}))
 | |
|     { }
 | |
| 
 | |
|     __socket_impl&
 | |
|     operator=(__socket_impl&& __rhs)
 | |
|     {
 | |
|       _M_ctx = __rhs._M_ctx;
 | |
|       _M_sockfd = std::exchange(__rhs._M_sockfd, -1);
 | |
|       _M_bits = std::exchange(__rhs._M_bits, {});
 | |
|       return *this;
 | |
|     }
 | |
| 
 | |
|     ~__socket_impl() = default;
 | |
| 
 | |
|     __socket_impl(const __socket_impl&) = delete;
 | |
|     __socket_impl& operator=(const __socket_impl&) = delete;
 | |
| 
 | |
|     executor_type get_executor() noexcept { return _M_ctx->get_executor(); }
 | |
| 
 | |
|     native_handle_type native_handle() noexcept { return _M_sockfd; }
 | |
| 
 | |
|     bool is_open() const noexcept { return _M_sockfd != -1; }
 | |
| 
 | |
|     void
 | |
|     close(error_code& __ec)
 | |
|     {
 | |
|       if (is_open())
 | |
| 	{
 | |
| 	  cancel(__ec);
 | |
| 	  if (!__ec)
 | |
| 	    {
 | |
| 	      if (::close(_M_sockfd) == -1)
 | |
| 		__ec.assign(errno, generic_category());
 | |
| 	      else
 | |
| 		{
 | |
| 		  get_executor().context()._M_remove_fd(_M_sockfd);
 | |
| 		  _M_sockfd = -1;
 | |
| 		}
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     void cancel(error_code& __ec) { _M_ctx->cancel(_M_sockfd, __ec); }
 | |
| 
 | |
|     void
 | |
|     non_blocking(bool __mode, error_code&)
 | |
|     { _M_bits.non_blocking = __mode; }
 | |
| 
 | |
|     bool non_blocking() const { return _M_bits.non_blocking; }
 | |
| 
 | |
|     void
 | |
|     native_non_blocking(bool __mode, error_code& __ec)
 | |
|     {
 | |
|       int __flags = ::fcntl(_M_sockfd, F_GETFL, 0);
 | |
|       if (__flags >= 0)
 | |
| 	{
 | |
| 	  if (__mode)
 | |
| 	    __flags |= O_NONBLOCK;
 | |
| 	  else
 | |
| 	    __flags &= ~O_NONBLOCK;
 | |
| 	  __flags = ::fcntl(_M_sockfd, F_SETFL, __flags);
 | |
| 	}
 | |
|       if (__flags == -1)
 | |
| 	__ec.assign(errno, generic_category());
 | |
|       else
 | |
| 	{
 | |
| 	  __ec.clear();
 | |
| 	  _M_bits.native_non_blocking = __mode;
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     bool
 | |
|     native_non_blocking() const
 | |
|     {
 | |
|       if (_M_bits.native_non_blocking == -1)
 | |
| 	{
 | |
| 	  const int __flags = ::fcntl(_M_sockfd, F_GETFL, 0);
 | |
| 	  if (__flags == -1)
 | |
| 	    return 0;
 | |
| 	  _M_bits.native_non_blocking = __flags & O_NONBLOCK;
 | |
| 	}
 | |
|       return _M_bits.native_non_blocking;
 | |
|     }
 | |
| 
 | |
|     io_context*	_M_ctx;
 | |
|     int		_M_sockfd{-1};
 | |
|     struct {
 | |
|       unsigned		non_blocking : 1;
 | |
|       mutable signed	native_non_blocking : 2;
 | |
|       unsigned		enable_connection_aborted : 1;
 | |
|     } _M_bits{};
 | |
|   };
 | |
| 
 | |
|   template<typename _Protocol>
 | |
|     class __basic_socket_impl : public __socket_impl
 | |
|     {
 | |
|       using __base = __socket_impl;
 | |
| 
 | |
|     protected:
 | |
|       using protocol_type = _Protocol;
 | |
|       using endpoint_type = typename protocol_type::endpoint;
 | |
| 
 | |
|       explicit
 | |
|       __basic_socket_impl(io_context& __ctx) : __base(__ctx) { }
 | |
| 
 | |
|       __basic_socket_impl(__basic_socket_impl&&) = default;
 | |
| 
 | |
|       template<typename _OtherProtocol>
 | |
| 	__basic_socket_impl(__basic_socket_impl<_OtherProtocol>&& __rhs)
 | |
| 	: __base(std::move(__rhs)), _M_protocol(std::move(__rhs._M_protocol))
 | |
| 	{ }
 | |
| 
 | |
|       __basic_socket_impl&
 | |
|       operator=(__basic_socket_impl&& __rhs)
 | |
|       {
 | |
| 	if (this == std::addressof(__rhs))
 | |
| 	  return *this;
 | |
| 	_M_close();
 | |
| 	__base::operator=(std::move(__rhs));
 | |
| 	return *this;
 | |
|       }
 | |
| 
 | |
|       ~__basic_socket_impl() { _M_close(); }
 | |
| 
 | |
|       __basic_socket_impl(const __basic_socket_impl&) = delete;
 | |
|       __basic_socket_impl& operator=(const __basic_socket_impl&) = delete;
 | |
| 
 | |
|       void
 | |
|       open(const protocol_type& __protocol, error_code& __ec)
 | |
|       {
 | |
| 	if (is_open())
 | |
| 	  __ec = socket_errc::already_open;
 | |
| 	else
 | |
| 	  {
 | |
| 	    _M_protocol = __protocol;
 | |
| 	    _M_sockfd = ::socket(__protocol.family(), __protocol.type(),
 | |
| 				 __protocol.protocol());
 | |
| 	    if (is_open())
 | |
| 	      {
 | |
| 		get_executor().context()._M_add_fd(_M_sockfd);
 | |
| 	      __ec.clear();
 | |
| 	      }
 | |
| 	    else
 | |
| 	      __ec.assign(errno, std::generic_category());
 | |
| 	  }
 | |
|       }
 | |
| 
 | |
|       void
 | |
|       assign(const protocol_type& __protocol,
 | |
| 	     const native_handle_type& __native_socket,
 | |
| 	     error_code& __ec)
 | |
|       {
 | |
| 	if (is_open())
 | |
| 	  __ec = socket_errc::already_open;
 | |
| 	else
 | |
| 	  {
 | |
| 	    _M_protocol = __protocol;
 | |
| 	    _M_bits.native_non_blocking = -1;
 | |
| 	    _M_sockfd = __native_socket;
 | |
| 	    if (is_open())
 | |
| 	      {
 | |
| 		get_executor().context()._M_add_fd(_M_sockfd);
 | |
| 		__ec.clear();
 | |
| 	      }
 | |
| 	    else
 | |
| 	      __ec.assign(errno, std::generic_category());
 | |
| 	  }
 | |
|       }
 | |
| 
 | |
|       template<typename _SettableSocketOption>
 | |
| 	void
 | |
| 	set_option(const _SettableSocketOption& __option, error_code& __ec)
 | |
| 	{
 | |
| 	  int __result = ::setsockopt(_M_sockfd, __option.level(_M_protocol),
 | |
| 				      __option.name(_M_protocol),
 | |
| 				      __option.data(_M_protocol),
 | |
| 				      __option.size(_M_protocol));
 | |
| 	  if (__result == -1)
 | |
| 	    __ec.assign(errno, generic_category());
 | |
| 	  else
 | |
| 	    __ec.clear();
 | |
| 	}
 | |
| 
 | |
|       template<typename _GettableSocketOption>
 | |
| 	void
 | |
| 	get_option(_GettableSocketOption& __option, error_code& __ec) const
 | |
| 	{
 | |
| 	  int __result = ::getsockopt(_M_sockfd, __option.level(_M_protocol),
 | |
| 				      __option.name(_M_protocol),
 | |
| 				      __option.data(_M_protocol),
 | |
| 				      __option.size(_M_protocol));
 | |
| 	  if (__result == -1)
 | |
| 	    __ec.assign(errno, generic_category());
 | |
| 	  else
 | |
| 	    __ec.clear();
 | |
| 	}
 | |
| 
 | |
|       template<typename _IoControlCommand>
 | |
| 	void
 | |
| 	io_control(_IoControlCommand& __command, error_code& __ec)
 | |
| 	{
 | |
| 	  int __result = ::ioctl(_M_sockfd, __command.name(_M_protocol),
 | |
| 				 __command.data(_M_protocol));
 | |
| 	  if (__result == -1)
 | |
| 	    __ec.assign(errno, generic_category());
 | |
| 	  else
 | |
| 	    __ec.clear();
 | |
| 	}
 | |
| 
 | |
|       endpoint_type
 | |
|       local_endpoint(error_code& __ec) const
 | |
|       {
 | |
| 	endpoint_type __endpoint;
 | |
| 	socklen_t __endpoint_len = __endpoint.capacity();
 | |
| 	if (::getsockname(_M_sockfd, (sockaddr*)__endpoint.data(),
 | |
|                           &__endpoint_len) == -1)
 | |
| 	  {
 | |
| 	    __ec.assign(errno, generic_category());
 | |
| 	    return endpoint_type{};
 | |
| 	  }
 | |
| 	__ec.clear();
 | |
| 	__endpoint.resize(__endpoint_len);
 | |
| 	return __endpoint;
 | |
|       }
 | |
| 
 | |
|       void
 | |
|       bind(const endpoint_type& __endpoint, error_code& __ec)
 | |
|       {
 | |
| 	if (::bind(_M_sockfd, (sockaddr*)__endpoint.data(), __endpoint.size())
 | |
| 	    == -1)
 | |
| 	  __ec.assign(errno, generic_category());
 | |
| 	else
 | |
| 	  __ec.clear();
 | |
|       }
 | |
| 
 | |
|       _Protocol	_M_protocol{ endpoint_type{}.protocol() };
 | |
| 
 | |
|     private:
 | |
|       void
 | |
|       _M_close()
 | |
|       {
 | |
| 	if (is_open())
 | |
| 	  {
 | |
| 	    error_code __ec;
 | |
| 	    cancel(__ec);
 | |
| 	    set_option(socket_base::linger{false, chrono::seconds{}}, __ec);
 | |
| 	    ::close(_M_sockfd);
 | |
| 	  }
 | |
|       }
 | |
|     };
 | |
| 
 | |
|   template<typename _Protocol>
 | |
|     class basic_socket
 | |
|     : public socket_base, private __basic_socket_impl<_Protocol>
 | |
|     {
 | |
|       using __base = __basic_socket_impl<_Protocol>;
 | |
| 
 | |
|     public:
 | |
|       // types:
 | |
| 
 | |
|       typedef io_context::executor_type executor_type;
 | |
|       typedef int native_handle_type;
 | |
|       typedef _Protocol protocol_type;
 | |
|       typedef typename protocol_type::endpoint endpoint_type;
 | |
| 
 | |
|       // basic_socket operations:
 | |
| 
 | |
|       executor_type get_executor() noexcept { return __base::get_executor(); }
 | |
| 
 | |
|       native_handle_type
 | |
|       native_handle() noexcept { return __base::native_handle(); }
 | |
| 
 | |
|       void
 | |
|       open(const protocol_type& __protocol = protocol_type())
 | |
|       { open(__protocol, __throw_on_error{"basic_socket::open"}); }
 | |
| 
 | |
|       void
 | |
|       open(const protocol_type& __protocol, error_code& __ec)
 | |
|       { __base::open(__protocol, __ec); }
 | |
| 
 | |
|       void
 | |
|       assign(const protocol_type& __protocol,
 | |
| 	     const native_handle_type& __native_socket)
 | |
|       {
 | |
| 	assign(__protocol, __native_socket,
 | |
| 	       __throw_on_error{"basic_socket::assign"});
 | |
|       }
 | |
| 
 | |
|       void
 | |
|       assign(const protocol_type& __protocol,
 | |
| 	     const native_handle_type& __native_socket,
 | |
| 	     error_code& __ec)
 | |
|       { __base::assign(__protocol, __native_socket, __ec); }
 | |
| 
 | |
|       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 cancel() { cancel(__throw_on_error{"basic_socket::cancel"}); }
 | |
| 
 | |
|       void cancel(error_code& __ec) { __base::cancel(__ec); }
 | |
| 
 | |
|       template<typename _SettableSocketOption>
 | |
| 	void
 | |
| 	set_option(const _SettableSocketOption& __option)
 | |
| 	{ set_option(__option, __throw_on_error{"basic_socket::set_option"}); }
 | |
| 
 | |
|       template<typename _SettableSocketOption>
 | |
| 	void
 | |
| 	set_option(const _SettableSocketOption& __option, error_code& __ec)
 | |
| 	{ __base::set_option(__option, __ec); }
 | |
| 
 | |
|       template<typename _GettableSocketOption>
 | |
| 	void
 | |
| 	get_option(_GettableSocketOption& __option) const
 | |
| 	{ get_option(__option, __throw_on_error{"basic_socket::get_option"}); }
 | |
| 
 | |
|       template<typename _GettableSocketOption>
 | |
| 	void
 | |
| 	get_option(_GettableSocketOption& __option, error_code& __ec) const
 | |
| 	{ __base::get_option(__option, __ec); }
 | |
| 
 | |
|       template<typename _IoControlCommand>
 | |
| 	void
 | |
| 	io_control(_IoControlCommand& __command)
 | |
| 	{
 | |
| 	  io_control(__command, __throw_on_error{"basic_socket::io_control"});
 | |
| 	}
 | |
| 
 | |
|       template<typename _IoControlCommand>
 | |
| 	void
 | |
| 	io_control(_IoControlCommand& __command, error_code& __ec)
 | |
| 	{ __base::io_control(__command, __ec); }
 | |
| 
 | |
|       void
 | |
|       non_blocking(bool __mode)
 | |
|       { non_blocking(__mode, __throw_on_error{"basic_socket::non_blocking"}); }
 | |
| 
 | |
|       void
 | |
|       non_blocking(bool __mode, error_code& __ec)
 | |
|       { __base::non_blocking(__mode, __ec); }
 | |
| 
 | |
|       bool non_blocking() const { return __base::non_blocking(); }
 | |
| 
 | |
|       void
 | |
|       native_non_blocking(bool __mode)
 | |
|       {
 | |
| 	native_non_blocking(__mode, __throw_on_error{
 | |
| 	    "basic_socket::native_non_blocking"});
 | |
|       }
 | |
| 
 | |
|       void
 | |
|       native_non_blocking(bool __mode, error_code& __ec)
 | |
|       { __base::native_non_blocking(__mode, __ec); }
 | |
| 
 | |
|       bool
 | |
|       native_non_blocking() const
 | |
|       { return __base::native_non_blocking(); }
 | |
| 
 | |
|       bool at_mark() const
 | |
|       { return at_mark(__throw_on_error{"basic_socket::at_mark"}); }
 | |
| 
 | |
|       bool
 | |
|       at_mark(error_code& __ec) const
 | |
|       {
 | |
| 	const int __result = ::sockatmark(native_handle());
 | |
| 	if (__result == -1)
 | |
| 	  __ec.assign(errno, generic_category());
 | |
| 	else
 | |
| 	  {
 | |
| 	    __ec.clear();
 | |
| 	    return __result;
 | |
| 	  }
 | |
|       }
 | |
| 
 | |
|       size_t
 | |
|       available() const
 | |
|       { return available(__throw_on_error{"basic_socket::available"}); }
 | |
| 
 | |
|       size_t
 | |
|       available(error_code& __ec) const
 | |
|       {
 | |
| 	if (!is_open())
 | |
| 	  {
 | |
| 	    __ec = std::make_error_code(errc::bad_file_descriptor);
 | |
| 	    return 0;
 | |
| 	  }
 | |
| #ifdef FIONREAD
 | |
| 	int __avail = 0;
 | |
| 	if (::ioctl(this->_M_sockfd, FIONREAD, &__avail) == -1)
 | |
| 	  {
 | |
| 	    __ec.assign(errno, generic_category());
 | |
| 	    return 0;
 | |
| 	  }
 | |
| 	__ec.clear();
 | |
| 	return __avail;
 | |
| #else
 | |
| 	return 0;
 | |
| #endif
 | |
|       }
 | |
| 
 | |
|       void
 | |
|       bind(const endpoint_type& __endpoint)
 | |
|       { return bind(__endpoint, __throw_on_error{"basic_socket::bind"}); }
 | |
| 
 | |
|       void
 | |
|       bind(const endpoint_type& __endpoint, error_code& __ec)
 | |
|       { __base::bind(__endpoint, __ec); }
 | |
| 
 | |
|       void shutdown(shutdown_type __what)
 | |
|       { return shutdown(__what, __throw_on_error{"basic_socket::shutdown"}); }
 | |
| 
 | |
|       void
 | |
|       shutdown(shutdown_type __what, error_code& __ec)
 | |
|       {
 | |
| 	if (::shutdown(native_handle(), static_cast<int>(__what)) == -1)
 | |
| 	  __ec.assign(errno, generic_category());
 | |
| 	else
 | |
| 	  __ec.clear();
 | |
|       }
 | |
| 
 | |
|       endpoint_type
 | |
|       local_endpoint() const
 | |
|       {
 | |
| 	return local_endpoint(
 | |
| 	    __throw_on_error{"basic_socket::local_endpoint"});
 | |
|       }
 | |
| 
 | |
|       endpoint_type
 | |
|       local_endpoint(error_code& __ec) const
 | |
|       { return __base::local_endpoint(__ec); }
 | |
| 
 | |
|       endpoint_type
 | |
|       remote_endpoint() const
 | |
|       {
 | |
| 	return remote_endpoint(
 | |
| 	    __throw_on_error{"basic_socket::remote_endpoint"});
 | |
|       }
 | |
| 
 | |
|       endpoint_type
 | |
|       remote_endpoint(error_code& __ec) const
 | |
|       {
 | |
| 	endpoint_type __endpoint;
 | |
| 	socklen_t __endpoint_len = __endpoint.capacity();
 | |
| 	if (::getpeername(this->_M_sockfd, (sockaddr*)__endpoint.data(),
 | |
|                           &__endpoint_len)
 | |
| 	    == -1)
 | |
| 	  {
 | |
| 	    __ec.assign(errno, generic_category());
 | |
| 	    return endpoint_type{};
 | |
| 	  }
 | |
| 	__ec.clear();
 | |
| 	__endpoint.resize(__endpoint_len);
 | |
| 	return __endpoint;
 | |
|       }
 | |
| 
 | |
|       void
 | |
|       connect(const endpoint_type& __endpoint)
 | |
|       {
 | |
| 	return connect(__endpoint, __throw_on_error{"basic_socket::connect"});
 | |
|       }
 | |
| 
 | |
|       void
 | |
|       connect(const endpoint_type& __endpoint, error_code& __ec)
 | |
|       {
 | |
| 	if (!is_open())
 | |
| 	  {
 | |
| 	    open(__endpoint.protocol(), __ec);
 | |
| 	    if (__ec)
 | |
| 	      return;
 | |
| 	  }
 | |
| 	if (::connect(native_handle(), (const sockaddr*)__endpoint.data(),
 | |
| 		      __endpoint.size()) == -1)
 | |
| 	  __ec.assign(errno, generic_category());
 | |
| 	else
 | |
| 	  __ec.clear();
 | |
|       }
 | |
| 
 | |
|       template<typename _CompletionToken>
 | |
| 	__deduced_t<_CompletionToken, void(error_code)>
 | |
| 	async_connect(const endpoint_type& __endpoint,
 | |
| 		      _CompletionToken&& __token)
 | |
| 	{
 | |
| 	  async_completion<_CompletionToken, void(error_code)> __init{__token};
 | |
| 
 | |
| 	  if (!is_open())
 | |
| 	    {
 | |
| 	      error_code __ec;
 | |
| 	      open(__endpoint.protocol(), __ec);
 | |
| 	      if (__ec)
 | |
| 		{
 | |
|                   auto __ex = net::get_associated_executor(
 | |
|                       __init.completion_handler, get_executor());
 | |
|                   auto __a = get_associated_allocator(
 | |
|                       __init.completion_handler, std::allocator<void>());
 | |
|                   __ex.post(
 | |
|                       [__h=std::move(__init.completion_handler), __ec]
 | |
|                       () mutable
 | |
|                       { __h(__ec); }, __a);
 | |
| 		  return __init.result.get();
 | |
| 		}
 | |
| 	    }
 | |
| 
 | |
| 	  get_executor().context().async_wait( native_handle(),
 | |
| 	      socket_base::wait_read,
 | |
| 	      [__h = std::move(__init.completion_handler),
 | |
|                __ep = std::move(__endpoint),
 | |
|                __fd = native_handle()]
 | |
|                (error_code __ec) mutable {
 | |
|                   if (!__ec && ::connect(__fd, (const sockaddr*)__ep.data(),
 | |
| 					 __ep.size()) == -1)
 | |
|                     __ec.assign(errno, generic_category());
 | |
| 		  __h(__ec);
 | |
| 	      });
 | |
| 	  return __init.result.get();
 | |
| 	}
 | |
| 
 | |
|       void
 | |
|       wait(wait_type __w)
 | |
|       { return wait(__w, __throw_on_error{"basic_socket::wait"}); }
 | |
| 
 | |
|       void
 | |
|       wait(wait_type __w, error_code& __ec)
 | |
|       {
 | |
| 	::pollfd __fd;
 | |
| 	__fd.fd = native_handle();
 | |
| 	__fd.events = static_cast<int>(__w);
 | |
| 	int __res = ::poll(&__fd, 1, -1);
 | |
| 	if (__res == -1)
 | |
| 	  __ec.assign(errno, generic_category());
 | |
| 	else
 | |
| 	  __ec.clear();
 | |
|       }
 | |
| 
 | |
|       template<typename _CompletionToken>
 | |
| 	__deduced_t<_CompletionToken, void(error_code)>
 | |
| 	async_wait(wait_type __w, _CompletionToken&& __token)
 | |
| 	{
 | |
| 	  async_completion<_CompletionToken, void(error_code)> __init{__token};
 | |
| 	  get_executor().context().async_wait( native_handle(),
 | |
| 	      static_cast<int>(__w),
 | |
| 	      [__h = std::move(__init.completion_handler)]
 | |
|               (error_code __ec) mutable {
 | |
| 		  __h(__ec);
 | |
| 	      });
 | |
| 	  return __init.result.get();
 | |
| 	}
 | |
| 
 | |
|     protected:
 | |
|       // construct / copy / destroy:
 | |
| 
 | |
|       using __base::__base;
 | |
| 
 | |
|       explicit
 | |
|       basic_socket(io_context& __ctx) : __base(__ctx) { }
 | |
| 
 | |
|       basic_socket(io_context& __ctx, const protocol_type& __protocol)
 | |
|       : __base(__ctx)
 | |
|       { open(__protocol); }
 | |
| 
 | |
|       basic_socket(io_context& __ctx, const endpoint_type& __endpoint)
 | |
|       : basic_socket(std::addressof(__ctx), __endpoint.protocol())
 | |
|       { bind(__endpoint); }
 | |
| 
 | |
|       basic_socket(io_context& __ctx, const protocol_type& __protocol,
 | |
| 		   const native_handle_type& __native_socket)
 | |
|       : __base(__ctx)
 | |
|       { assign(__protocol, __native_socket); }
 | |
| 
 | |
|       basic_socket(const basic_socket&) = delete;
 | |
| 
 | |
|       basic_socket(basic_socket&& __rhs) = default;
 | |
| 
 | |
|       template<typename _OtherProtocol, typename _Requires
 | |
| 	       = _Require<is_convertible<_OtherProtocol, _Protocol>>>
 | |
| 	basic_socket(basic_socket<_OtherProtocol>&& __rhs)
 | |
| 	: __base(std::move(__rhs)) { }
 | |
| 
 | |
|       ~basic_socket() = default;
 | |
| 
 | |
|       basic_socket& operator=(const basic_socket&) = delete;
 | |
| 
 | |
|       basic_socket& operator=(basic_socket&& __rhs) = default;
 | |
| 
 | |
|       template<typename _OtherProtocol>
 | |
| 	enable_if_t<is_convertible<_OtherProtocol, _Protocol>::value,
 | |
| 		    basic_socket&>
 | |
| 	operator=(basic_socket<_OtherProtocol>&& __rhs)
 | |
|         { return *this = basic_socket{std::move(__rhs)}; }
 | |
|     };
 | |
| 
 | |
|   template<typename _Protocol>
 | |
|     class basic_datagram_socket : public basic_socket<_Protocol>
 | |
|     {
 | |
|       using __base = basic_socket<_Protocol>;
 | |
| 
 | |
|     public:
 | |
|       // types:
 | |
| 
 | |
|       typedef int native_handle_type;
 | |
|       typedef _Protocol protocol_type;
 | |
|       typedef typename protocol_type::endpoint endpoint_type;
 | |
| 
 | |
|       // construct / copy / destroy:
 | |
| 
 | |
|       explicit
 | |
|       basic_datagram_socket(io_context& __ctx) : __base(__ctx) { }
 | |
| 
 | |
|       basic_datagram_socket(io_context& __ctx, const protocol_type& __protocol)
 | |
|       : __base(__ctx, __protocol) { }
 | |
| 
 | |
|       basic_datagram_socket(io_context& __ctx, const endpoint_type& __endpoint)
 | |
|       : __base(__ctx, __endpoint) { }
 | |
| 
 | |
|       basic_datagram_socket(io_context& __ctx, const protocol_type& __protocol,
 | |
| 			    const native_handle_type& __native_socket)
 | |
|       : __base(__ctx, __protocol, __native_socket) { }
 | |
| 
 | |
|       basic_datagram_socket(const basic_datagram_socket&) = delete;
 | |
| 
 | |
|       basic_datagram_socket(basic_datagram_socket&& __rhs) = default;
 | |
| 
 | |
|       template<typename _OtherProtocol, typename _Requires
 | |
| 	       = _Require<is_convertible<_OtherProtocol, _Protocol>>>
 | |
| 	basic_datagram_socket(basic_datagram_socket<_OtherProtocol>&& __rhs)
 | |
| 	: __base(std::move(__rhs)) { }
 | |
| 
 | |
|       ~basic_datagram_socket() = default;
 | |
| 
 | |
|       basic_datagram_socket& operator=(const basic_datagram_socket&) = delete;
 | |
| 
 | |
|       basic_datagram_socket& operator=(basic_datagram_socket&& __rhs) = default;
 | |
| 
 | |
|       template<typename _OtherProtocol>
 | |
| 	enable_if_t<is_convertible<_OtherProtocol, _Protocol>::value,
 | |
| 		    basic_datagram_socket&>
 | |
| 	operator=(basic_datagram_socket<_OtherProtocol>&& __rhs)
 | |
| 	{
 | |
| 	  __base::operator=(std::move(__rhs));
 | |
| 	  return *this;
 | |
| 	}
 | |
| 
 | |
|       // basic_datagram_socket operations:
 | |
| 
 | |
|       template<typename _MutableBufferSequence>
 | |
| 	size_t
 | |
| 	receive(const _MutableBufferSequence& __buffers)
 | |
| 	{
 | |
| 	  return receive(__buffers, socket_base::message_flags(),
 | |
| 			 __throw_on_error{"basic_datagram_socket::receive"});
 | |
| 	}
 | |
| 
 | |
|       template<typename _MutableBufferSequence>
 | |
| 	size_t
 | |
| 	receive(const _MutableBufferSequence& __buffers, error_code& __ec)
 | |
|         { return receive(__buffers, socket_base::message_flags(), __ec); }
 | |
| 
 | |
|       template<typename _MutableBufferSequence>
 | |
| 	size_t
 | |
| 	receive(const _MutableBufferSequence& __buffers,
 | |
| 		       socket_base::message_flags __flags)
 | |
| 	{
 | |
| 	  return receive(__buffers, __flags,
 | |
| 			 __throw_on_error{"basic_datagram_socket::receive"});
 | |
| 	}
 | |
| 
 | |
|       template<typename _MutableBufferSequence>
 | |
| 	size_t
 | |
| 	receive(const _MutableBufferSequence& __buffers,
 | |
| 		socket_base::message_flags __flags, error_code& __ec)
 | |
| 	{
 | |
| 	  socket_base::__msg_hdr __msg(__buffers);
 | |
| 	  ssize_t __result = ::recvmsg(this->native_handle(), &__msg,
 | |
| 				       static_cast<int>(__flags));
 | |
| 	  if (__result == -1)
 | |
|             {
 | |
|               __ec.assign(errno, generic_category());
 | |
|               return 0;
 | |
|             }
 | |
|           __ec.clear();
 | |
|           return __result;
 | |
| 	}
 | |
| 
 | |
|       template<typename _MutableBufferSequence, typename _CompletionToken>
 | |
| 	__deduced_t<_CompletionToken, void(error_code, size_t)>
 | |
| 	async_receive(const _MutableBufferSequence& __buffers,
 | |
| 		      _CompletionToken&& __token)
 | |
| 	{
 | |
| 	  return async_receive(__buffers, socket_base::message_flags(),
 | |
| 			       std::forward<_CompletionToken>(__token));
 | |
| 	}
 | |
| 
 | |
|       template<typename _MutableBufferSequence, typename _CompletionToken>
 | |
| 	__deduced_t<_CompletionToken, void(error_code, size_t)>
 | |
| 	async_receive(const _MutableBufferSequence& __buffers,
 | |
| 		      socket_base::message_flags __flags,
 | |
| 		      _CompletionToken&& __token)
 | |
| 	{
 | |
|           async_completion<_CompletionToken, void(error_code, size_t)>
 | |
|             __init{__token};
 | |
| 
 | |
| 	  this->get_executor().context().async_wait(this->native_handle(),
 | |
| 	      socket_base::wait_read,
 | |
| 	      [__h = std::move(__init.completion_handler),
 | |
|                &__buffers, __flags = static_cast<int>(__flags),
 | |
|                __fd = this->native_handle()]
 | |
|               (error_code __ec) mutable {
 | |
|                   if (__ec)
 | |
|                     {
 | |
|                       __h(__ec);
 | |
|                       return;
 | |
|                     }
 | |
|                   socket_base::__msg_hdr __msg(__buffers);
 | |
|                   ssize_t __result = ::recvmsg(__fd, &__msg, __flags);
 | |
|                   if (__result == -1)
 | |
|                     {
 | |
|                       __ec.assign(errno, generic_category());
 | |
|                       __result = 0;
 | |
|                     }
 | |
|                   else
 | |
|                     __ec.clear();
 | |
| 		  __h(__ec, __result);
 | |
| 	      });
 | |
| 	  return __init.result.get();
 | |
| 	}
 | |
| 
 | |
|       template<typename _MutableBufferSequence>
 | |
| 	size_t
 | |
| 	receive_from(const _MutableBufferSequence& __buffers,
 | |
| 		     endpoint_type& __sender)
 | |
| 	{
 | |
| 	  return receive_from(__buffers, __sender,
 | |
| 			      socket_base::message_flags(),
 | |
| 			      __throw_on_error{
 | |
| 				  "basic_datagram_socket::receive_from"});
 | |
| 	}
 | |
| 
 | |
|       template<typename _MutableBufferSequence>
 | |
| 	size_t
 | |
| 	receive_from(const _MutableBufferSequence& __buffers,
 | |
| 		     endpoint_type& __sender, error_code& __ec)
 | |
| 	{
 | |
| 	  return receive_from(__buffers, __sender,
 | |
| 			      socket_base::message_flags(), __ec);
 | |
| 	}
 | |
| 
 | |
|       template<typename _MutableBufferSequence>
 | |
| 	size_t
 | |
| 	receive_from(const _MutableBufferSequence& __buffers,
 | |
| 		     endpoint_type& __sender,
 | |
| 		     socket_base::message_flags __flags)
 | |
| 	{
 | |
| 	  return receive_from(__buffers, __sender, __flags,
 | |
| 			      __throw_on_error{
 | |
| 				  "basic_datagram_socket::receive_from"});
 | |
| 	}
 | |
| 
 | |
|       template<typename _MutableBufferSequence>
 | |
| 	size_t
 | |
| 	receive_from(const _MutableBufferSequence& __buffers,
 | |
| 		     endpoint_type& __sender,
 | |
| 		     socket_base::message_flags __flags,
 | |
| 		     error_code& __ec)
 | |
| 	{
 | |
| 	  socket_base::__msg_hdr __msg(__buffers, __sender);
 | |
| 	  ssize_t __result = ::recvmsg(this->native_handle(), &__msg,
 | |
| 				       static_cast<int>(__flags));
 | |
| 	  if (__result == -1)
 | |
|             {
 | |
|               __ec.assign(errno, generic_category());
 | |
|               return 0;
 | |
|             }
 | |
|           __ec.clear();
 | |
|           __sender.resize(__msg.msg_namelen);
 | |
|           return __result;
 | |
| 	}
 | |
| 
 | |
|       template<typename _MutableBufferSequence, typename _CompletionToken>
 | |
| 	__deduced_t<_CompletionToken, void(error_code, size_t)>
 | |
| 	async_receive_from(const _MutableBufferSequence& __buffers,
 | |
| 			   endpoint_type& __sender,
 | |
| 			   _CompletionToken&& __token)
 | |
| 	{
 | |
| 	  return async_receive_from(__buffers, __sender,
 | |
| 				    socket_base::message_flags(),
 | |
| 				    std::forward<_CompletionToken>(__token));
 | |
| 	}
 | |
| 
 | |
|       template<typename _MutableBufferSequence, typename _CompletionToken>
 | |
| 	__deduced_t<_CompletionToken, void(error_code, size_t)>
 | |
| 	async_receive_from(const _MutableBufferSequence& __buffers,
 | |
| 			   endpoint_type& __sender,
 | |
| 			   socket_base::message_flags __flags,
 | |
| 			   _CompletionToken&& __token)
 | |
| 	{
 | |
| 	  async_completion<_CompletionToken, void(error_code, size_t)>
 | |
|             __init{__token};
 | |
| 
 | |
| 	  this->get_executor().context().async_wait( this->native_handle(),
 | |
| 	      socket_base::wait_read,
 | |
| 	      [__h = std::move(__init.completion_handler),
 | |
|                &__buffers, __flags = static_cast<int>(__flags),
 | |
|                __sender = std::move(__sender),
 | |
|                __fd = this->native_handle()]
 | |
|               (error_code __ec) mutable {
 | |
|                   if (__ec)
 | |
|                     {
 | |
|                       __h(__ec);
 | |
|                       return;
 | |
|                     }
 | |
|                   socket_base::__msg_hdr __msg(__buffers, __sender);
 | |
|                   ssize_t __result = ::recvmsg(__fd, &__msg, __flags);
 | |
|                   if (__result == -1)
 | |
|                     {
 | |
|                       __ec.assign(errno, generic_category());
 | |
|                       __result = 0;
 | |
|                     }
 | |
|                   else
 | |
|                     {
 | |
|                       __ec.clear();
 | |
|                       __sender.resize(__msg.msg_namelen);
 | |
|                     }
 | |
| 		  __h(__ec, __result);
 | |
| 	      });
 | |
| 	  return __init.result.get();
 | |
| 	}
 | |
| 
 | |
|       template<typename _ConstBufferSequence>
 | |
| 	size_t
 | |
| 	send(const _ConstBufferSequence& __buffers)
 | |
| 	{
 | |
| 	  return send(__buffers, socket_base::message_flags(),
 | |
| 		      __throw_on_error{"basic_datagram_socket::send"});
 | |
| 	}
 | |
| 
 | |
|       template<typename _ConstBufferSequence>
 | |
| 	size_t
 | |
| 	send(const _ConstBufferSequence& __buffers, error_code& __ec)
 | |
| 	{ return send(__buffers, socket_base::message_flags(), __ec); }
 | |
| 
 | |
|       template<typename _ConstBufferSequence>
 | |
| 	size_t
 | |
| 	send(const _ConstBufferSequence& __buffers,
 | |
| 	     socket_base::message_flags __flags)
 | |
| 	{
 | |
| 	  return send(__buffers, __flags,
 | |
| 		      __throw_on_error{"basic_datagram_socket::send"});
 | |
| 	}
 | |
| 
 | |
|       template<typename _ConstBufferSequence>
 | |
| 	size_t
 | |
| 	send(const _ConstBufferSequence& __buffers,
 | |
| 	     socket_base::message_flags __flags, error_code& __ec)
 | |
| 	{
 | |
| 	  socket_base::__msg_hdr __msg(__buffers);
 | |
| 	  ssize_t __result = ::sendmsg(this->native_handle(), &__msg,
 | |
| 				       static_cast<int>(__flags));
 | |
| 	  if (__result == -1)
 | |
|             {
 | |
|               __ec.assign(errno, generic_category());
 | |
|               return 0;
 | |
|             }
 | |
|           __ec.clear();
 | |
|           return __result;
 | |
| 	}
 | |
| 
 | |
|       template<typename _ConstBufferSequence, typename _CompletionToken>
 | |
| 	__deduced_t<_CompletionToken, void(error_code, size_t)>
 | |
| 	async_send(const _ConstBufferSequence& __buffers,
 | |
| 			_CompletionToken&& __token)
 | |
| 	{
 | |
| 	  return async_send(__buffers, socket_base::message_flags(),
 | |
| 			    std::forward<_CompletionToken>(__token));
 | |
| 	}
 | |
| 
 | |
|       template<typename _ConstBufferSequence, typename _CompletionToken>
 | |
| 	__deduced_t<_CompletionToken, void(error_code, size_t)>
 | |
| 	async_send(const _ConstBufferSequence& __buffers,
 | |
| 		   socket_base::message_flags __flags,
 | |
| 		   _CompletionToken&& __token)
 | |
| 	{
 | |
| 	  async_completion<_CompletionToken, void(error_code, size_t)>
 | |
|             __init{__token};
 | |
| 
 | |
| 	  this->get_executor().context().async_wait( this->native_handle(),
 | |
| 	      socket_base::wait_write,
 | |
| 	      [__h = std::move(__init.completion_handler),
 | |
|                &__buffers, __flags = static_cast<int>(__flags),
 | |
|                __fd = this->native_handle()]
 | |
|               (error_code __ec) mutable {
 | |
|                   if (__ec)
 | |
|                     {
 | |
|                       __h(__ec);
 | |
|                       return;
 | |
|                     }
 | |
|                   socket_base::__msg_hdr __msg(__buffers);
 | |
|                   ssize_t __result = ::sendmsg(__fd, &__msg, __flags);
 | |
|                   if (__result == -1)
 | |
|                     {
 | |
|                       __ec.assign(errno, generic_category());
 | |
|                       __result = 0;
 | |
|                     }
 | |
|                   else
 | |
|                     __ec.clear();
 | |
| 		  __h(__ec, __result);
 | |
| 	      });
 | |
| 	  return __init.result.get();
 | |
| 	}
 | |
| 
 | |
|       template<typename _ConstBufferSequence>
 | |
| 	size_t
 | |
| 	send_to(const _ConstBufferSequence& __buffers,
 | |
| 	        const endpoint_type& __recipient)
 | |
| 	{
 | |
| 	  return send_to(__buffers, __recipient,
 | |
| 			 socket_base::message_flags(),
 | |
| 			 __throw_on_error{"basic_datagram_socket::send_to"});
 | |
| 	}
 | |
| 
 | |
|       template<typename _ConstBufferSequence>
 | |
| 	size_t
 | |
| 	send_to(const _ConstBufferSequence& __buffers,
 | |
| 		const endpoint_type& __recipient, error_code& __ec)
 | |
| 	{
 | |
| 	  return send_to(__buffers, __recipient,
 | |
| 			 socket_base::message_flags(), __ec);
 | |
| 	}
 | |
| 
 | |
|       template<typename _ConstBufferSequence>
 | |
| 	size_t
 | |
| 	send_to(const _ConstBufferSequence& __buffers,
 | |
| 		const endpoint_type& __recipient,
 | |
| 		socket_base::message_flags __flags)
 | |
| 	{
 | |
| 	  return send_to(__buffers, __recipient, __flags,
 | |
| 			 __throw_on_error{"basic_datagram_socket::send_to"});
 | |
| 	}
 | |
| 
 | |
|       template<typename _ConstBufferSequence>
 | |
| 	size_t
 | |
| 	send_to(const _ConstBufferSequence& __buffers,
 | |
| 	        const endpoint_type& __recipient,
 | |
| 		socket_base::message_flags __flags, error_code& __ec)
 | |
| 	{
 | |
| 	  socket_base::__msg_hdr __msg(__buffers, __recipient);
 | |
| 	  ssize_t __result = ::sendmsg(this->native_handle(), &__msg,
 | |
| 				       static_cast<int>(__flags));
 | |
| 	  if (__result == -1)
 | |
|             {
 | |
|               __ec.assign(errno, generic_category());
 | |
|               return 0;
 | |
|             }
 | |
|           __ec.clear();
 | |
|           __recipient.resize(__msg.msg_namelen);
 | |
|           return __result;
 | |
| 	}
 | |
| 
 | |
|       template<typename _ConstBufferSequence, typename _CompletionToken>
 | |
| 	__deduced_t<_CompletionToken, void(error_code, size_t)>
 | |
| 	async_send_to(const _ConstBufferSequence& __buffers,
 | |
| 		      const endpoint_type& __recipient,
 | |
| 		      _CompletionToken&& __token)
 | |
| 	{
 | |
| 	  return async_send_to(__buffers, __recipient,
 | |
| 			       socket_base::message_flags(),
 | |
| 			       std::forward<_CompletionToken>(__token));
 | |
| 	}
 | |
| 
 | |
|       template<typename _ConstBufferSequence, typename _CompletionToken>
 | |
| 	__deduced_t<_CompletionToken, void(error_code, size_t)>
 | |
| 	async_send_to(const _ConstBufferSequence& __buffers,
 | |
| 		      const endpoint_type& __recipient,
 | |
| 		      socket_base::message_flags __flags,
 | |
| 		      _CompletionToken&& __token)
 | |
| 	{
 | |
| 	  async_completion<_CompletionToken, void(error_code, size_t)>
 | |
|             __init{__token};
 | |
| 
 | |
| 	  this->get_executor().context().async_wait( this->native_handle(),
 | |
| 	      socket_base::wait_write,
 | |
| 	      [__h = std::move(__init.completion_handler),
 | |
|                &__buffers, __flags = static_cast<int>(__flags),
 | |
|                __recipient = std::move(__recipient),
 | |
|                __fd = this->native_handle()]
 | |
|               (error_code __ec) mutable {
 | |
|                   if (__ec)
 | |
|                     {
 | |
|                       __h(__ec);
 | |
|                       return;
 | |
|                     }
 | |
|                   socket_base::__msg_hdr __msg(__buffers, __recipient);
 | |
|                   ssize_t __result = ::sendmsg(__fd, &__msg, __flags);
 | |
|                   if (__result == -1)
 | |
|                     {
 | |
|                       __ec.assign(errno, generic_category());
 | |
|                       __result = 0;
 | |
|                     }
 | |
|                   else
 | |
|                     {
 | |
|                       __ec.clear();
 | |
|                       __recipient.resize(__msg.msg_namelen);
 | |
|                     }
 | |
| 		  __h(__ec, __result);
 | |
| 	      });
 | |
| 	  return __init.result.get();
 | |
| 	}
 | |
|     };
 | |
| 
 | |
|   template<typename _Protocol>
 | |
|     class basic_stream_socket : public basic_socket<_Protocol>
 | |
|     {
 | |
|       using __base = basic_socket<_Protocol>;
 | |
| 
 | |
|     public:
 | |
|       // types:
 | |
| 
 | |
|       typedef int native_handle_type;
 | |
|       typedef _Protocol protocol_type;
 | |
|       typedef typename protocol_type::endpoint endpoint_type;
 | |
| 
 | |
|       // construct / copy / destroy:
 | |
| 
 | |
|       explicit
 | |
|       basic_stream_socket(io_context& __ctx) : __base(__ctx) { }
 | |
| 
 | |
|       basic_stream_socket(io_context& __ctx, const protocol_type& __protocol)
 | |
|       : __base(__ctx, __protocol) { }
 | |
| 
 | |
|       basic_stream_socket(io_context& __ctx, const endpoint_type& __endpoint)
 | |
|       : __base(__ctx, __endpoint) { }
 | |
| 
 | |
|       basic_stream_socket(io_context& __ctx, const protocol_type& __protocol,
 | |
| 			  const native_handle_type& __native_socket)
 | |
|       : __base(__ctx, __protocol, __native_socket) { }
 | |
| 
 | |
|       basic_stream_socket(const basic_stream_socket&) = delete;
 | |
| 
 | |
|       basic_stream_socket(basic_stream_socket&& __rhs) = default;
 | |
| 
 | |
|       template<typename _OtherProtocol, typename _Requires
 | |
| 	       = _Require<is_convertible<_OtherProtocol, _Protocol>>>
 | |
| 	basic_stream_socket(basic_stream_socket<_OtherProtocol>&& __rhs)
 | |
| 	: __base(std::move(__rhs)) { }
 | |
| 
 | |
|       ~basic_stream_socket() = default;
 | |
| 
 | |
|       basic_stream_socket& operator=(const basic_stream_socket&) = delete;
 | |
| 
 | |
|       basic_stream_socket& operator=(basic_stream_socket&& __rhs) = default;
 | |
| 
 | |
|       template<class _OtherProtocol>
 | |
| 	enable_if_t<is_convertible<_OtherProtocol, _Protocol>::value,
 | |
| 		    basic_stream_socket&>
 | |
| 	operator=(basic_stream_socket<_OtherProtocol>&& __rhs)
 | |
| 	{
 | |
| 	  __base::operator=(std::move(__rhs));
 | |
| 	  return *this;
 | |
| 	}
 | |
| 
 | |
|       // basic_stream_socket operations:
 | |
| 
 | |
|       template<class _MutableBufferSequence>
 | |
| 	size_t
 | |
| 	receive(const _MutableBufferSequence& __buffers)
 | |
| 	{
 | |
| 	  return receive(__buffers, socket_base::message_flags(),
 | |
| 			 __throw_on_error{"basic_stream_socket::receive"});
 | |
| 	}
 | |
| 
 | |
|       template<class _MutableBufferSequence>
 | |
| 	size_t
 | |
| 	receive(const _MutableBufferSequence& __buffers, error_code& __ec)
 | |
|         { return receive(__buffers, socket_base::message_flags(), __ec); }
 | |
| 
 | |
|       template<class _MutableBufferSequence>
 | |
| 	size_t
 | |
| 	receive(const _MutableBufferSequence& __buffers,
 | |
| 		socket_base::message_flags __flags)
 | |
| 	{
 | |
| 	  return receive(__buffers, __flags,
 | |
| 			 __throw_on_error{"basic_stream_socket::receive"});
 | |
| 	}
 | |
| 
 | |
|       template<class _MutableBufferSequence>
 | |
| 	size_t
 | |
| 	receive(const _MutableBufferSequence& __buffers,
 | |
| 		socket_base::message_flags __flags, error_code& __ec)
 | |
| 	{
 | |
| 	  if (__buffer_empty(__buffers))
 | |
| 	    {
 | |
| 	      __ec.clear();
 | |
| 	      return 0;
 | |
| 	    }
 | |
| 
 | |
| 	  socket_base::__msg_hdr __msg(__buffers);
 | |
| 	  ssize_t __result = ::recvmsg(this->native_handle(), &__msg,
 | |
| 				       static_cast<int>(__flags));
 | |
| 	  if (__result >= 0)
 | |
| 	    {
 | |
| 	      __ec.clear();
 | |
| 	      return __result;
 | |
| 	    }
 | |
| 	  __ec.assign(errno, generic_category());
 | |
| 	  return 0;
 | |
| 	}
 | |
| 
 | |
|       template<class _MutableBufferSequence, class _CompletionToken>
 | |
| 	__deduced_t<_CompletionToken, void(error_code, size_t)>
 | |
| 	async_receive(const _MutableBufferSequence& __buffers,
 | |
| 		      _CompletionToken&& __token)
 | |
| 	{
 | |
| 	  return async_receive(__buffers, socket_base::message_flags(),
 | |
| 			       std::forward<_CompletionToken>(__token));
 | |
| 	}
 | |
| 
 | |
|       template<class _MutableBufferSequence, class _CompletionToken>
 | |
| 	__deduced_t<_CompletionToken, void(error_code, size_t)>
 | |
| 	async_receive(const _MutableBufferSequence& __buffers,
 | |
| 		      socket_base::message_flags __flags,
 | |
| 		      _CompletionToken&& __token)
 | |
| 	{
 | |
| 	  async_completion<_CompletionToken, void(error_code, size_t)>
 | |
|             __init{__token};
 | |
| 
 | |
|           if (__buffer_empty(__buffers))
 | |
| 	    {
 | |
|               auto __ex = net::get_associated_executor(
 | |
|                   __init.completion_handler, this->get_executor());
 | |
|               auto __a = get_associated_allocator(
 | |
|                   __init.completion_handler, std::allocator<void>());
 | |
|               __ex.post(
 | |
|                   [__h=std::move(__init.completion_handler)] () mutable
 | |
|                   { __h(error_code{}, 0); }, __a);
 | |
|               return __init.result.get();
 | |
| 	    }
 | |
| 
 | |
|           this->get_executor().context().async_wait(this->native_handle(),
 | |
| 	      socket_base::wait_read,
 | |
| 	      [__h = std::move(__init.completion_handler),
 | |
|                &__buffers, __flags = static_cast<int>(__flags),
 | |
|                __fd = this->native_handle()]
 | |
|               (error_code __ec) mutable {
 | |
|                   if (__ec)
 | |
|                     {
 | |
|                       __h(__ec);
 | |
|                       return;
 | |
|                     }
 | |
|                   socket_base::__msg_hdr __msg(__buffers);
 | |
|                   ssize_t __result = ::recvmsg(__fd, &__msg, __flags);
 | |
|                   if (__result == -1)
 | |
|                     {
 | |
|                       __ec.assign(errno, generic_category());
 | |
|                       __result = 0;
 | |
|                     }
 | |
|                   else
 | |
|                     __ec.clear();
 | |
| 		  __h(__ec, __result);
 | |
| 	      });
 | |
| 	  return __init.result.get();
 | |
| 	}
 | |
| 
 | |
|       template<class _ConstBufferSequence>
 | |
| 	size_t
 | |
| 	send(const _ConstBufferSequence& __buffers)
 | |
| 	{
 | |
| 	  return send(__buffers, socket_base::message_flags(),
 | |
| 		      __throw_on_error{"basic_stream_socket::send"});
 | |
| 	}
 | |
| 
 | |
|       template<class _ConstBufferSequence>
 | |
| 	size_t
 | |
| 	send(const _ConstBufferSequence& __buffers, error_code& __ec)
 | |
| 	{ return send(__buffers, socket_base::message_flags(), __ec); }
 | |
| 
 | |
|       template<class _ConstBufferSequence>
 | |
| 	size_t
 | |
| 	send(const _ConstBufferSequence& __buffers,
 | |
| 	     socket_base::message_flags __flags)
 | |
| 	{
 | |
| 	  return send(__buffers, socket_base::message_flags(),
 | |
| 		      __throw_on_error{"basic_stream_socket::send"});
 | |
| 	}
 | |
| 
 | |
|       template<class _ConstBufferSequence>
 | |
| 	size_t
 | |
| 	send(const _ConstBufferSequence& __buffers,
 | |
| 	     socket_base::message_flags __flags, error_code& __ec)
 | |
| 	{
 | |
| 	  if (__buffer_empty(__buffers))
 | |
| 	    {
 | |
| 	      __ec.clear();
 | |
| 	      return 0;
 | |
| 	    }
 | |
| 
 | |
| 	  socket_base::__msg_hdr __msg(__buffers);
 | |
| 	  ssize_t __result = ::sendmsg(this->native_handle(), &__msg,
 | |
| 				       static_cast<int>(__flags));
 | |
| 	  if (__result >= 0)
 | |
| 	    {
 | |
| 	      __ec.clear();
 | |
| 	      return __result;
 | |
| 	    }
 | |
| 	  __ec.assign(errno, generic_category());
 | |
| 	  return 0;
 | |
| 	}
 | |
| 
 | |
|       template<class _ConstBufferSequence, class _CompletionToken>
 | |
| 	__deduced_t<_CompletionToken, void(error_code, size_t)>
 | |
| 	async_send(const _ConstBufferSequence& __buffers,
 | |
| 		   _CompletionToken&& __token)
 | |
| 	{
 | |
| 	  return async_send(__buffers, socket_base::message_flags(),
 | |
| 			    std::forward<_CompletionToken>(__token));
 | |
| 	}
 | |
| 
 | |
|       template<class _ConstBufferSequence, class _CompletionToken>
 | |
| 	__deduced_t<_CompletionToken, void(error_code, size_t)>
 | |
| 	async_send(const _ConstBufferSequence& __buffers,
 | |
| 		   socket_base::message_flags __flags,
 | |
| 		   _CompletionToken&& __token)
 | |
| 	{
 | |
| 	  async_completion<_CompletionToken, void(error_code, size_t)>
 | |
|             __init{__token};
 | |
| 
 | |
|           if (__buffer_empty(__buffers))
 | |
| 	    {
 | |
|               auto __ex = net::get_associated_executor(
 | |
|                   __init.completion_handler, this->get_executor());
 | |
|               auto __a = get_associated_allocator(
 | |
|                   __init.completion_handler, std::allocator<void>());
 | |
|               __ex.post(
 | |
|                   [__h=std::move(__init.completion_handler)] () mutable
 | |
|                   { __h(error_code{}, 0); }, __a);
 | |
|               return __init.result.get();
 | |
| 	    }
 | |
| 
 | |
|           this->get_executor().context().async_wait(this->native_handle(),
 | |
| 	      socket_base::wait_write,
 | |
| 	      [__h = std::move(__init.completion_handler),
 | |
|                &__buffers, __flags = static_cast<int>(__flags),
 | |
|                __fd = this->native_handle()]
 | |
|               (error_code __ec) mutable {
 | |
|                   if (__ec)
 | |
|                     {
 | |
|                       __h(__ec);
 | |
|                       return;
 | |
|                     }
 | |
|                   socket_base::__msg_hdr __msg(__buffers);
 | |
|                   ssize_t __result = ::sendmsg(__fd, &__msg, __flags);
 | |
|                   if (__result == -1)
 | |
|                     {
 | |
|                       __ec.assign(errno, generic_category());
 | |
|                       __result = 0;
 | |
|                     }
 | |
|                   else
 | |
|                     __ec.clear();
 | |
| 		  __h(__ec, __result);
 | |
| 	      });
 | |
| 	  return __init.result.get();
 | |
| 	}
 | |
| 
 | |
|       template<class _MutableBufferSequence>
 | |
| 	size_t
 | |
| 	read_some(const _MutableBufferSequence& __buffers)
 | |
| 	{
 | |
| 	  return receive(__buffers,
 | |
| 			 __throw_on_error{"basic_stream_socket::read_some"});
 | |
| 	}
 | |
| 
 | |
|       template<class _MutableBufferSequence>
 | |
| 	size_t
 | |
| 	read_some(const _MutableBufferSequence& __buffers, error_code& __ec)
 | |
| 	{ return receive(__buffers, __ec); }
 | |
| 
 | |
|       template<class _MutableBufferSequence, class _CompletionToken>
 | |
| 	__deduced_t<_CompletionToken, void(error_code, size_t)>
 | |
| 	async_read_some(const _MutableBufferSequence& __buffers,
 | |
| 			_CompletionToken&& __token)
 | |
| 	{
 | |
| 	  return async_receive(__buffers,
 | |
| 			       std::forward<_CompletionToken>(__token));
 | |
| 	}
 | |
| 
 | |
|       template<class _ConstBufferSequence>
 | |
| 	size_t
 | |
| 	write_some(const _ConstBufferSequence& __buffers)
 | |
| 	{
 | |
| 	  return send(__buffers,
 | |
| 		      __throw_on_error{"basic_stream_socket:write_some"});
 | |
| 	}
 | |
| 
 | |
|       template<class _ConstBufferSequence>
 | |
| 	size_t
 | |
| 	write_some(const _ConstBufferSequence& __buffers, error_code& __ec)
 | |
| 	{  return send(__buffers, __ec); }
 | |
| 
 | |
|       template<class _ConstBufferSequence, class _CompletionToken>
 | |
| 	__deduced_t<_CompletionToken, void(error_code, size_t)>
 | |
| 	async_write_some(const _ConstBufferSequence& __buffers,
 | |
| 			      _CompletionToken&& __token)
 | |
| 	{
 | |
| 	  return async_send(__buffers,
 | |
| 			    std::forward<_CompletionToken>(__token));
 | |
| 	}
 | |
|     };
 | |
| 
 | |
|   template<typename _AcceptableProtocol>
 | |
|     class basic_socket_acceptor
 | |
|     : public socket_base, private __basic_socket_impl<_AcceptableProtocol>
 | |
|     {
 | |
|       using __base = __basic_socket_impl<_AcceptableProtocol>;
 | |
| 
 | |
|     public:
 | |
|       // types:
 | |
| 
 | |
|       typedef io_context::executor_type executor_type;
 | |
|       typedef int native_handle_type;
 | |
|       typedef _AcceptableProtocol protocol_type;
 | |
|       typedef typename protocol_type::endpoint endpoint_type;
 | |
|       typedef typename protocol_type::socket socket_type;
 | |
| 
 | |
|       // construct / copy / destroy:
 | |
| 
 | |
|       explicit
 | |
|       basic_socket_acceptor(io_context& __ctx)
 | |
|       : __base(__ctx), _M_protocol(endpoint_type{}.protocol()) { }
 | |
| 
 | |
|       basic_socket_acceptor(io_context& __ctx,
 | |
| 			    const protocol_type& __protocol)
 | |
|       : __base(__ctx), _M_protocol(__protocol)
 | |
|       { open(__protocol); }
 | |
| 
 | |
|       basic_socket_acceptor(io_context& __ctx, const endpoint_type& __endpoint,
 | |
| 			    bool __reuse_addr = true)
 | |
|       : basic_socket_acceptor(__ctx, __endpoint.protocol())
 | |
|       {
 | |
| 	if (__reuse_addr)
 | |
| 	  set_option(reuse_address(true));
 | |
| 	bind(__endpoint);
 | |
| 	listen();
 | |
|       }
 | |
| 
 | |
|       basic_socket_acceptor(io_context& __ctx, const protocol_type& __protocol,
 | |
| 			    const native_handle_type& __native_acceptor)
 | |
|       : basic_socket_acceptor(__ctx, __protocol)
 | |
|       { assign(__protocol, __native_acceptor); }
 | |
| 
 | |
|       basic_socket_acceptor(const basic_socket_acceptor&) = delete;
 | |
| 
 | |
|       basic_socket_acceptor(basic_socket_acceptor&&) = default;
 | |
| 
 | |
|       template<typename _OtherProtocol, typename _Requires
 | |
| 	       = _Require<is_convertible<_OtherProtocol, protocol_type>>>
 | |
| 	basic_socket_acceptor(basic_socket_acceptor<_OtherProtocol>&& __rhs)
 | |
| 	: __base(std::move(__rhs)) { }
 | |
| 
 | |
|       ~basic_socket_acceptor() = default;
 | |
| 
 | |
|       basic_socket_acceptor& operator=(const basic_socket_acceptor&) = delete;
 | |
| 
 | |
|       basic_socket_acceptor& operator=(basic_socket_acceptor&&) = default;
 | |
| 
 | |
|       template<class _OtherProtocol>
 | |
| 	enable_if_t<is_convertible<_OtherProtocol, protocol_type>::value,
 | |
| 		    basic_socket_acceptor&>
 | |
| 	operator=(basic_socket_acceptor<_OtherProtocol>&& __rhs)
 | |
| 	{
 | |
| 	  __base::operator=(std::move(__rhs));
 | |
| 	  return *this;
 | |
| 	}
 | |
| 
 | |
|       // basic_socket_acceptor operations:
 | |
| 
 | |
|       executor_type get_executor() noexcept { return __base::get_executor(); }
 | |
| 
 | |
|       native_handle_type
 | |
|       native_handle() noexcept { return __base::native_handle(); }
 | |
| 
 | |
|       void
 | |
|       open(const protocol_type& __protocol = protocol_type())
 | |
|       { open(__protocol, __throw_on_error{"basic_socket_acceptor::open"}); }
 | |
| 
 | |
|       void
 | |
|       open(const protocol_type& __protocol, error_code& __ec)
 | |
|       { __base::open(__protocol, __ec); }
 | |
| 
 | |
|       void
 | |
|       assign(const protocol_type& __protocol,
 | |
| 	     const native_handle_type& __native_acceptor)
 | |
|       {
 | |
| 	assign(__protocol, __native_acceptor,
 | |
| 	       __throw_on_error{"basic_socket_acceptor::assign"});
 | |
|       }
 | |
| 
 | |
|       void
 | |
|       assign(const protocol_type& __protocol,
 | |
| 	     const native_handle_type& __native_acceptor,
 | |
| 	     error_code& __ec)
 | |
|       { __base::assign(__protocol, __native_acceptor, __ec); }
 | |
| 
 | |
|       bool
 | |
|       is_open() const noexcept { return __base::is_open(); }
 | |
| 
 | |
|       void
 | |
|       close() { close(__throw_on_error{"basic_socket_acceptor::close"}); }
 | |
| 
 | |
|       void
 | |
|       close(error_code& __ec) { __base::_close(__ec); }
 | |
| 
 | |
|       void
 | |
|       cancel() { cancel(__throw_on_error{"basic_socket_acceptor::cancel"}); }
 | |
| 
 | |
|       void
 | |
|       cancel(error_code& __ec) { __base::cancel(__ec); }
 | |
| 
 | |
|       template<typename _SettableSocketOption>
 | |
| 	void
 | |
| 	set_option(const _SettableSocketOption& __option)
 | |
| 	{
 | |
| 	  set_option(__option,
 | |
| 		     __throw_on_error{"basic_socket_acceptor::set_option"});
 | |
| 	}
 | |
| 
 | |
|       template<typename _SettableSocketOption>
 | |
| 	void
 | |
| 	set_option(const _SettableSocketOption& __option, error_code& __ec)
 | |
| 	{ __base::set_option(__option, __ec); }
 | |
| 
 | |
|       template<typename _GettableSocketOption>
 | |
| 	void
 | |
| 	get_option(_GettableSocketOption& __option) const
 | |
| 	{
 | |
| 	  get_option(__option,
 | |
| 		     __throw_on_error{"basic_socket_acceptor::get_option"});
 | |
| 	}
 | |
| 
 | |
|       template<typename _GettableSocketOption>
 | |
| 	void
 | |
| 	get_option(_GettableSocketOption& __option, error_code& __ec) const
 | |
| 	{ __base::get_option(__option, __ec); }
 | |
| 
 | |
|       template<typename _IoControlCommand>
 | |
| 	void
 | |
| 	io_control(_IoControlCommand& __command)
 | |
| 	{
 | |
| 	  io_control(__command,
 | |
| 		     __throw_on_error{"basic_socket_acceptor::io_control"});
 | |
| 	}
 | |
| 
 | |
|       template<typename _IoControlCommand>
 | |
| 	void
 | |
| 	io_control(_IoControlCommand& __command, error_code& __ec)
 | |
| 	{ __base::io_control(__command, __ec); }
 | |
| 
 | |
|       void
 | |
|       non_blocking(bool __mode)
 | |
|       {
 | |
| 	non_blocking(__mode,
 | |
| 		     __throw_on_error{"basic_socket_acceptor::non_blocking"});
 | |
|       }
 | |
| 
 | |
|       void
 | |
|       non_blocking(bool __mode, error_code& __ec)
 | |
|       { __base::non_blocking(__mode, __ec); }
 | |
| 
 | |
|       bool non_blocking() const { return __base::non_blocking(); }
 | |
| 
 | |
|       void
 | |
|       native_non_blocking(bool __mode)
 | |
|       {
 | |
| 	native_non_blocking(__mode, __throw_on_error{
 | |
| 	    "basic_socket_acceptor::native_non_blocking"});
 | |
|       }
 | |
| 
 | |
|       void
 | |
|       native_non_blocking(bool __mode, error_code& __ec)
 | |
|       { __base::native_non_blocking(__mode, __ec); }
 | |
| 
 | |
|       bool
 | |
|       native_non_blocking() const
 | |
|       { return __base::native_non_blocking(); }
 | |
| 
 | |
|       void
 | |
|       bind(const endpoint_type& __endpoint)
 | |
|       {
 | |
| 	return bind(__endpoint,
 | |
| 		    __throw_on_error{"basic_socket_acceptor::bind"});
 | |
|       }
 | |
| 
 | |
|       void
 | |
|       bind(const endpoint_type& __endpoint, error_code& __ec)
 | |
|       { __base::bind(__endpoint, __ec); }
 | |
| 
 | |
|       void
 | |
|       listen(int __backlog = max_listen_connections)
 | |
|       {
 | |
| 	return listen(__backlog,
 | |
| 		      __throw_on_error{"basic_socket_acceptor::listen"});
 | |
|       }
 | |
| 
 | |
|       void listen(int __backlog, error_code& __ec)
 | |
|       {
 | |
| 	if (::listen(native_handle(), __backlog) == -1)
 | |
| 	  __ec.assign(errno, generic_category());
 | |
| 	else
 | |
| 	  __ec.clear();
 | |
|       }
 | |
| 
 | |
|       endpoint_type
 | |
|       local_endpoint() const
 | |
|       {
 | |
| 	return local_endpoint(
 | |
| 	    __throw_on_error{"basic_socket_acceptor::local_endpoint"});
 | |
|       }
 | |
| 
 | |
|       endpoint_type
 | |
|       local_endpoint(error_code& __ec) const
 | |
|       { return __base::local_endpoint(__ec); }
 | |
| 
 | |
|       void
 | |
|       enable_connection_aborted(bool __mode)
 | |
|       { __base::_M_bits.enable_connection_aborted = __mode; }
 | |
| 
 | |
|       bool
 | |
|       enable_connection_aborted() const
 | |
|       { return __base::_M_bits.enable_connection_aborted; }
 | |
| 
 | |
|       socket_type
 | |
|       accept()
 | |
|       { return accept(__throw_on_error{"basic_socket_acceptor::accept"}); }
 | |
| 
 | |
|       socket_type
 | |
|       accept(error_code& __ec)
 | |
|       { return accept(get_executor().context(), __ec); }
 | |
| 
 | |
|       socket_type accept(io_context& __ctx)
 | |
|       {
 | |
| 	return accept(__ctx,
 | |
| 		      __throw_on_error{"basic_socket_acceptor::accept"});
 | |
|       }
 | |
| 
 | |
|       socket_type
 | |
|       accept(io_context& __ctx, error_code& __ec)
 | |
|       {
 | |
| 	do
 | |
| 	  {
 | |
| 	    int __h = ::accept(native_handle(), nullptr, 0);
 | |
| 	    if (__h != -1)
 | |
| 	      {
 | |
| 		__ec.clear();
 | |
| 		return socket_type{__ctx, _M_protocol, __h};
 | |
| 	      }
 | |
| 	  } while (errno == ECONNABORTED && enable_connection_aborted());
 | |
| 	__ec.assign(errno, generic_category());
 | |
| 	return socket_type{__ctx};
 | |
|       }
 | |
| 
 | |
|       template<class _CompletionToken>
 | |
| 	__deduced_t<_CompletionToken, void(error_code, socket_type)>
 | |
| 	async_accept(_CompletionToken&& __token)
 | |
| 	{
 | |
| 	  return async_accept(get_executor().context(),
 | |
| 			      std::forward<_CompletionToken>(__token));
 | |
| 	}
 | |
| 
 | |
|       template<class _CompletionToken>
 | |
| 	__deduced_t<_CompletionToken, void(error_code, socket_type)>
 | |
| 	async_accept(io_context& __ctx, _CompletionToken&& __token)
 | |
| 	{
 | |
|           async_completion<_CompletionToken, void(error_code, socket_type)>
 | |
|             __init{__token};
 | |
| 
 | |
| 	  __ctx.get_executor().context().async_wait(native_handle(),
 | |
| 	      socket_base::wait_read,
 | |
| 	      [__h = std::move(__init.completion_handler),
 | |
|                __connabort = enable_connection_aborted(),
 | |
|                __fd = native_handle(),
 | |
|                __protocol = _M_protocol,
 | |
|                &__ctx
 | |
|               ]
 | |
|               (error_code __ec) mutable {
 | |
|                   if (__ec)
 | |
|                     {
 | |
|                       __h(__ec, socket_type(__ctx));
 | |
|                       return;
 | |
|                     }
 | |
|                   do
 | |
|                     {
 | |
|                       int __newfd = ::accept(__fd, nullptr, 0);
 | |
|                       if (__newfd != -1)
 | |
|                         {
 | |
|                           __ec.clear();
 | |
|                           __h(__ec, socket_type{__ctx, __protocol, __newfd});
 | |
|                           return;
 | |
|                         }
 | |
|                     } while (errno == ECONNABORTED && __connabort);
 | |
|                   __ec.assign(errno, generic_category());
 | |
|                   __h(__ec, socket_type(__ctx));
 | |
| 	      });
 | |
| 	  return __init.result.get();
 | |
| 	}
 | |
| 
 | |
|       socket_type
 | |
|       accept(endpoint_type& __endpoint)
 | |
|       {
 | |
| 	return accept(get_executor().context(), __endpoint,
 | |
| 		      __throw_on_error{"basic_socket_acceptor::accept"});
 | |
|       }
 | |
| 
 | |
|       socket_type
 | |
|       accept(endpoint_type& __endpoint, error_code& __ec)
 | |
|       { return accept(get_executor().context(), __endpoint, __ec); }
 | |
| 
 | |
|       socket_type
 | |
|       accept(io_context& __ctx, endpoint_type& __endpoint)
 | |
|       {
 | |
| 	return accept(__ctx, __endpoint,
 | |
| 		      __throw_on_error{"basic_socket_acceptor::accept"});
 | |
|       }
 | |
| 
 | |
|       socket_type
 | |
|       accept(io_context& __ctx, endpoint_type& __endpoint, error_code& __ec)
 | |
|       {
 | |
| 	do
 | |
| 	  {
 | |
| 	    socklen_t __len = __endpoint.capacity();
 | |
| 	    int __h = ::accept(native_handle(), (sockaddr*)__endpoint.data(),
 | |
| 			       &__len);
 | |
| 	    if (__h != -1)
 | |
| 	      {
 | |
| 		__endpoint.resize(__len);
 | |
| 		return socket_type{__ctx, _M_protocol, __h};
 | |
| 	      }
 | |
| 	  } while (errno == ECONNABORTED && enable_connection_aborted());
 | |
| 	__ec.assign(errno, generic_category());
 | |
| 	return socket_type{__ctx};
 | |
|       }
 | |
| 
 | |
|       template<class _CompletionToken>
 | |
| 	__deduced_t<_CompletionToken, void(error_code, socket_type)>
 | |
| 	async_accept(endpoint_type& __endpoint,
 | |
| 			     _CompletionToken&& __token)
 | |
| 	{
 | |
| 	  return async_accept(get_executor().context(), __endpoint,
 | |
| 			      std::forward<_CompletionToken>(__token));
 | |
| 	}
 | |
| 
 | |
|       template<class _CompletionToken>
 | |
| 	__deduced_t<_CompletionToken, void(error_code, socket_type)>
 | |
| 	async_accept(io_context& __ctx, endpoint_type& __endpoint,
 | |
| 			     _CompletionToken&& __token)
 | |
|         {
 | |
|           async_completion<_CompletionToken, void(error_code, socket_type)>
 | |
|             __init{__token};
 | |
| 
 | |
| 	  __ctx.get_executor().context().async_wait(native_handle(),
 | |
| 	      socket_base::wait_read,
 | |
| 	      [__h = std::move(__init.completion_handler),
 | |
|               __ep = std::move(__endpoint),
 | |
|                __connabort = enable_connection_aborted(),
 | |
|                __fd = native_handle(),
 | |
|                &__ctx
 | |
|               ]
 | |
|               (error_code __ec) mutable {
 | |
|                   if (__ec)
 | |
|                     {
 | |
|                       __h(__ec, socket_type(__ctx));
 | |
|                       return;
 | |
|                     }
 | |
|                   do
 | |
|                     {
 | |
|                       socklen_t __len = __ep.capacity();
 | |
|                       int __newfd = ::accept(__fd, __ep.data, &__len);
 | |
|                       if (__newfd != -1)
 | |
|                         {
 | |
|                           __ep.resize(__len);
 | |
|                           auto __protocol = __ep.protocol();
 | |
|                           __ec.clear();
 | |
|                           __h(__ec, socket_type{__ctx, __protocol, __newfd});
 | |
|                           return;
 | |
|                         }
 | |
|                     } while (errno == ECONNABORTED && __connabort);
 | |
|                   __ec.assign(errno, generic_category());
 | |
|                   __h(__ec, socket_type(__ctx));
 | |
| 	      });
 | |
| 	  return __init.result.get();
 | |
|         }
 | |
| 
 | |
|       void
 | |
|       wait(wait_type __w)
 | |
|       { wait(__w, __throw_on_error{"basic_socket_acceptor::wait"}); }
 | |
| 
 | |
|       void
 | |
|       wait(wait_type __w, error_code& __ec)
 | |
|       {
 | |
| 	::pollfd __fds;
 | |
| 	__fds.fd = native_handle();
 | |
| 	__fds.events = __w; // __w | POLLIN;
 | |
| 	if (::poll(&__fds, 1, -1) == -1)
 | |
| 	  __ec.assign(errno, generic_category());
 | |
| 	else
 | |
| 	  __ec.clear();
 | |
|       }
 | |
| 
 | |
|       template<class _CompletionToken>
 | |
| 	__deduced_t<_CompletionToken, void(error_code)>
 | |
| 	async_wait(wait_type __w, _CompletionToken&& __token)
 | |
|         {
 | |
| 	  async_completion<_CompletionToken, void(error_code)> __init{__token};
 | |
| 	  get_executor().context().async_wait( native_handle(),
 | |
| 	      static_cast<int>(__w),
 | |
| 	      [__h = std::move(__init.completion_handler)]
 | |
|               (error_code __ec) mutable {
 | |
| 		  __h(__ec);
 | |
| 	      });
 | |
| 	  return __init.result.get();
 | |
| 	}
 | |
| 
 | |
|     private:
 | |
|       protocol_type _M_protocol;
 | |
|     };
 | |
| 
 | |
|   // @}
 | |
| 
 | |
|   /** @brief Socket streams
 | |
|    * @{
 | |
|    */
 | |
| 
 | |
|   template<typename _Protocol, typename _Clock, typename _WaitTraits>
 | |
|     class basic_socket_streambuf : public basic_streambuf<char>
 | |
|     {
 | |
|     public:
 | |
|       // types:
 | |
| 
 | |
|       typedef _Protocol protocol_type;
 | |
|       typedef typename protocol_type::endpoint endpoint_type;
 | |
|       typedef _Clock clock_type;
 | |
|       typedef typename clock_type::time_point time_point;
 | |
|       typedef typename clock_type::duration duration;
 | |
|       typedef _WaitTraits wait_traits_type;
 | |
| 
 | |
|       // construct / copy / destroy:
 | |
| 
 | |
|       basic_socket_streambuf() : _M_socket(_S_ctx()) { }
 | |
| 
 | |
|       explicit
 | |
|       basic_socket_streambuf(basic_stream_socket<protocol_type> __s)
 | |
|       : _M_socket(std::move(__s)) { }
 | |
| 
 | |
|       basic_socket_streambuf(const basic_socket_streambuf&) = delete;
 | |
| 
 | |
|       basic_socket_streambuf(basic_socket_streambuf&& __rhs); // TODO
 | |
| 
 | |
| 
 | |
|       virtual ~basic_socket_streambuf(); // TODO
 | |
| 
 | |
|       basic_socket_streambuf& operator=(const basic_socket_streambuf&) = delete;
 | |
| 
 | |
|       basic_socket_streambuf& operator=(basic_socket_streambuf&& __rhs); // TODO
 | |
| 
 | |
|       // members:
 | |
| 
 | |
|       basic_socket_streambuf* connect(const endpoint_type& __e); // TODO
 | |
| 
 | |
|       template<typename... _Args>
 | |
| 	basic_socket_streambuf* connect(_Args&&... ); // TODO
 | |
| 
 | |
|       basic_socket_streambuf* close(); // TODO
 | |
| 
 | |
|       basic_socket<protocol_type>& socket() { return _M_socket; }
 | |
|       error_code error() const { return _M_ec; }
 | |
| 
 | |
|       time_point expiry() const { return _M_expiry; }
 | |
| 
 | |
|       void
 | |
|       expires_at(const time_point& __t)
 | |
|       { _M_expiry = __t; }
 | |
| 
 | |
|       void
 | |
|       expires_after(const duration& __d)
 | |
|       { expires_at(clock_type::now() + __d); }
 | |
| 
 | |
|     protected:
 | |
|       // overridden virtual functions: // TODO
 | |
|       virtual int_type underflow() override;
 | |
|       virtual int_type pbackfail(int_type __c = traits_type::eof()) override;
 | |
|       virtual int_type overflow(int_type __c = traits_type::eof()) override;
 | |
|       virtual int sync() override;
 | |
|       virtual streambuf* setbuf(char_type* __s, streamsize __n) override;
 | |
| 
 | |
|     private:
 | |
|       static io_context&
 | |
|       _S_ctx()
 | |
|       {
 | |
| 	static io_context __ctx;
 | |
| 	return __ctx;
 | |
|       }
 | |
| 
 | |
|       basic_stream_socket<protocol_type> _M_socket;
 | |
|       error_code _M_ec;
 | |
|       time_point _M_expiry{ time_point::max() };
 | |
|     };
 | |
| 
 | |
|   template<typename _Protocol, class _Clock, typename _WaitTraits>
 | |
|     class basic_socket_iostream : public basic_iostream<char>
 | |
|     {
 | |
|       using __streambuf_type
 | |
| 	= basic_socket_streambuf<_Protocol, _Clock, _WaitTraits>;
 | |
| 
 | |
|     public:
 | |
|       // types:
 | |
| 
 | |
|       typedef _Protocol protocol_type;
 | |
|       typedef typename protocol_type::endpoint endpoint_type;
 | |
|       typedef _Clock clock_type;
 | |
|       typedef typename clock_type::time_point time_point;
 | |
|       typedef typename clock_type::duration duration;
 | |
|       typedef _WaitTraits wait_traits_type;
 | |
| 
 | |
|       // construct / copy / destroy:
 | |
| 
 | |
|       // TODO base-from-member ?
 | |
|       basic_socket_iostream() : basic_iostream(nullptr), _M_sb()
 | |
|       {
 | |
| 	this->init(std::addressof(_M_sb));
 | |
| 	this->setf(std::ios::unitbuf);
 | |
|       }
 | |
| 
 | |
|       explicit
 | |
|       basic_socket_iostream(basic_stream_socket<protocol_type> __s)
 | |
|       : basic_iostream(nullptr), _M_sb(std::move(__s))
 | |
|       {
 | |
| 	this->init(std::addressof(_M_sb));
 | |
| 	this->setf(std::ios::unitbuf);
 | |
|       }
 | |
| 
 | |
|       basic_socket_iostream(const basic_socket_iostream&) = delete;
 | |
| 
 | |
|       basic_socket_iostream(basic_socket_iostream&& __rhs)
 | |
|       : basic_iostream(nullptr), _M_sb(std::move(__rhs._M_sb))
 | |
| 	// XXX ???     ^^^^^^^
 | |
|       {
 | |
| 	// XXX ??? this->init(std::addressof(_M_sb));
 | |
| 	this->set_rbduf(std::addressof(_M_sb));
 | |
|       }
 | |
| 
 | |
|       template<typename... _Args>
 | |
| 	explicit
 | |
| 	basic_socket_iostream(_Args&&... __args)
 | |
| 	: basic_iostream(nullptr), _M_sb()
 | |
| 	{
 | |
| 	  this->init(std::addressof(_M_sb));
 | |
| 	  this->setf(std::ios::unitbuf);
 | |
| 	  connect(forward<_Args>(__args)...);
 | |
| 	}
 | |
| 
 | |
|       basic_socket_iostream& operator=(const basic_socket_iostream&) = delete;
 | |
| 
 | |
|       basic_socket_iostream& operator=(basic_socket_iostream&& __rhs); // TODO
 | |
| 
 | |
|       // members:
 | |
| 
 | |
|       template<typename... _Args>
 | |
| 	void
 | |
| 	connect(_Args&&... __args)
 | |
| 	{
 | |
| 	  if (rdbuf()->connect(forward<_Args>(__args)...) == nullptr)
 | |
| 	    this->setstate(failbit);
 | |
| 	}
 | |
| 
 | |
|       void
 | |
|       close()
 | |
|       {
 | |
| 	if (rdbuf()->close() == nullptr)
 | |
| 	  this->setstate(failbit);
 | |
|       }
 | |
| 
 | |
|       basic_socket_streambuf<protocol_type, clock_type, wait_traits_type>*
 | |
|       rdbuf() const
 | |
|       { return const_cast<__streambuf_type*>(std::addressof(_M_sb)); }
 | |
| 
 | |
|       basic_socket<protocol_type>& socket() { return rdbuf()->socket(); }
 | |
|       error_code error() const { return rdbuf()->error(); }
 | |
| 
 | |
|       time_point expiry() const { return rdbuf()->expiry(); }
 | |
|       void expires_at(const time_point& __t) { rdbuf()->expires_at(__t); }
 | |
|       void expires_after(const duration& __d) { rdbuf()->expires_after(__d); }
 | |
| 
 | |
|     private:
 | |
|       __streambuf_type _M_sb;
 | |
|     };
 | |
| 
 | |
|   // @}
 | |
| 
 | |
|   /** @brief synchronous connect operations
 | |
|    * @{
 | |
|    */
 | |
| 
 | |
|   template<typename _Protocol, typename _EndpointSequence,
 | |
| 	   typename _ConnectCondition>
 | |
|     inline typename _Protocol::endpoint
 | |
|     connect(basic_socket<_Protocol>& __s,
 | |
| 	    const _EndpointSequence& __endpoints,
 | |
| 	    _ConnectCondition __c, error_code& __ec)
 | |
|     {
 | |
|       __ec.clear();
 | |
|       bool __found = false;
 | |
|       for (auto& __ep : __endpoints)
 | |
| 	{
 | |
| 	  if (__c(__ec, __ep))
 | |
| 	    {
 | |
| 	      __found = true;
 | |
| 	      __s.close(__ec);
 | |
| 	      if (!__ec)
 | |
| 		__s.open(__ep.protocol(), __ec);
 | |
| 	      if (!__ec)
 | |
| 		__s.connect(__ep, __ec);
 | |
| 	      if (!__ec)
 | |
| 		return __ep;
 | |
| 	    }
 | |
| 	}
 | |
|       if (!__found)
 | |
| 	__ec = socket_errc::not_found;
 | |
|       return typename _Protocol::endpoint{};
 | |
|     }
 | |
| 
 | |
|   template<typename _Protocol, typename _InputIterator,
 | |
| 	   typename _ConnectCondition>
 | |
|     inline _InputIterator
 | |
|     connect(basic_socket<_Protocol>& __s,
 | |
| 	    _InputIterator __first, _InputIterator __last,
 | |
| 	    _ConnectCondition __c, error_code& __ec)
 | |
|     {
 | |
|       __ec.clear();
 | |
|       bool __found = false;
 | |
|       for (auto __i = __first; __i != __last; ++__i)
 | |
| 	{
 | |
| 	  if (__c(__ec, *__i))
 | |
| 	    {
 | |
| 	      __found = true;
 | |
| 	      __s.close(__ec);
 | |
| 	      if (!__ec)
 | |
| 		__s.open(typename _Protocol::endpoint(*__i).protocol(), __ec);
 | |
| 	      if (!__ec)
 | |
| 		__s.connect(*__i, __ec);
 | |
| 	      if (!__ec)
 | |
| 		return __i;
 | |
| 	    }
 | |
| 	}
 | |
|       if (!__found)
 | |
| 	__ec = socket_errc::not_found;
 | |
|       return __last;
 | |
|     }
 | |
| 
 | |
|   template<typename _Protocol, typename _EndpointSequence,
 | |
| 	   typename _ConnectCondition>
 | |
|     inline typename _Protocol::endpoint
 | |
|     connect(basic_socket<_Protocol>& __s,
 | |
| 	    const _EndpointSequence& __endpoints,
 | |
| 	    _ConnectCondition __c)
 | |
|     {
 | |
|       return net::connect(__s, __endpoints, __c, __throw_on_error{"connect"});
 | |
|     }
 | |
| 
 | |
|   template<typename _Protocol, typename _InputIterator,
 | |
| 	   typename _ConnectCondition>
 | |
|     inline _InputIterator
 | |
|     connect(basic_socket<_Protocol>& __s,
 | |
| 	    _InputIterator __first, _InputIterator __last,
 | |
| 	    _ConnectCondition __c)
 | |
|     {
 | |
|       return net::connect(__s, __first, __last, __c,
 | |
| 			  __throw_on_error{"connect"});
 | |
|     }
 | |
| 
 | |
|   template<typename _Protocol, typename _EndpointSequence>
 | |
|     inline typename _Protocol::endpoint
 | |
|     connect(basic_socket<_Protocol>& __s,
 | |
| 	    const _EndpointSequence& __endpoints)
 | |
|     {
 | |
|       return net::connect(__s, __endpoints, [](auto, auto){ return true; },
 | |
| 			  __throw_on_error{"connect"});
 | |
|     }
 | |
| 
 | |
|   template<typename _Protocol, typename _EndpointSequence>
 | |
|     inline typename _Protocol::endpoint
 | |
|     connect(basic_socket<_Protocol>& __s,
 | |
| 	    const _EndpointSequence& __endpoints,
 | |
| 	    error_code& __ec)
 | |
|     {
 | |
|       return net::connect(__s, __endpoints, [](auto, auto){ return true; },
 | |
| 			  __ec);
 | |
|     }
 | |
| 
 | |
|   template<typename _Protocol, typename _InputIterator>
 | |
|     inline _InputIterator
 | |
|     connect(basic_socket<_Protocol>& __s,
 | |
| 	    _InputIterator __first, _InputIterator __last)
 | |
|     {
 | |
|       return net::connect(__s, __first, __last, [](auto, auto){ return true; },
 | |
| 			  __throw_on_error{"connect"});
 | |
|     }
 | |
| 
 | |
|   template<typename _Protocol, typename _InputIterator>
 | |
|     inline _InputIterator
 | |
|     connect(basic_socket<_Protocol>& __s,
 | |
| 	    _InputIterator __first, _InputIterator __last,
 | |
| 	    error_code& __ec)
 | |
|     {
 | |
|       return net::connect(__s, __first, __last, [](auto, auto){ return true; },
 | |
| 			  __ec);
 | |
|     }
 | |
| 
 | |
|   // @}
 | |
| 
 | |
|   /** @brief asynchronous connect operations
 | |
|    * @{
 | |
|    */
 | |
| 
 | |
|   template<typename _Protocol, typename _EndpointSequence,
 | |
| 	   typename _ConnectCondition, typename _CompletionToken>
 | |
|     inline
 | |
|     __deduced_t<_CompletionToken,
 | |
| 		void(error_code, typename _Protocol::endpoint)>
 | |
|     async_connect(basic_socket<_Protocol>& __s,
 | |
| 		  const _EndpointSequence& __endpoints,
 | |
| 		  _ConnectCondition __c, _CompletionToken&& __token); // TODO
 | |
| 
 | |
|   template<typename _Protocol, typename _EndpointSequence,
 | |
| 	   typename _CompletionToken>
 | |
|     inline
 | |
|     __deduced_t<_CompletionToken,
 | |
| 		void(error_code, typename _Protocol::endpoint)>
 | |
|     async_connect(basic_socket<_Protocol>& __s,
 | |
| 		  const _EndpointSequence& __endpoints,
 | |
| 		  _CompletionToken&& __token)
 | |
|     {
 | |
|       return net::async_connect(__s, __endpoints,
 | |
| 				[](auto, auto){ return true; },
 | |
| 				forward<_CompletionToken>(__token));
 | |
|     }
 | |
| 
 | |
|   template<typename _Protocol, typename _InputIterator,
 | |
| 	   typename _ConnectCondition, typename _CompletionToken>
 | |
|     inline
 | |
|     __deduced_t<_CompletionToken, void(error_code, _InputIterator)>
 | |
|     async_connect(basic_socket<_Protocol>& __s,
 | |
| 		  _InputIterator __first, _InputIterator __last,
 | |
| 		  _ConnectCondition __c, _CompletionToken&& __token); // TODO
 | |
| 
 | |
|   template<typename _Protocol, typename _InputIterator,
 | |
| 	   typename _CompletionToken>
 | |
|     inline
 | |
|     __deduced_t<_CompletionToken, void(error_code, _InputIterator)>
 | |
|     async_connect(basic_socket<_Protocol>& __s,
 | |
| 		  _InputIterator __first, _InputIterator __last,
 | |
| 		  _CompletionToken&& __token)
 | |
|     {
 | |
|       return net::async_connect(__s, __first, __last,
 | |
| 				[](auto, auto){ return true; },
 | |
| 				forward<_CompletionToken>(__token));
 | |
|     }
 | |
| 
 | |
|   // @}
 | |
| 
 | |
| #endif  // _GLIBCXX_HAVE_UNISTD_H
 | |
| 
 | |
|   // @}
 | |
| 
 | |
| _GLIBCXX_END_NAMESPACE_VERSION
 | |
| } // namespace v1
 | |
| } // namespace net
 | |
| } // namespace experimental
 | |
| 
 | |
|   template<>
 | |
|     struct is_error_code_enum<experimental::net::v1::socket_errc>
 | |
|     : public true_type {};
 | |
| 
 | |
| } // namespace std
 | |
| 
 | |
| #endif // C++14
 | |
| 
 | |
| #endif // _GLIBCXX_EXPERIMENTAL_SOCKET
 |