Home | History | Annotate | Line # | Download | only in experimental
      1 // <experimental/socket> -*- C++ -*-
      2 
      3 // Copyright (C) 2015-2022 Free Software Foundation, Inc.
      4 //
      5 // This file is part of the GNU ISO C++ Library.  This library is free
      6 // software; you can redistribute it and/or modify it under the
      7 // terms of the GNU General Public License as published by the
      8 // Free Software Foundation; either version 3, or (at your option)
      9 // any later version.
     10 
     11 // This library is distributed in the hope that it will be useful,
     12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14 // GNU General Public License for more details.
     15 
     16 // Under Section 7 of GPL version 3, you are granted additional
     17 // permissions described in the GCC Runtime Library Exception, version
     18 // 3.1, as published by the Free Software Foundation.
     19 
     20 // You should have received a copy of the GNU General Public License and
     21 // a copy of the GCC Runtime Library Exception along with this program;
     22 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     23 // <http://www.gnu.org/licenses/>.
     24 
     25 /** @file experimental/socket
     26  *  This is a TS C++ Library header.
     27  *  @ingroup networking-ts
     28  */
     29 
     30 #ifndef _GLIBCXX_EXPERIMENTAL_SOCKET
     31 #define _GLIBCXX_EXPERIMENTAL_SOCKET
     32 
     33 #pragma GCC system_header
     34 
     35 #if __cplusplus >= 201402L
     36 
     37 #include <experimental/netfwd>
     38 #include <experimental/buffer>
     39 #include <experimental/io_context>
     40 #include <experimental/bits/net.h>
     41 #include <streambuf>
     42 #include <istream>
     43 #include <bits/unique_ptr.h>
     44 #if _GLIBCXX_HAVE_UNISTD_H
     45 # include <unistd.h>
     46 # ifdef _GLIBCXX_HAVE_SYS_SOCKET_H
     47 #  include <sys/socket.h>	// socket etc
     48 # endif
     49 # ifdef _GLIBCXX_HAVE_SYS_IOCTL_H
     50 #  include <sys/ioctl.h>	// ioctl
     51 # endif
     52 # ifdef _GLIBCXX_HAVE_SYS_UIO_H
     53 #  include <sys/uio.h>		// iovec
     54 # endif
     55 # ifdef _GLIBCXX_HAVE_POLL_H
     56 #  include <poll.h>		// poll, pollfd, POLLIN, POLLOUT, POLLERR
     57 # endif
     58 # ifdef _GLIBCXX_HAVE_FCNTL_H
     59 #  include <fcntl.h>		// fcntl, F_GETFL, F_SETFL
     60 # endif
     61 #endif
     62 
     63 namespace std _GLIBCXX_VISIBILITY(default)
     64 {
     65 _GLIBCXX_BEGIN_NAMESPACE_VERSION
     66 namespace experimental
     67 {
     68 namespace net
     69 {
     70 inline namespace v1
     71 {
     72 
     73   /** @addtogroup networking-ts
     74    *  @{
     75    */
     76 
     77   enum class socket_errc {  // TODO decide values
     78     already_open = 3,
     79     not_found = 4
     80   };
     81 
     82 } // namespace v1
     83 } // namespace net
     84 } // namespace experimental
     85 
     86   template<>
     87     struct is_error_code_enum<experimental::net::v1::socket_errc>
     88     : public true_type {};
     89 
     90 namespace experimental
     91 {
     92 namespace net
     93 {
     94 inline namespace v1
     95 {
     96   const error_category& socket_category() noexcept
     97   {
     98     struct __cat : error_category
     99     {
    100       const char* name() const noexcept { return "socket"; }
    101 
    102       std::string message(int __e) const
    103       {
    104 	if (__e == (int)socket_errc::already_open)
    105 	  return "already open";
    106 	else if (__e == (int)socket_errc::not_found)
    107 	  return "endpoint not found";
    108 	return "socket error";
    109       }
    110 
    111       virtual void __message(int) { } // TODO dual ABI XXX
    112     };
    113     static __cat __c;
    114     return __c;
    115   }
    116 
    117   inline error_code
    118   make_error_code(socket_errc __e) noexcept
    119   { return error_code(static_cast<int>(__e), socket_category()); }
    120 
    121   inline error_condition
    122   make_error_condition(socket_errc __e) noexcept
    123   { return error_condition(static_cast<int>(__e), socket_category()); }
    124 
    125 
    126   // TODO GettableSocket reqs
    127   // TODO SettableSocket reqs
    128   // TODO BooleanSocketOption reqs
    129   // TODO IntegerSocketOption reqs
    130   // TODO IoControlCommand reqs
    131   // TODO ConnectCondition reqs
    132 
    133   /** @brief Sockets
    134    * @{
    135    */
    136 
    137   class socket_base
    138   {
    139   public:
    140 #ifdef _GLIBCXX_HAVE_SYS_SOCKET_H
    141     class broadcast : public __sockopt_crtp<broadcast, bool>
    142     {
    143     public:
    144       using __sockopt_crtp::__sockopt_crtp;
    145       using __sockopt_crtp::operator=;
    146 
    147     private:
    148       friend __sockopt_crtp<broadcast, bool>;
    149       static const int _S_level = SOL_SOCKET;
    150       static const int _S_name = SO_BROADCAST;
    151     };
    152 
    153     class debug : public __sockopt_crtp<debug, bool>
    154     {
    155     public:
    156       friend __sockopt_crtp<debug, bool>;
    157       using __sockopt_crtp::__sockopt_crtp;
    158       using __sockopt_crtp::operator=;
    159 
    160     private:
    161       static const int _S_level = SOL_SOCKET;
    162       static const int _S_name = SO_DEBUG;
    163     };
    164 
    165     class do_not_route : public __sockopt_crtp<do_not_route, bool>
    166     {
    167     public:
    168       using __sockopt_crtp::__sockopt_crtp;
    169       using __sockopt_crtp::operator=;
    170 
    171     private:
    172       friend __sockopt_crtp<do_not_route, bool>;
    173       static const int _S_level = SOL_SOCKET;
    174       static const int _S_name = SO_DONTROUTE;
    175     };
    176 
    177     class keep_alive : public __sockopt_crtp<keep_alive, bool>
    178     {
    179     public:
    180       using __sockopt_crtp::__sockopt_crtp;
    181       using __sockopt_crtp::operator=;
    182 
    183     private:
    184       friend __sockopt_crtp<keep_alive, bool>;
    185       static const int _S_level = SOL_SOCKET;
    186       static const int _S_name = SO_KEEPALIVE;
    187     };
    188 
    189     class linger : public __sockopt_crtp<linger, ::linger>
    190     {
    191     public:
    192       using __sockopt_crtp::__sockopt_crtp;
    193       using __sockopt_crtp::operator=;
    194 
    195       linger() noexcept = default;
    196 
    197       linger(bool __e, chrono::seconds __t) noexcept
    198       {
    199 	enabled(__e);
    200 	timeout(__t);
    201       }
    202 
    203       bool
    204       enabled() const noexcept
    205       { return _M_value.l_onoff != 0; }
    206 
    207       void
    208       enabled(bool __e) noexcept
    209       { _M_value.l_onoff = int(__e); }
    210 
    211       chrono::seconds
    212       timeout() const noexcept
    213       { return chrono::seconds(_M_value.l_linger); }
    214 
    215       void
    216       timeout(chrono::seconds __t) noexcept
    217       { _M_value.l_linger = __t.count(); }
    218 
    219     private:
    220       friend __sockopt_crtp<linger, ::linger>;
    221       static const int _S_level = SOL_SOCKET;
    222       static const int _S_name = SO_LINGER;
    223     };
    224 
    225     class out_of_band_inline : public __sockopt_crtp<out_of_band_inline, bool>
    226     {
    227     public:
    228       using __sockopt_crtp::__sockopt_crtp;
    229       using __sockopt_crtp::operator=;
    230 
    231     private:
    232       friend __sockopt_crtp<out_of_band_inline, bool>;
    233       static const int _S_level = SOL_SOCKET;
    234       static const int _S_name = SO_OOBINLINE;
    235     };
    236 
    237     class receive_buffer_size : public __sockopt_crtp<receive_buffer_size>
    238     {
    239     public:
    240       using __sockopt_crtp::__sockopt_crtp;
    241       using __sockopt_crtp::operator=;
    242 
    243     private:
    244       friend __sockopt_crtp<receive_buffer_size>;
    245       static const int _S_level = SOL_SOCKET;
    246       static const int _S_name = SO_RCVBUF;
    247     };
    248 
    249     class receive_low_watermark : public __sockopt_crtp<receive_low_watermark>
    250     {
    251     public:
    252       using __sockopt_crtp::__sockopt_crtp;
    253       using __sockopt_crtp::operator=;
    254 
    255     private:
    256       friend __sockopt_crtp<receive_low_watermark>;
    257       static const int _S_level = SOL_SOCKET;
    258       static const int _S_name = SO_RCVLOWAT;
    259     };
    260 
    261     class reuse_address : public __sockopt_crtp<reuse_address, bool>
    262     {
    263     public:
    264       using __sockopt_crtp::__sockopt_crtp;
    265       using __sockopt_crtp::operator=;
    266 
    267     private:
    268       friend __sockopt_crtp<reuse_address, bool>;
    269       static const int _S_level = SOL_SOCKET;
    270       static const int _S_name = SO_REUSEADDR;
    271     };
    272 
    273     class send_buffer_size : public __sockopt_crtp<send_buffer_size>
    274     {
    275     public:
    276       using __sockopt_crtp::__sockopt_crtp;
    277       using __sockopt_crtp::operator=;
    278 
    279     private:
    280       friend __sockopt_crtp<send_buffer_size>;
    281       static const int _S_level = SOL_SOCKET;
    282       static const int _S_name = SO_SNDBUF;
    283     };
    284 
    285     class send_low_watermark : public __sockopt_crtp<send_low_watermark>
    286     {
    287     public:
    288       using __sockopt_crtp::__sockopt_crtp;
    289       using __sockopt_crtp::operator=;
    290 
    291     private:
    292       friend __sockopt_crtp<send_low_watermark>;
    293       static const int _S_level = SOL_SOCKET;
    294       static const int _S_name = SO_SNDLOWAT;
    295     };
    296 #endif // HAVE_SYS_SOCKET_H
    297 
    298     enum shutdown_type : int { };
    299 #if defined SHUT_RD && defined SHUT_WR && defined SHUT_RDWR
    300     static constexpr shutdown_type shutdown_receive = (shutdown_type)SHUT_RD;
    301     static constexpr shutdown_type shutdown_send    = (shutdown_type)SHUT_WR;
    302     static constexpr shutdown_type shutdown_both    = (shutdown_type)SHUT_RDWR;
    303 #endif
    304 
    305     enum wait_type : int { };
    306 #ifdef _GLIBCXX_HAVE_POLL_H
    307     static constexpr wait_type wait_read  = (wait_type)POLLIN;
    308     static constexpr wait_type wait_write = (wait_type)POLLOUT;
    309     static constexpr wait_type wait_error = (wait_type)POLLERR;
    310 #else
    311     static constexpr wait_type wait_read  = (wait_type)1;
    312     static constexpr wait_type wait_write = (wait_type)2;
    313     static constexpr wait_type wait_error = (wait_type)4;
    314 #endif
    315 
    316     enum message_flags : int { };
    317 #if defined MSG_PEEK && defined MSG_OOB && defined MSG_DONTROUTE
    318     static constexpr message_flags message_peek
    319       = (message_flags)MSG_PEEK;
    320     static constexpr message_flags message_out_of_band
    321       = (message_flags)MSG_OOB;
    322     static constexpr message_flags message_do_not_route
    323       = (message_flags)MSG_DONTROUTE;
    324 #endif
    325 
    326 #ifdef SOMAXCONN
    327     static constexpr int max_listen_connections = SOMAXCONN;
    328 #else
    329     static constexpr int max_listen_connections = 4;
    330 #endif
    331 
    332     // message_flags bitmask operations are defined as hidden friends.
    333 
    334     friend constexpr message_flags
    335     operator&(message_flags __f1, message_flags __f2) noexcept
    336     { return message_flags( int(__f1) & int(__f2) ); }
    337 
    338     friend constexpr message_flags
    339     operator|(message_flags __f1, message_flags __f2) noexcept
    340     { return message_flags( int(__f1) | int(__f2) ); }
    341 
    342     friend constexpr message_flags
    343     operator^(message_flags __f1, message_flags __f2) noexcept
    344     { return message_flags( int(__f1) ^ int(__f2) ); }
    345 
    346     friend constexpr message_flags
    347     operator~(message_flags __f) noexcept
    348     { return message_flags( ~int(__f) ); }
    349 
    350     friend constexpr message_flags&
    351     operator&=(message_flags& __f1, message_flags __f2) noexcept
    352     { return __f1 = (__f1 & __f2); }
    353 
    354     friend constexpr message_flags&
    355     operator|=(message_flags& __f1, message_flags __f2) noexcept
    356     { return __f1 = (__f1 | __f2); }
    357 
    358     friend constexpr message_flags&
    359     operator^=(message_flags& __f1, message_flags __f2) noexcept
    360     { return __f1 = (__f1 ^ __f2); }
    361 
    362 #ifdef _GLIBCXX_HAVE_SYS_SOCKET_H
    363   protected:
    364     struct __msg_hdr : ::msghdr
    365     {
    366 #ifdef IOV_MAX
    367       using __iovec_array = array<::iovec, IOV_MAX>;
    368 #elif _GLIBCXX_HAVE_UNISTD_H
    369       struct __iovec_array
    370       {
    371 	__iovec_array() : _M_ptr(new ::iovec[size()]) { }
    372 
    373 	::iovec& operator[](size_t __n) noexcept { return _M_ptr[__n]; }
    374 
    375 	::iovec* data() noexcept { return _M_ptr.get(); }
    376 
    377 	static size_t size()
    378 	{
    379 	  static const size_t __iov_max = ::sysconf(_SC_IOV_MAX);
    380 	  return __iov_max;
    381 	}
    382 
    383       private:
    384 	unique_ptr<::iovec[]> _M_ptr;
    385       };
    386 #else
    387       using __iovec_array = array<::iovec, 16>;
    388 #endif
    389 
    390       __iovec_array _M_iov;
    391 
    392       template<typename _BufferSequence>
    393 	explicit
    394 	__msg_hdr(const _BufferSequence& __buffers)
    395 	: msghdr()
    396 	{
    397 	  auto __buf = net::buffer_sequence_begin(__buffers);
    398 	  const auto __bufend = net::buffer_sequence_end(__buffers);
    399 	  size_t __len = 0;
    400 	  while (__buf != __bufend && __len != _M_iov.size())
    401 	    {
    402 	      _M_iov[__len].iov_base = (void*)__buf->data();
    403 	      _M_iov[__len].iov_len = __buf->size();
    404 	      ++__buf;
    405 	      ++__len;
    406 	    }
    407 	  this->msg_iovlen = __len;
    408 	  this->msg_iov = _M_iov.data();
    409 	}
    410 
    411       template<typename _BufferSequence, typename _Endpoint>
    412 	__msg_hdr(const _BufferSequence& __buffers, const _Endpoint& __ep)
    413 	: __msg_hdr(__buffers)
    414 	{
    415 	  this->msg_name = __ep.data();
    416 	  this->msg_namelen = __ep.size();
    417 	}
    418     };
    419 #endif
    420 
    421   protected:
    422     socket_base() = default;
    423     ~socket_base() = default;
    424   };
    425 
    426   // TODO define socket_base static constants in .so for C++14 mode
    427 
    428 #if _GLIBCXX_HAVE_UNISTD_H
    429 
    430   class __socket_impl
    431   {
    432   protected:
    433 
    434     using executor_type = io_context::executor_type;
    435     using native_handle_type = int;
    436 
    437     explicit
    438     __socket_impl(io_context& __ctx) : _M_ctx(std::addressof(__ctx)) { }
    439 
    440     __socket_impl(__socket_impl&& __rhs)
    441     : _M_ctx(__rhs._M_ctx),
    442       _M_sockfd(std::__exchange(__rhs._M_sockfd, -1)),
    443       _M_bits(std::__exchange(__rhs._M_bits, {}))
    444     { }
    445 
    446     __socket_impl&
    447     operator=(__socket_impl&& __rhs)
    448     {
    449       _M_ctx = __rhs._M_ctx;
    450       _M_sockfd = std::__exchange(__rhs._M_sockfd, -1);
    451       _M_bits = std::__exchange(__rhs._M_bits, {});
    452       return *this;
    453     }
    454 
    455     ~__socket_impl() = default;
    456 
    457     __socket_impl(const __socket_impl&) = delete;
    458     __socket_impl& operator=(const __socket_impl&) = delete;
    459 
    460     executor_type get_executor() noexcept { return _M_ctx->get_executor(); }
    461 
    462     native_handle_type native_handle() noexcept { return _M_sockfd; }
    463 
    464     bool is_open() const noexcept { return _M_sockfd != -1; }
    465 
    466     void
    467     close(error_code& __ec)
    468     {
    469       if (is_open())
    470 	{
    471 	  cancel(__ec);
    472 	  if (!__ec)
    473 	    {
    474 	      if (::close(_M_sockfd) == -1)
    475 		__ec.assign(errno, generic_category());
    476 	      else
    477 		{
    478 		  get_executor().context()._M_remove_fd(_M_sockfd);
    479 		  _M_sockfd = -1;
    480 		}
    481 	    }
    482 	}
    483     }
    484 
    485     void cancel(error_code& __ec) { _M_ctx->cancel(_M_sockfd, __ec); }
    486 
    487     void
    488     non_blocking(bool __mode, error_code&)
    489     { _M_bits.non_blocking = __mode; }
    490 
    491     bool non_blocking() const { return _M_bits.non_blocking; }
    492 
    493     void
    494     native_non_blocking(bool __mode, error_code& __ec)
    495     {
    496 #if defined _GLIBCXX_HAVE_FCNTL_H && defined _GLIBCXX_HAVE_DECL_O_NONBLOCK
    497       int __flags = ::fcntl(_M_sockfd, F_GETFL, 0);
    498       if (__flags >= 0)
    499 	{
    500 	  if (__mode)
    501 	    __flags |= O_NONBLOCK;
    502 	  else
    503 	    __flags &= ~O_NONBLOCK;
    504 	  __flags = ::fcntl(_M_sockfd, F_SETFL, __flags);
    505 	}
    506       if (__flags == -1)
    507 	__ec.assign(errno, generic_category());
    508       else
    509 	{
    510 	  __ec.clear();
    511 	  _M_bits.native_non_blocking = __mode;
    512 	}
    513 #else
    514       __ec = std::make_error_code(std::errc::not_supported);
    515 #endif
    516     }
    517 
    518     bool
    519     native_non_blocking() const
    520     {
    521 #if defined _GLIBCXX_HAVE_FCNTL_H && defined _GLIBCXX_HAVE_DECL_O_NONBLOCK
    522       if (_M_bits.native_non_blocking == -1)
    523 	{
    524 	  const int __flags = ::fcntl(_M_sockfd, F_GETFL, 0);
    525 	  if (__flags == -1)
    526 	    return 0;
    527 	  _M_bits.native_non_blocking = __flags & O_NONBLOCK;
    528 	}
    529       return _M_bits.native_non_blocking;
    530 #else
    531       return false;
    532 #endif
    533     }
    534 
    535     io_context*	_M_ctx;
    536     int		_M_sockfd{-1};
    537     struct {
    538       unsigned		non_blocking : 1;
    539       mutable signed	native_non_blocking : 2;
    540       unsigned		enable_connection_aborted : 1;
    541     } _M_bits{};
    542   };
    543 
    544   template<typename _Protocol>
    545     class __basic_socket_impl : public __socket_impl
    546     {
    547       using __base = __socket_impl;
    548 
    549     protected:
    550       using protocol_type = _Protocol;
    551       using endpoint_type = typename protocol_type::endpoint;
    552 
    553       explicit
    554       __basic_socket_impl(io_context& __ctx) : __base(__ctx) { }
    555 
    556       __basic_socket_impl(__basic_socket_impl&&) = default;
    557 
    558       template<typename _OtherProtocol>
    559 	__basic_socket_impl(__basic_socket_impl<_OtherProtocol>&& __rhs)
    560 	: __base(std::move(__rhs)), _M_protocol(std::move(__rhs._M_protocol))
    561 	{ }
    562 
    563       __basic_socket_impl&
    564       operator=(__basic_socket_impl&& __rhs)
    565       {
    566 	if (this == std::addressof(__rhs))
    567 	  return *this;
    568 	_M_close();
    569 	__base::operator=(std::move(__rhs));
    570 	return *this;
    571       }
    572 
    573       ~__basic_socket_impl() { _M_close(); }
    574 
    575       __basic_socket_impl(const __basic_socket_impl&) = delete;
    576       __basic_socket_impl& operator=(const __basic_socket_impl&) = delete;
    577 
    578       void
    579       open(const protocol_type& __protocol, error_code& __ec)
    580       {
    581 #ifdef _GLIBCXX_HAVE_SYS_SOCKET_H
    582 	if (is_open())
    583 	  __ec = socket_errc::already_open;
    584 	else
    585 	  {
    586 	    _M_protocol = __protocol;
    587 	    _M_sockfd = ::socket(__protocol.family(), __protocol.type(),
    588 				 __protocol.protocol());
    589 	    if (is_open())
    590 	      {
    591 		get_executor().context()._M_add_fd(_M_sockfd);
    592 	      __ec.clear();
    593 	      }
    594 	    else
    595 	      __ec.assign(errno, std::generic_category());
    596 	  }
    597 #else
    598 	__ec = std::make_error_code(errc::operation_not_supported);
    599 #endif
    600       }
    601 
    602       void
    603       assign(const protocol_type& __protocol,
    604 	     const native_handle_type& __native_socket,
    605 	     error_code& __ec)
    606       {
    607 	if (is_open())
    608 	  __ec = socket_errc::already_open;
    609 	else
    610 	  {
    611 	    _M_protocol = __protocol;
    612 	    _M_bits.native_non_blocking = -1;
    613 	    _M_sockfd = __native_socket;
    614 	    if (is_open())
    615 	      {
    616 		get_executor().context()._M_add_fd(_M_sockfd);
    617 		__ec.clear();
    618 	      }
    619 	    else
    620 	      __ec.assign(errno, std::generic_category());
    621 	  }
    622       }
    623 
    624       native_handle_type release(error_code& __ec)
    625       {
    626 	__glibcxx_assert(is_open());
    627 	cancel(__ec);
    628 	return std::__exchange(_M_sockfd, -1);
    629       }
    630 
    631       template<typename _SettableSocketOption>
    632 	void
    633 	set_option(const _SettableSocketOption& __option, error_code& __ec)
    634 	{
    635 # ifdef _GLIBCXX_HAVE_SYS_SOCKET_H
    636 	  int __result = ::setsockopt(_M_sockfd, __option.level(_M_protocol),
    637 				      __option.name(_M_protocol),
    638 				      __option.data(_M_protocol),
    639 				      __option.size(_M_protocol));
    640 	  if (__result == -1)
    641 	    __ec.assign(errno, generic_category());
    642 	  else
    643 	    __ec.clear();
    644 #else
    645 	  __ec = std::make_error_code(std::errc::not_supported);
    646 #endif
    647 	}
    648 
    649       template<typename _GettableSocketOption>
    650 	void
    651 	get_option(_GettableSocketOption& __option, error_code& __ec) const
    652 	{
    653 # ifdef _GLIBCXX_HAVE_SYS_SOCKET_H
    654 	  int __result = ::getsockopt(_M_sockfd, __option.level(_M_protocol),
    655 				      __option.name(_M_protocol),
    656 				      __option.data(_M_protocol),
    657 				      __option.size(_M_protocol));
    658 	  if (__result == -1)
    659 	    __ec.assign(errno, generic_category());
    660 	  else
    661 	    __ec.clear();
    662 #else
    663 	  __ec = std::make_error_code(std::errc::not_supported);
    664 #endif
    665 	}
    666 
    667       template<typename _IoControlCommand>
    668 	void
    669 	io_control(_IoControlCommand& __command, error_code& __ec)
    670 	{
    671 #ifdef _GLIBCXX_HAVE_SYS_IOCTL_H
    672 	  int __result = ::ioctl(_M_sockfd, __command.name(),
    673 				 __command.data());
    674 	  if (__result == -1)
    675 	    __ec.assign(errno, generic_category());
    676 	  else
    677 	    __ec.clear();
    678 #else
    679 	  __ec = std::make_error_code(std::errc::not_supported);
    680 #endif
    681 	}
    682 
    683       endpoint_type
    684       local_endpoint(error_code& __ec) const
    685       {
    686 	endpoint_type __endpoint;
    687 #ifdef _GLIBCXX_HAVE_SYS_SOCKET_H
    688 	socklen_t __endpoint_len = __endpoint.capacity();
    689 	if (::getsockname(_M_sockfd, (sockaddr*)__endpoint.data(),
    690 			  &__endpoint_len) == -1)
    691 	  {
    692 	    __ec.assign(errno, generic_category());
    693 	    return endpoint_type{};
    694 	  }
    695 	__ec.clear();
    696 	__endpoint.resize(__endpoint_len);
    697 #else
    698 	__ec = std::make_error_code(errc::operation_not_supported);
    699 #endif
    700 	return __endpoint;
    701       }
    702 
    703       void
    704       bind(const endpoint_type& __endpoint, error_code& __ec)
    705       {
    706 #ifdef _GLIBCXX_HAVE_SYS_SOCKET_H
    707 	if (::bind(_M_sockfd, (sockaddr*)__endpoint.data(), __endpoint.size())
    708 	    == -1)
    709 	  __ec.assign(errno, generic_category());
    710 	else
    711 	  __ec.clear();
    712 #else
    713 	__ec = std::make_error_code(errc::operation_not_supported);
    714 #endif
    715       }
    716 
    717       _Protocol	_M_protocol{ endpoint_type{}.protocol() };
    718 
    719     private:
    720       void
    721       _M_close()
    722       {
    723 	if (is_open())
    724 	  {
    725 	    error_code __ec;
    726 	    cancel(__ec);
    727 #ifdef _GLIBCXX_HAVE_SYS_SOCKET_H
    728 	    set_option(socket_base::linger{false, chrono::seconds{}}, __ec);
    729 #endif
    730 	    ::close(_M_sockfd);
    731 	  }
    732       }
    733     };
    734 
    735   template<typename _Protocol>
    736     class basic_socket
    737     : public socket_base, private __basic_socket_impl<_Protocol>
    738     {
    739       using __base = __basic_socket_impl<_Protocol>;
    740 
    741     public:
    742       // types:
    743 
    744       using executor_type = io_context::executor_type;
    745       using native_handle_type = int;
    746       using protocol_type = _Protocol;
    747       using endpoint_type = typename protocol_type::endpoint;
    748 
    749       static_assert(__detail::__protocol<protocol_type>,
    750 		    "protocol_type meets the Protocol requirements");
    751 
    752       // basic_socket operations:
    753 
    754       executor_type get_executor() noexcept { return __base::get_executor(); }
    755 
    756       native_handle_type
    757       native_handle() noexcept { return __base::native_handle(); }
    758 
    759       void
    760       open(const protocol_type& __protocol = protocol_type())
    761       { open(__protocol, __throw_on_error{"basic_socket::open"}); }
    762 
    763       void
    764       open(const protocol_type& __protocol, error_code& __ec)
    765       { __base::open(__protocol, __ec); }
    766 
    767       void
    768       assign(const protocol_type& __protocol,
    769 	     const native_handle_type& __native_socket)
    770       {
    771 	assign(__protocol, __native_socket,
    772 	       __throw_on_error{"basic_socket::assign"});
    773       }
    774 
    775       void
    776       assign(const protocol_type& __protocol,
    777 	     const native_handle_type& __native_socket,
    778 	     error_code& __ec)
    779       { __base::assign(__protocol, __native_socket, __ec); }
    780 
    781       native_handle_type release()
    782       { return release(__throw_on_error{"basic_socket::release"}); }
    783 
    784       native_handle_type release(error_code& __ec)
    785       { return __base::release(__ec); }
    786 
    787       _GLIBCXX_NODISCARD bool
    788       is_open() const noexcept { return __base::is_open(); }
    789 
    790       void close() { close(__throw_on_error{"basic_socket::close"}); }
    791 
    792       void close(error_code& __ec) { __base::close(__ec); }
    793 
    794       void cancel() { cancel(__throw_on_error{"basic_socket::cancel"}); }
    795 
    796       void cancel(error_code& __ec) { __base::cancel(__ec); }
    797 
    798       template<typename _SettableSocketOption>
    799 	void
    800 	set_option(const _SettableSocketOption& __option)
    801 	{ set_option(__option, __throw_on_error{"basic_socket::set_option"}); }
    802 
    803       template<typename _SettableSocketOption>
    804 	void
    805 	set_option(const _SettableSocketOption& __option, error_code& __ec)
    806 	{ __base::set_option(__option, __ec); }
    807 
    808       template<typename _GettableSocketOption>
    809 	void
    810 	get_option(_GettableSocketOption& __option) const
    811 	{ get_option(__option, __throw_on_error{"basic_socket::get_option"}); }
    812 
    813       template<typename _GettableSocketOption>
    814 	void
    815 	get_option(_GettableSocketOption& __option, error_code& __ec) const
    816 	{ __base::get_option(__option, __ec); }
    817 
    818       template<typename _IoControlCommand>
    819 	void
    820 	io_control(_IoControlCommand& __command)
    821 	{
    822 	  io_control(__command, __throw_on_error{"basic_socket::io_control"});
    823 	}
    824 
    825       template<typename _IoControlCommand>
    826 	void
    827 	io_control(_IoControlCommand& __command, error_code& __ec)
    828 	{ __base::io_control(__command, __ec); }
    829 
    830       void
    831       non_blocking(bool __mode)
    832       { non_blocking(__mode, __throw_on_error{"basic_socket::non_blocking"}); }
    833 
    834       void
    835       non_blocking(bool __mode, error_code& __ec)
    836       { __base::non_blocking(__mode, __ec); }
    837 
    838       bool non_blocking() const { return __base::non_blocking(); }
    839 
    840       void
    841       native_non_blocking(bool __mode)
    842       {
    843 	native_non_blocking(__mode, __throw_on_error{
    844 	    "basic_socket::native_non_blocking"});
    845       }
    846 
    847       void
    848       native_non_blocking(bool __mode, error_code& __ec)
    849       { __base::native_non_blocking(__mode, __ec); }
    850 
    851       bool
    852       native_non_blocking() const
    853       { return __base::native_non_blocking(); }
    854 
    855       bool at_mark() const
    856       { return at_mark(__throw_on_error{"basic_socket::at_mark"}); }
    857 
    858       bool
    859       at_mark(error_code& __ec) const
    860       {
    861 #ifdef _GLIBCXX_HAVE_SOCKATMARK
    862 	const int __result = ::sockatmark(native_handle());
    863 	if (__result == -1)
    864 	  {
    865 	    __ec.assign(errno, generic_category());
    866 	    return false;
    867 	  }
    868 	__ec.clear();
    869 	return (bool)__result;
    870 #else
    871 	__ec = std::make_error_code(errc::operation_not_supported);
    872 	return false;
    873 #endif
    874       }
    875 
    876       size_t
    877       available() const
    878       { return available(__throw_on_error{"basic_socket::available"}); }
    879 
    880       size_t
    881       available(error_code& __ec) const
    882       {
    883 	if (!is_open())
    884 	  {
    885 	    __ec = std::make_error_code(errc::bad_file_descriptor);
    886 	    return 0;
    887 	  }
    888 #if defined _GLIBCXX_HAVE_SYS_IOCTL_H && defined FIONREAD
    889 	int __avail = 0;
    890 	if (::ioctl(this->_M_sockfd, FIONREAD, &__avail) == -1)
    891 	  {
    892 	    __ec.assign(errno, generic_category());
    893 	    return 0;
    894 	  }
    895 	__ec.clear();
    896 	return __avail;
    897 #else
    898 	return 0;
    899 #endif
    900       }
    901 
    902       void
    903       bind(const endpoint_type& __endpoint)
    904       { return bind(__endpoint, __throw_on_error{"basic_socket::bind"}); }
    905 
    906       void
    907       bind(const endpoint_type& __endpoint, error_code& __ec)
    908       { __base::bind(__endpoint, __ec); }
    909 
    910       void shutdown(shutdown_type __what)
    911       { return shutdown(__what, __throw_on_error{"basic_socket::shutdown"}); }
    912 
    913       void
    914       shutdown(shutdown_type __what, error_code& __ec)
    915       {
    916 #ifdef _GLIBCXX_HAVE_SYS_SOCKET_H
    917 	if (::shutdown(native_handle(), static_cast<int>(__what)) == -1)
    918 	  __ec.assign(errno, generic_category());
    919 	else
    920 	  __ec.clear();
    921 #else
    922 	__ec = std::make_error_code(errc::operation_not_supported);
    923 #endif
    924       }
    925 
    926       endpoint_type
    927       local_endpoint() const
    928       {
    929 	return local_endpoint(
    930 	    __throw_on_error{"basic_socket::local_endpoint"});
    931       }
    932 
    933       endpoint_type
    934       local_endpoint(error_code& __ec) const
    935       { return __base::local_endpoint(__ec); }
    936 
    937       endpoint_type
    938       remote_endpoint() const
    939       {
    940 	return remote_endpoint(
    941 	    __throw_on_error{"basic_socket::remote_endpoint"});
    942       }
    943 
    944       endpoint_type
    945       remote_endpoint(error_code& __ec) const
    946       {
    947 	endpoint_type __endpoint;
    948 #ifdef _GLIBCXX_HAVE_SYS_SOCKET_H
    949 	socklen_t __endpoint_len = __endpoint.capacity();
    950 	if (::getpeername(this->_M_sockfd, (sockaddr*)__endpoint.data(),
    951 			  &__endpoint_len)
    952 	    == -1)
    953 	  {
    954 	    __ec.assign(errno, generic_category());
    955 	    return endpoint_type{};
    956 	  }
    957 	__ec.clear();
    958 	__endpoint.resize(__endpoint_len);
    959 #else
    960 	__ec = std::make_error_code(errc::operation_not_supported);
    961 #endif
    962 	return __endpoint;
    963       }
    964 
    965       void
    966       connect(const endpoint_type& __endpoint)
    967       {
    968 	return connect(__endpoint, __throw_on_error{"basic_socket::connect"});
    969       }
    970 
    971       void
    972       connect(const endpoint_type& __endpoint, error_code& __ec)
    973       {
    974 #ifdef _GLIBCXX_HAVE_SYS_SOCKET_H
    975 	if (!is_open())
    976 	  {
    977 	    open(__endpoint.protocol(), __ec);
    978 	    if (__ec)
    979 	      return;
    980 	  }
    981 	if (::connect(native_handle(), (const sockaddr*)__endpoint.data(),
    982 		      __endpoint.size()) == -1)
    983 	  __ec.assign(errno, generic_category());
    984 	else
    985 	  __ec.clear();
    986 #else
    987 	__ec = std::make_error_code(errc::operation_not_supported);
    988 #endif
    989       }
    990 
    991       template<typename _CompletionToken>
    992 	__deduced_t<_CompletionToken, void(error_code)>
    993 	async_connect(const endpoint_type& __endpoint,
    994 		      _CompletionToken&& __token)
    995 	{
    996 	  async_completion<_CompletionToken, void(error_code)> __init{__token};
    997 
    998 	  if (!is_open())
    999 	    {
   1000 	      error_code __ec;
   1001 	      open(__endpoint.protocol(), __ec);
   1002 	      if (__ec)
   1003 		{
   1004                   auto __ex = net::get_associated_executor(
   1005                       __init.completion_handler, get_executor());
   1006                   auto __a = get_associated_allocator(
   1007                       __init.completion_handler, std::allocator<void>());
   1008                   __ex.post(
   1009                       [__h = std::move(__init.completion_handler), __ec]
   1010                       () mutable
   1011                       { __h(__ec); }, __a);
   1012 		  return __init.result.get();
   1013 		}
   1014 	    }
   1015 
   1016 	  get_executor().context().async_wait( native_handle(),
   1017 	      (int) socket_base::wait_read,
   1018 	      [__h = std::move(__init.completion_handler),
   1019                __ep = std::move(__endpoint),
   1020                __fd = native_handle()]
   1021                (error_code __ec) mutable {
   1022 #ifdef _GLIBCXX_HAVE_SYS_SOCKET_H
   1023                   if (!__ec && ::connect(__fd, (const sockaddr*)__ep.data(),
   1024 					 __ep.size()) == -1)
   1025                     __ec.assign(errno, generic_category());
   1026 #else
   1027 		  __ec = std::make_error_code(errc::operation_not_supported);
   1028 #endif
   1029 		  __h(__ec);
   1030 	      });
   1031 	  return __init.result.get();
   1032 	}
   1033 
   1034       void
   1035       wait(wait_type __w)
   1036       { return wait(__w, __throw_on_error{"basic_socket::wait"}); }
   1037 
   1038       void
   1039       wait(wait_type __w, error_code& __ec)
   1040       {
   1041 #ifdef _GLIBCXX_HAVE_POLL_H
   1042 	::pollfd __fd;
   1043 	__fd.fd = native_handle();
   1044 	__fd.events = static_cast<int>(__w);
   1045 	int __res = ::poll(&__fd, 1, -1);
   1046 	if (__res == -1)
   1047 	  __ec.assign(errno, generic_category());
   1048 	else
   1049 	  __ec.clear();
   1050 #else
   1051 	__ec = std::make_error_code(errc::operation_not_supported);
   1052 #endif
   1053       }
   1054 
   1055       template<typename _CompletionToken>
   1056 	__deduced_t<_CompletionToken, void(error_code)>
   1057 	async_wait(wait_type __w, _CompletionToken&& __token)
   1058 	{
   1059 	  async_completion<_CompletionToken, void(error_code)> __init{__token};
   1060 	  get_executor().context().async_wait( native_handle(),
   1061 	      static_cast<int>(__w),
   1062 	      [__h = std::move(__init.completion_handler)]
   1063               (error_code __ec) mutable {
   1064 		  __h(__ec);
   1065 	      });
   1066 	  return __init.result.get();
   1067 	}
   1068 
   1069     protected:
   1070       // construct / copy / destroy:
   1071 
   1072       using __base::__base;
   1073 
   1074       explicit
   1075       basic_socket(io_context& __ctx) : __base(__ctx) { }
   1076 
   1077       basic_socket(io_context& __ctx, const protocol_type& __protocol)
   1078       : __base(__ctx)
   1079       { open(__protocol); }
   1080 
   1081       basic_socket(io_context& __ctx, const endpoint_type& __endpoint)
   1082       : basic_socket(__ctx, __endpoint.protocol())
   1083       { bind(__endpoint); }
   1084 
   1085       basic_socket(io_context& __ctx, const protocol_type& __protocol,
   1086 		   const native_handle_type& __native_socket)
   1087       : __base(__ctx)
   1088       { assign(__protocol, __native_socket); }
   1089 
   1090       basic_socket(const basic_socket&) = delete;
   1091 
   1092       basic_socket(basic_socket&& __rhs) = default;
   1093 
   1094       template<typename _OtherProtocol, typename _Requires
   1095 	       = _Require<is_convertible<_OtherProtocol, _Protocol>>>
   1096 	basic_socket(basic_socket<_OtherProtocol>&& __rhs)
   1097 	: __base(std::move(__rhs)) { }
   1098 
   1099       ~basic_socket() = default;
   1100 
   1101       basic_socket& operator=(const basic_socket&) = delete;
   1102 
   1103       basic_socket& operator=(basic_socket&& __rhs) = default;
   1104 
   1105       template<typename _OtherProtocol>
   1106 	enable_if_t<is_convertible<_OtherProtocol, _Protocol>::value,
   1107 		    basic_socket&>
   1108 	operator=(basic_socket<_OtherProtocol>&& __rhs)
   1109         { return *this = basic_socket{std::move(__rhs)}; }
   1110     };
   1111 
   1112   template<typename _Protocol>
   1113     class basic_datagram_socket : public basic_socket<_Protocol>
   1114     {
   1115       using __base = basic_socket<_Protocol>;
   1116 
   1117     public:
   1118       // types:
   1119 
   1120       using native_handle_type = int;
   1121       using protocol_type = _Protocol;
   1122       using endpoint_type = typename protocol_type::endpoint;
   1123 
   1124       // construct / copy / destroy:
   1125 
   1126       explicit
   1127       basic_datagram_socket(io_context& __ctx) : __base(__ctx) { }
   1128 
   1129       basic_datagram_socket(io_context& __ctx, const protocol_type& __protocol)
   1130       : __base(__ctx, __protocol) { }
   1131 
   1132       basic_datagram_socket(io_context& __ctx, const endpoint_type& __endpoint)
   1133       : __base(__ctx, __endpoint) { }
   1134 
   1135       basic_datagram_socket(io_context& __ctx, const protocol_type& __protocol,
   1136 			    const native_handle_type& __native_socket)
   1137       : __base(__ctx, __protocol, __native_socket) { }
   1138 
   1139       basic_datagram_socket(const basic_datagram_socket&) = delete;
   1140 
   1141       basic_datagram_socket(basic_datagram_socket&& __rhs) = default;
   1142 
   1143       template<typename _OtherProtocol, typename _Requires
   1144 	       = _Require<is_convertible<_OtherProtocol, _Protocol>>>
   1145 	basic_datagram_socket(basic_datagram_socket<_OtherProtocol>&& __rhs)
   1146 	: __base(std::move(__rhs)) { }
   1147 
   1148       ~basic_datagram_socket() = default;
   1149 
   1150       basic_datagram_socket& operator=(const basic_datagram_socket&) = delete;
   1151 
   1152       basic_datagram_socket& operator=(basic_datagram_socket&& __rhs) = default;
   1153 
   1154       template<typename _OtherProtocol>
   1155 	enable_if_t<is_convertible<_OtherProtocol, _Protocol>::value,
   1156 		    basic_datagram_socket&>
   1157 	operator=(basic_datagram_socket<_OtherProtocol>&& __rhs)
   1158 	{
   1159 	  __base::operator=(std::move(__rhs));
   1160 	  return *this;
   1161 	}
   1162 
   1163       // basic_datagram_socket operations:
   1164 
   1165       template<typename _MutableBufferSequence>
   1166 	size_t
   1167 	receive(const _MutableBufferSequence& __buffers)
   1168 	{
   1169 	  return receive(__buffers, socket_base::message_flags(),
   1170 			 __throw_on_error{"basic_datagram_socket::receive"});
   1171 	}
   1172 
   1173       template<typename _MutableBufferSequence>
   1174 	size_t
   1175 	receive(const _MutableBufferSequence& __buffers, error_code& __ec)
   1176         { return receive(__buffers, socket_base::message_flags(), __ec); }
   1177 
   1178       template<typename _MutableBufferSequence>
   1179 	size_t
   1180 	receive(const _MutableBufferSequence& __buffers,
   1181 		       socket_base::message_flags __flags)
   1182 	{
   1183 	  return receive(__buffers, __flags,
   1184 			 __throw_on_error{"basic_datagram_socket::receive"});
   1185 	}
   1186 
   1187       template<typename _MutableBufferSequence>
   1188 	size_t
   1189 	receive(const _MutableBufferSequence& __buffers,
   1190 		socket_base::message_flags __flags, error_code& __ec)
   1191 	{
   1192 #ifdef _GLIBCXX_HAVE_SYS_SOCKET_H
   1193 	  socket_base::__msg_hdr __msg(__buffers);
   1194 	  ssize_t __result = ::recvmsg(this->native_handle(), &__msg,
   1195 				       static_cast<int>(__flags));
   1196 	  if (__result == -1)
   1197             {
   1198               __ec.assign(errno, generic_category());
   1199               return 0;
   1200             }
   1201           __ec.clear();
   1202           return __result;
   1203 #else
   1204 	  __ec = std::make_error_code(errc::operation_not_supported);
   1205 	  return 0;
   1206 #endif
   1207 	}
   1208 
   1209       template<typename _MutableBufferSequence, typename _CompletionToken>
   1210 	__deduced_t<_CompletionToken, void(error_code, size_t)>
   1211 	async_receive(const _MutableBufferSequence& __buffers,
   1212 		      _CompletionToken&& __token)
   1213 	{
   1214 	  return async_receive(__buffers, socket_base::message_flags(),
   1215 			       std::forward<_CompletionToken>(__token));
   1216 	}
   1217 
   1218       template<typename _MutableBufferSequence, typename _CompletionToken>
   1219 	__deduced_t<_CompletionToken, void(error_code, size_t)>
   1220 	async_receive(const _MutableBufferSequence& __buffers,
   1221 		      socket_base::message_flags __flags,
   1222 		      _CompletionToken&& __token)
   1223 	{
   1224           async_completion<_CompletionToken, void(error_code, size_t)>
   1225             __init{__token};
   1226 
   1227 	  this->get_executor().context().async_wait(this->native_handle(),
   1228 	      (int) socket_base::wait_read,
   1229 	      [__h = std::move(__init.completion_handler),
   1230                &__buffers, __flags = static_cast<int>(__flags),
   1231                __fd = this->native_handle()]
   1232               (error_code __ec) mutable {
   1233                   if (__ec)
   1234                     {
   1235                       __h(__ec);
   1236                       return;
   1237                     }
   1238 #ifdef _GLIBCXX_HAVE_SYS_SOCKET_H
   1239                   socket_base::__msg_hdr __msg(__buffers);
   1240                   ssize_t __result = ::recvmsg(__fd, &__msg, __flags);
   1241                   if (__result == -1)
   1242                     {
   1243                       __ec.assign(errno, generic_category());
   1244                       __result = 0;
   1245                     }
   1246                   else
   1247                     __ec.clear();
   1248 		  __h(__ec, __result);
   1249 #else
   1250 		  __h(std::make_error_code(errc::operation_not_supported), 0);
   1251 #endif
   1252 	      });
   1253 	  return __init.result.get();
   1254 	}
   1255 
   1256       template<typename _MutableBufferSequence>
   1257 	size_t
   1258 	receive_from(const _MutableBufferSequence& __buffers,
   1259 		     endpoint_type& __sender)
   1260 	{
   1261 	  return receive_from(__buffers, __sender,
   1262 			      socket_base::message_flags(),
   1263 			      __throw_on_error{
   1264 				  "basic_datagram_socket::receive_from"});
   1265 	}
   1266 
   1267       template<typename _MutableBufferSequence>
   1268 	size_t
   1269 	receive_from(const _MutableBufferSequence& __buffers,
   1270 		     endpoint_type& __sender, error_code& __ec)
   1271 	{
   1272 	  return receive_from(__buffers, __sender,
   1273 			      socket_base::message_flags(), __ec);
   1274 	}
   1275 
   1276       template<typename _MutableBufferSequence>
   1277 	size_t
   1278 	receive_from(const _MutableBufferSequence& __buffers,
   1279 		     endpoint_type& __sender,
   1280 		     socket_base::message_flags __flags)
   1281 	{
   1282 	  return receive_from(__buffers, __sender, __flags,
   1283 			      __throw_on_error{
   1284 				  "basic_datagram_socket::receive_from"});
   1285 	}
   1286 
   1287       template<typename _MutableBufferSequence>
   1288 	size_t
   1289 	receive_from(const _MutableBufferSequence& __buffers,
   1290 		     endpoint_type& __sender,
   1291 		     socket_base::message_flags __flags,
   1292 		     error_code& __ec)
   1293 	{
   1294 #ifdef _GLIBCXX_HAVE_SYS_SOCKET_H
   1295 	  socket_base::__msg_hdr __msg(__buffers, __sender);
   1296 	  ssize_t __result = ::recvmsg(this->native_handle(), &__msg,
   1297 				       static_cast<int>(__flags));
   1298 	  if (__result == -1)
   1299             {
   1300               __ec.assign(errno, generic_category());
   1301               return 0;
   1302             }
   1303           __ec.clear();
   1304           __sender.resize(__msg.msg_namelen);
   1305           return __result;
   1306 #else
   1307 	  __ec = std::make_error_code(errc::operation_not_supported);
   1308 	  return 0;
   1309 #endif
   1310 	}
   1311 
   1312       template<typename _MutableBufferSequence, typename _CompletionToken>
   1313 	__deduced_t<_CompletionToken, void(error_code, size_t)>
   1314 	async_receive_from(const _MutableBufferSequence& __buffers,
   1315 			   endpoint_type& __sender,
   1316 			   _CompletionToken&& __token)
   1317 	{
   1318 	  return async_receive_from(__buffers, __sender,
   1319 				    socket_base::message_flags(),
   1320 				    std::forward<_CompletionToken>(__token));
   1321 	}
   1322 
   1323       template<typename _MutableBufferSequence, typename _CompletionToken>
   1324 	__deduced_t<_CompletionToken, void(error_code, size_t)>
   1325 	async_receive_from(const _MutableBufferSequence& __buffers,
   1326 			   endpoint_type& __sender,
   1327 			   socket_base::message_flags __flags,
   1328 			   _CompletionToken&& __token)
   1329 	{
   1330 	  async_completion<_CompletionToken, void(error_code, size_t)>
   1331             __init{__token};
   1332 
   1333 	  this->get_executor().context().async_wait( this->native_handle(),
   1334 	      (int) socket_base::wait_read,
   1335 	      [__h = std::move(__init.completion_handler),
   1336                &__buffers, __flags = static_cast<int>(__flags),
   1337                __sender = std::move(__sender),
   1338                __fd = this->native_handle()]
   1339               (error_code __ec) mutable {
   1340                   if (__ec)
   1341                     {
   1342                       __h(__ec);
   1343                       return;
   1344                     }
   1345 #ifdef _GLIBCXX_HAVE_SYS_SOCKET_H
   1346                   socket_base::__msg_hdr __msg(__buffers, __sender);
   1347                   ssize_t __result = ::recvmsg(__fd, &__msg, __flags);
   1348                   if (__result == -1)
   1349                     {
   1350                       __ec.assign(errno, generic_category());
   1351                       __result = 0;
   1352                     }
   1353                   else
   1354                     {
   1355                       __ec.clear();
   1356                       __sender.resize(__msg.msg_namelen);
   1357                     }
   1358 		  __h(__ec, __result);
   1359 #else
   1360 		  __h(std::make_error_code(errc::operation_not_supported), 0);
   1361 #endif
   1362 	      });
   1363 	  return __init.result.get();
   1364 	}
   1365 
   1366       template<typename _ConstBufferSequence>
   1367 	size_t
   1368 	send(const _ConstBufferSequence& __buffers)
   1369 	{
   1370 	  return send(__buffers, socket_base::message_flags(),
   1371 		      __throw_on_error{"basic_datagram_socket::send"});
   1372 	}
   1373 
   1374       template<typename _ConstBufferSequence>
   1375 	size_t
   1376 	send(const _ConstBufferSequence& __buffers, error_code& __ec)
   1377 	{ return send(__buffers, socket_base::message_flags(), __ec); }
   1378 
   1379       template<typename _ConstBufferSequence>
   1380 	size_t
   1381 	send(const _ConstBufferSequence& __buffers,
   1382 	     socket_base::message_flags __flags)
   1383 	{
   1384 	  return send(__buffers, __flags,
   1385 		      __throw_on_error{"basic_datagram_socket::send"});
   1386 	}
   1387 
   1388       template<typename _ConstBufferSequence>
   1389 	size_t
   1390 	send(const _ConstBufferSequence& __buffers,
   1391 	     socket_base::message_flags __flags, error_code& __ec)
   1392 	{
   1393 #ifdef _GLIBCXX_HAVE_SYS_SOCKET_H
   1394 	  socket_base::__msg_hdr __msg(__buffers);
   1395 	  ssize_t __result = ::sendmsg(this->native_handle(), &__msg,
   1396 				       static_cast<int>(__flags));
   1397 	  if (__result == -1)
   1398             {
   1399               __ec.assign(errno, generic_category());
   1400               return 0;
   1401             }
   1402           __ec.clear();
   1403           return __result;
   1404 #else
   1405 	  __ec = std::make_error_code(errc::operation_not_supported);
   1406 	  return 0;
   1407 #endif
   1408 	}
   1409 
   1410       template<typename _ConstBufferSequence, typename _CompletionToken>
   1411 	__deduced_t<_CompletionToken, void(error_code, size_t)>
   1412 	async_send(const _ConstBufferSequence& __buffers,
   1413 			_CompletionToken&& __token)
   1414 	{
   1415 	  return async_send(__buffers, socket_base::message_flags(),
   1416 			    std::forward<_CompletionToken>(__token));
   1417 	}
   1418 
   1419       template<typename _ConstBufferSequence, typename _CompletionToken>
   1420 	__deduced_t<_CompletionToken, void(error_code, size_t)>
   1421 	async_send(const _ConstBufferSequence& __buffers,
   1422 		   socket_base::message_flags __flags,
   1423 		   _CompletionToken&& __token)
   1424 	{
   1425 	  async_completion<_CompletionToken, void(error_code, size_t)>
   1426             __init{__token};
   1427 
   1428 	  this->get_executor().context().async_wait( this->native_handle(),
   1429 	      (int) socket_base::wait_write,
   1430 	      [__h = std::move(__init.completion_handler),
   1431                &__buffers, __flags = static_cast<int>(__flags),
   1432                __fd = this->native_handle()]
   1433               (error_code __ec) mutable {
   1434                   if (__ec)
   1435                     {
   1436                       __h(__ec);
   1437                       return;
   1438                     }
   1439 #ifdef _GLIBCXX_HAVE_SYS_SOCKET_H
   1440                   socket_base::__msg_hdr __msg(__buffers);
   1441                   ssize_t __result = ::sendmsg(__fd, &__msg, __flags);
   1442                   if (__result == -1)
   1443                     {
   1444                       __ec.assign(errno, generic_category());
   1445                       __result = 0;
   1446                     }
   1447                   else
   1448                     __ec.clear();
   1449 		  __h(__ec, __result);
   1450 #else
   1451 		  __h(std::make_error_code(errc::operation_not_supported), 0);
   1452 #endif
   1453 	      });
   1454 	  return __init.result.get();
   1455 	}
   1456 
   1457       template<typename _ConstBufferSequence>
   1458 	size_t
   1459 	send_to(const _ConstBufferSequence& __buffers,
   1460 	        const endpoint_type& __recipient)
   1461 	{
   1462 	  return send_to(__buffers, __recipient,
   1463 			 socket_base::message_flags(),
   1464 			 __throw_on_error{"basic_datagram_socket::send_to"});
   1465 	}
   1466 
   1467       template<typename _ConstBufferSequence>
   1468 	size_t
   1469 	send_to(const _ConstBufferSequence& __buffers,
   1470 		const endpoint_type& __recipient, error_code& __ec)
   1471 	{
   1472 	  return send_to(__buffers, __recipient,
   1473 			 socket_base::message_flags(), __ec);
   1474 	}
   1475 
   1476       template<typename _ConstBufferSequence>
   1477 	size_t
   1478 	send_to(const _ConstBufferSequence& __buffers,
   1479 		const endpoint_type& __recipient,
   1480 		socket_base::message_flags __flags)
   1481 	{
   1482 	  return send_to(__buffers, __recipient, __flags,
   1483 			 __throw_on_error{"basic_datagram_socket::send_to"});
   1484 	}
   1485 
   1486       template<typename _ConstBufferSequence>
   1487 	size_t
   1488 	send_to(const _ConstBufferSequence& __buffers,
   1489 	        const endpoint_type& __recipient,
   1490 		socket_base::message_flags __flags, error_code& __ec)
   1491 	{
   1492 #ifdef _GLIBCXX_HAVE_SYS_SOCKET_H
   1493 	  socket_base::__msg_hdr __msg(__buffers, __recipient);
   1494 	  ssize_t __result = ::sendmsg(this->native_handle(), &__msg,
   1495 				       static_cast<int>(__flags));
   1496 	  if (__result == -1)
   1497             {
   1498               __ec.assign(errno, generic_category());
   1499               return 0;
   1500             }
   1501           __ec.clear();
   1502           __recipient.resize(__msg.msg_namelen);
   1503           return __result;
   1504 #else
   1505 	  __ec = std::make_error_code(errc::operation_not_supported);
   1506 	  return 0;
   1507 #endif
   1508 	}
   1509 
   1510       template<typename _ConstBufferSequence, typename _CompletionToken>
   1511 	__deduced_t<_CompletionToken, void(error_code, size_t)>
   1512 	async_send_to(const _ConstBufferSequence& __buffers,
   1513 		      const endpoint_type& __recipient,
   1514 		      _CompletionToken&& __token)
   1515 	{
   1516 	  return async_send_to(__buffers, __recipient,
   1517 			       socket_base::message_flags(),
   1518 			       std::forward<_CompletionToken>(__token));
   1519 	}
   1520 
   1521       template<typename _ConstBufferSequence, typename _CompletionToken>
   1522 	__deduced_t<_CompletionToken, void(error_code, size_t)>
   1523 	async_send_to(const _ConstBufferSequence& __buffers,
   1524 		      const endpoint_type& __recipient,
   1525 		      socket_base::message_flags __flags,
   1526 		      _CompletionToken&& __token)
   1527 	{
   1528 	  async_completion<_CompletionToken, void(error_code, size_t)>
   1529             __init{__token};
   1530 
   1531 	  this->get_executor().context().async_wait( this->native_handle(),
   1532 	      (int) socket_base::wait_write,
   1533 	      [__h = std::move(__init.completion_handler),
   1534                &__buffers, __flags = static_cast<int>(__flags),
   1535                __recipient = std::move(__recipient),
   1536                __fd = this->native_handle()]
   1537               (error_code __ec) mutable {
   1538                   if (__ec)
   1539                     {
   1540                       __h(__ec);
   1541                       return;
   1542                     }
   1543 #ifdef _GLIBCXX_HAVE_SYS_SOCKET_H
   1544                   socket_base::__msg_hdr __msg(__buffers, __recipient);
   1545                   ssize_t __result = ::sendmsg(__fd, &__msg, __flags);
   1546                   if (__result == -1)
   1547                     {
   1548                       __ec.assign(errno, generic_category());
   1549                       __result = 0;
   1550                     }
   1551                   else
   1552                     {
   1553                       __ec.clear();
   1554                       __recipient.resize(__msg.msg_namelen);
   1555                     }
   1556 		  __h(__ec, __result);
   1557 #else
   1558 		  __h(std::make_error_code(errc::operation_not_supported), 0);
   1559 #endif
   1560 	      });
   1561 	  return __init.result.get();
   1562 	}
   1563     };
   1564 
   1565   template<typename _Protocol>
   1566     class basic_stream_socket : public basic_socket<_Protocol>
   1567     {
   1568       using __base = basic_socket<_Protocol>;
   1569 
   1570     public:
   1571       // types:
   1572 
   1573       using native_handle_type = int;
   1574       using protocol_type = _Protocol;
   1575       using endpoint_type = typename protocol_type::endpoint;
   1576 
   1577       // construct / copy / destroy:
   1578 
   1579       explicit
   1580       basic_stream_socket(io_context& __ctx) : __base(__ctx) { }
   1581 
   1582       basic_stream_socket(io_context& __ctx, const protocol_type& __protocol)
   1583       : __base(__ctx, __protocol) { }
   1584 
   1585       basic_stream_socket(io_context& __ctx, const endpoint_type& __endpoint)
   1586       : __base(__ctx, __endpoint) { }
   1587 
   1588       basic_stream_socket(io_context& __ctx, const protocol_type& __protocol,
   1589 			  const native_handle_type& __native_socket)
   1590       : __base(__ctx, __protocol, __native_socket) { }
   1591 
   1592       basic_stream_socket(const basic_stream_socket&) = delete;
   1593 
   1594       basic_stream_socket(basic_stream_socket&& __rhs) = default;
   1595 
   1596       template<typename _OtherProtocol, typename _Requires
   1597 	       = _Require<is_convertible<_OtherProtocol, _Protocol>>>
   1598 	basic_stream_socket(basic_stream_socket<_OtherProtocol>&& __rhs)
   1599 	: __base(std::move(__rhs)) { }
   1600 
   1601       ~basic_stream_socket() = default;
   1602 
   1603       basic_stream_socket& operator=(const basic_stream_socket&) = delete;
   1604 
   1605       basic_stream_socket& operator=(basic_stream_socket&& __rhs) = default;
   1606 
   1607       template<class _OtherProtocol>
   1608 	enable_if_t<is_convertible<_OtherProtocol, _Protocol>::value,
   1609 		    basic_stream_socket&>
   1610 	operator=(basic_stream_socket<_OtherProtocol>&& __rhs)
   1611 	{
   1612 	  __base::operator=(std::move(__rhs));
   1613 	  return *this;
   1614 	}
   1615 
   1616       // basic_stream_socket operations:
   1617 
   1618       template<class _MutableBufferSequence>
   1619 	size_t
   1620 	receive(const _MutableBufferSequence& __buffers)
   1621 	{
   1622 	  return receive(__buffers, socket_base::message_flags(),
   1623 			 __throw_on_error{"basic_stream_socket::receive"});
   1624 	}
   1625 
   1626       template<class _MutableBufferSequence>
   1627 	size_t
   1628 	receive(const _MutableBufferSequence& __buffers, error_code& __ec)
   1629         { return receive(__buffers, socket_base::message_flags(), __ec); }
   1630 
   1631       template<class _MutableBufferSequence>
   1632 	size_t
   1633 	receive(const _MutableBufferSequence& __buffers,
   1634 		socket_base::message_flags __flags)
   1635 	{
   1636 	  return receive(__buffers, __flags,
   1637 			 __throw_on_error{"basic_stream_socket::receive"});
   1638 	}
   1639 
   1640       template<class _MutableBufferSequence>
   1641 	size_t
   1642 	receive(const _MutableBufferSequence& __buffers,
   1643 		socket_base::message_flags __flags, error_code& __ec)
   1644 	{
   1645 	  if (__buffer_empty(__buffers))
   1646 	    {
   1647 	      __ec.clear();
   1648 	      return 0;
   1649 	    }
   1650 #ifdef _GLIBCXX_HAVE_SYS_SOCKET_H
   1651 	  socket_base::__msg_hdr __msg(__buffers);
   1652 	  ssize_t __result = ::recvmsg(this->native_handle(), &__msg,
   1653 				       static_cast<int>(__flags));
   1654 	  if (__result >= 0)
   1655 	    {
   1656 	      __ec.clear();
   1657 	      return __result;
   1658 	    }
   1659 	  __ec.assign(errno, generic_category());
   1660 #else
   1661 	  __ec = std::make_error_code(errc::operation_not_supported);
   1662 #endif
   1663 	  return 0;
   1664 	}
   1665 
   1666       template<class _MutableBufferSequence, class _CompletionToken>
   1667 	__deduced_t<_CompletionToken, void(error_code, size_t)>
   1668 	async_receive(const _MutableBufferSequence& __buffers,
   1669 		      _CompletionToken&& __token)
   1670 	{
   1671 	  return async_receive(__buffers, socket_base::message_flags(),
   1672 			       std::forward<_CompletionToken>(__token));
   1673 	}
   1674 
   1675       template<class _MutableBufferSequence, class _CompletionToken>
   1676 	__deduced_t<_CompletionToken, void(error_code, size_t)>
   1677 	async_receive(const _MutableBufferSequence& __buffers,
   1678 		      socket_base::message_flags __flags,
   1679 		      _CompletionToken&& __token)
   1680 	{
   1681 	  async_completion<_CompletionToken, void(error_code, size_t)>
   1682             __init{__token};
   1683 
   1684           if (__buffer_empty(__buffers))
   1685 	    {
   1686               auto __ex = net::get_associated_executor(
   1687                   __init.completion_handler, this->get_executor());
   1688               auto __a = get_associated_allocator(
   1689                   __init.completion_handler, std::allocator<void>());
   1690               __ex.post(
   1691                   [__h=std::move(__init.completion_handler)] () mutable
   1692                   { __h(error_code{}, 0); }, __a);
   1693               return __init.result.get();
   1694 	    }
   1695 
   1696           this->get_executor().context().async_wait(this->native_handle(),
   1697 	      (int) socket_base::wait_read,
   1698 	      [__h = std::move(__init.completion_handler),
   1699                &__buffers, __flags = static_cast<int>(__flags),
   1700                __fd = this->native_handle()]
   1701               (error_code __ec) mutable {
   1702                   if (__ec)
   1703                     {
   1704                       __h(__ec);
   1705                       return;
   1706                     }
   1707 #ifdef _GLIBCXX_HAVE_SYS_SOCKET_H
   1708                   socket_base::__msg_hdr __msg(__buffers);
   1709                   ssize_t __result = ::recvmsg(__fd, &__msg, __flags);
   1710                   if (__result == -1)
   1711                     {
   1712                       __ec.assign(errno, generic_category());
   1713                       __result = 0;
   1714                     }
   1715                   else
   1716                     __ec.clear();
   1717 		  __h(__ec, __result);
   1718 #else
   1719 		  __h(std::make_error_code(errc::operation_not_supported), 0);
   1720 #endif
   1721 	      });
   1722 	  return __init.result.get();
   1723 	}
   1724 
   1725       template<class _ConstBufferSequence>
   1726 	size_t
   1727 	send(const _ConstBufferSequence& __buffers)
   1728 	{
   1729 	  return send(__buffers, socket_base::message_flags(),
   1730 		      __throw_on_error{"basic_stream_socket::send"});
   1731 	}
   1732 
   1733       template<class _ConstBufferSequence>
   1734 	size_t
   1735 	send(const _ConstBufferSequence& __buffers, error_code& __ec)
   1736 	{ return send(__buffers, socket_base::message_flags(), __ec); }
   1737 
   1738       template<class _ConstBufferSequence>
   1739 	size_t
   1740 	send(const _ConstBufferSequence& __buffers,
   1741 	     socket_base::message_flags __flags)
   1742 	{
   1743 	  return send(__buffers, socket_base::message_flags(),
   1744 		      __throw_on_error{"basic_stream_socket::send"});
   1745 	}
   1746 
   1747       template<class _ConstBufferSequence>
   1748 	size_t
   1749 	send(const _ConstBufferSequence& __buffers,
   1750 	     socket_base::message_flags __flags, error_code& __ec)
   1751 	{
   1752 	  if (__buffer_empty(__buffers))
   1753 	    {
   1754 	      __ec.clear();
   1755 	      return 0;
   1756 	    }
   1757 #ifdef _GLIBCXX_HAVE_SYS_SOCKET_H
   1758 	  socket_base::__msg_hdr __msg(__buffers);
   1759 	  ssize_t __result = ::sendmsg(this->native_handle(), &__msg,
   1760 				       static_cast<int>(__flags));
   1761 	  if (__result >= 0)
   1762 	    {
   1763 	      __ec.clear();
   1764 	      return __result;
   1765 	    }
   1766 	  __ec.assign(errno, generic_category());
   1767 #else
   1768 	  __ec = std::make_error_code(errc::operation_not_supported);
   1769 #endif
   1770 	  return 0;
   1771 	}
   1772 
   1773       template<class _ConstBufferSequence, class _CompletionToken>
   1774 	__deduced_t<_CompletionToken, void(error_code, size_t)>
   1775 	async_send(const _ConstBufferSequence& __buffers,
   1776 		   _CompletionToken&& __token)
   1777 	{
   1778 	  return async_send(__buffers, socket_base::message_flags(),
   1779 			    std::forward<_CompletionToken>(__token));
   1780 	}
   1781 
   1782       template<class _ConstBufferSequence, class _CompletionToken>
   1783 	__deduced_t<_CompletionToken, void(error_code, size_t)>
   1784 	async_send(const _ConstBufferSequence& __buffers,
   1785 		   socket_base::message_flags __flags,
   1786 		   _CompletionToken&& __token)
   1787 	{
   1788 	  async_completion<_CompletionToken, void(error_code, size_t)>
   1789             __init{__token};
   1790 
   1791           if (__buffer_empty(__buffers))
   1792 	    {
   1793               auto __ex = net::get_associated_executor(
   1794                   __init.completion_handler, this->get_executor());
   1795               auto __a = get_associated_allocator(
   1796                   __init.completion_handler, std::allocator<void>());
   1797               __ex.post(
   1798                   [__h=std::move(__init.completion_handler)] () mutable
   1799                   { __h(error_code{}, 0); }, __a);
   1800               return __init.result.get();
   1801 	    }
   1802 
   1803           this->get_executor().context().async_wait(this->native_handle(),
   1804 	      (int) socket_base::wait_write,
   1805 	      [__h = std::move(__init.completion_handler),
   1806                &__buffers, __flags = static_cast<int>(__flags),
   1807                __fd = this->native_handle()]
   1808               (error_code __ec) mutable {
   1809                   if (__ec)
   1810                     {
   1811                       __h(__ec);
   1812                       return;
   1813                     }
   1814 #ifdef _GLIBCXX_HAVE_SYS_SOCKET_H
   1815                   socket_base::__msg_hdr __msg(__buffers);
   1816                   ssize_t __result = ::sendmsg(__fd, &__msg, __flags);
   1817                   if (__result == -1)
   1818                     {
   1819                       __ec.assign(errno, generic_category());
   1820                       __result = 0;
   1821                     }
   1822                   else
   1823                     __ec.clear();
   1824 		  __h(__ec, __result);
   1825 #else
   1826 		  __h(std::make_error_code(errc::operation_not_supported), 0);
   1827 #endif
   1828 	      });
   1829 	  return __init.result.get();
   1830 	}
   1831 
   1832       template<class _MutableBufferSequence>
   1833 	size_t
   1834 	read_some(const _MutableBufferSequence& __buffers)
   1835 	{
   1836 	  return receive(__buffers,
   1837 			 __throw_on_error{"basic_stream_socket::read_some"});
   1838 	}
   1839 
   1840       template<class _MutableBufferSequence>
   1841 	size_t
   1842 	read_some(const _MutableBufferSequence& __buffers, error_code& __ec)
   1843 	{ return receive(__buffers, __ec); }
   1844 
   1845       template<class _MutableBufferSequence, class _CompletionToken>
   1846 	__deduced_t<_CompletionToken, void(error_code, size_t)>
   1847 	async_read_some(const _MutableBufferSequence& __buffers,
   1848 			_CompletionToken&& __token)
   1849 	{
   1850 	  return async_receive(__buffers,
   1851 			       std::forward<_CompletionToken>(__token));
   1852 	}
   1853 
   1854       template<class _ConstBufferSequence>
   1855 	size_t
   1856 	write_some(const _ConstBufferSequence& __buffers)
   1857 	{
   1858 	  return send(__buffers,
   1859 		      __throw_on_error{"basic_stream_socket:write_some"});
   1860 	}
   1861 
   1862       template<class _ConstBufferSequence>
   1863 	size_t
   1864 	write_some(const _ConstBufferSequence& __buffers, error_code& __ec)
   1865 	{  return send(__buffers, __ec); }
   1866 
   1867       template<class _ConstBufferSequence, class _CompletionToken>
   1868 	__deduced_t<_CompletionToken, void(error_code, size_t)>
   1869 	async_write_some(const _ConstBufferSequence& __buffers,
   1870 			      _CompletionToken&& __token)
   1871 	{
   1872 	  return async_send(__buffers,
   1873 			    std::forward<_CompletionToken>(__token));
   1874 	}
   1875     };
   1876 
   1877   template<typename _AcceptableProtocol>
   1878     class basic_socket_acceptor
   1879     : public socket_base, private __basic_socket_impl<_AcceptableProtocol>
   1880     {
   1881       using __base = __basic_socket_impl<_AcceptableProtocol>;
   1882 
   1883     public:
   1884       // types:
   1885 
   1886       using executor_type = io_context::executor_type;
   1887       using native_handle_type = int;
   1888       using protocol_type = _AcceptableProtocol;
   1889       using endpoint_type = typename protocol_type::endpoint;
   1890       using socket_type = typename protocol_type::socket;
   1891 
   1892       static_assert(__detail::__acceptable_protocol<protocol_type>,
   1893 		    "protocol_type meets the AcceptableProtocol requirements");
   1894 
   1895       // construct / copy / destroy:
   1896 
   1897       explicit
   1898       basic_socket_acceptor(io_context& __ctx)
   1899       : __base(__ctx), _M_protocol(endpoint_type{}.protocol()) { }
   1900 
   1901       basic_socket_acceptor(io_context& __ctx,
   1902 			    const protocol_type& __protocol)
   1903       : __base(__ctx), _M_protocol(__protocol)
   1904       { open(__protocol); }
   1905 
   1906       basic_socket_acceptor(io_context& __ctx, const endpoint_type& __endpoint,
   1907 			    [[__maybe_unused__]] bool __reuse_addr = true)
   1908       : basic_socket_acceptor(__ctx, __endpoint.protocol())
   1909       {
   1910 #ifdef _GLIBCXX_HAVE_SYS_SOCKET_H
   1911 	if (__reuse_addr)
   1912 	  set_option(reuse_address(true));
   1913 #endif
   1914 	bind(__endpoint);
   1915 	listen();
   1916       }
   1917 
   1918       basic_socket_acceptor(io_context& __ctx, const protocol_type& __protocol,
   1919 			    const native_handle_type& __native_acceptor)
   1920       : basic_socket_acceptor(__ctx, __protocol)
   1921       { assign(__protocol, __native_acceptor); }
   1922 
   1923       basic_socket_acceptor(const basic_socket_acceptor&) = delete;
   1924 
   1925       basic_socket_acceptor(basic_socket_acceptor&&) = default;
   1926 
   1927       template<typename _OtherProtocol, typename _Requires
   1928 	       = _Require<is_convertible<_OtherProtocol, protocol_type>>>
   1929 	basic_socket_acceptor(basic_socket_acceptor<_OtherProtocol>&& __rhs)
   1930 	: __base(std::move(__rhs)) { }
   1931 
   1932       ~basic_socket_acceptor() = default;
   1933 
   1934       basic_socket_acceptor& operator=(const basic_socket_acceptor&) = delete;
   1935 
   1936       basic_socket_acceptor& operator=(basic_socket_acceptor&&) = default;
   1937 
   1938       template<class _OtherProtocol>
   1939 	enable_if_t<is_convertible<_OtherProtocol, protocol_type>::value,
   1940 		    basic_socket_acceptor&>
   1941 	operator=(basic_socket_acceptor<_OtherProtocol>&& __rhs)
   1942 	{
   1943 	  __base::operator=(std::move(__rhs));
   1944 	  return *this;
   1945 	}
   1946 
   1947       // basic_socket_acceptor operations:
   1948 
   1949       executor_type get_executor() noexcept { return __base::get_executor(); }
   1950 
   1951       native_handle_type
   1952       native_handle() noexcept { return __base::native_handle(); }
   1953 
   1954       void
   1955       open(const protocol_type& __protocol = protocol_type())
   1956       { open(__protocol, __throw_on_error{"basic_socket_acceptor::open"}); }
   1957 
   1958       void
   1959       open(const protocol_type& __protocol, error_code& __ec)
   1960       { __base::open(__protocol, __ec); }
   1961 
   1962       void
   1963       assign(const protocol_type& __protocol,
   1964 	     const native_handle_type& __native_acceptor)
   1965       {
   1966 	assign(__protocol, __native_acceptor,
   1967 	       __throw_on_error{"basic_socket_acceptor::assign"});
   1968       }
   1969 
   1970       void
   1971       assign(const protocol_type& __protocol,
   1972 	     const native_handle_type& __native_acceptor,
   1973 	     error_code& __ec)
   1974       { __base::assign(__protocol, __native_acceptor, __ec); }
   1975 
   1976       native_handle_type release()
   1977       { return release(__throw_on_error{"basic_socket_acceptor::release"}); }
   1978 
   1979       native_handle_type release(error_code& __ec)
   1980       { return __base::release(__ec); }
   1981 
   1982       _GLIBCXX_NODISCARD bool
   1983       is_open() const noexcept { return __base::is_open(); }
   1984 
   1985       void
   1986       close() { close(__throw_on_error{"basic_socket_acceptor::close"}); }
   1987 
   1988       void
   1989       close(error_code& __ec) { __base::_close(__ec); }
   1990 
   1991       void
   1992       cancel() { cancel(__throw_on_error{"basic_socket_acceptor::cancel"}); }
   1993 
   1994       void
   1995       cancel(error_code& __ec) { __base::cancel(__ec); }
   1996 
   1997       template<typename _SettableSocketOption>
   1998 	void
   1999 	set_option(const _SettableSocketOption& __option)
   2000 	{
   2001 	  set_option(__option,
   2002 		     __throw_on_error{"basic_socket_acceptor::set_option"});
   2003 	}
   2004 
   2005       template<typename _SettableSocketOption>
   2006 	void
   2007 	set_option(const _SettableSocketOption& __option, error_code& __ec)
   2008 	{ __base::set_option(__option, __ec); }
   2009 
   2010       template<typename _GettableSocketOption>
   2011 	void
   2012 	get_option(_GettableSocketOption& __option) const
   2013 	{
   2014 	  get_option(__option,
   2015 		     __throw_on_error{"basic_socket_acceptor::get_option"});
   2016 	}
   2017 
   2018       template<typename _GettableSocketOption>
   2019 	void
   2020 	get_option(_GettableSocketOption& __option, error_code& __ec) const
   2021 	{ __base::get_option(__option, __ec); }
   2022 
   2023       template<typename _IoControlCommand>
   2024 	void
   2025 	io_control(_IoControlCommand& __command)
   2026 	{
   2027 	  io_control(__command,
   2028 		     __throw_on_error{"basic_socket_acceptor::io_control"});
   2029 	}
   2030 
   2031       template<typename _IoControlCommand>
   2032 	void
   2033 	io_control(_IoControlCommand& __command, error_code& __ec)
   2034 	{ __base::io_control(__command, __ec); }
   2035 
   2036       void
   2037       non_blocking(bool __mode)
   2038       {
   2039 	non_blocking(__mode,
   2040 		     __throw_on_error{"basic_socket_acceptor::non_blocking"});
   2041       }
   2042 
   2043       void
   2044       non_blocking(bool __mode, error_code& __ec)
   2045       { __base::non_blocking(__mode, __ec); }
   2046 
   2047       bool non_blocking() const { return __base::non_blocking(); }
   2048 
   2049       void
   2050       native_non_blocking(bool __mode)
   2051       {
   2052 	native_non_blocking(__mode, __throw_on_error{
   2053 	    "basic_socket_acceptor::native_non_blocking"});
   2054       }
   2055 
   2056       void
   2057       native_non_blocking(bool __mode, error_code& __ec)
   2058       { __base::native_non_blocking(__mode, __ec); }
   2059 
   2060       bool
   2061       native_non_blocking() const
   2062       { return __base::native_non_blocking(); }
   2063 
   2064       void
   2065       bind(const endpoint_type& __endpoint)
   2066       {
   2067 	return bind(__endpoint,
   2068 		    __throw_on_error{"basic_socket_acceptor::bind"});
   2069       }
   2070 
   2071       void
   2072       bind(const endpoint_type& __endpoint, error_code& __ec)
   2073       { __base::bind(__endpoint, __ec); }
   2074 
   2075       void
   2076       listen(int __backlog = max_listen_connections)
   2077       {
   2078 	return listen(__backlog,
   2079 		      __throw_on_error{"basic_socket_acceptor::listen"});
   2080       }
   2081 
   2082       void
   2083       listen(int __backlog, error_code& __ec)
   2084       {
   2085 #ifdef _GLIBCXX_HAVE_SYS_SOCKET_H
   2086 	if (::listen(native_handle(), __backlog) == -1)
   2087 	  __ec.assign(errno, generic_category());
   2088 	else
   2089 	  __ec.clear();
   2090 #else
   2091 	__ec = std::make_error_code(errc::operation_not_supported);
   2092 #endif
   2093       }
   2094 
   2095       endpoint_type
   2096       local_endpoint() const
   2097       {
   2098 	return local_endpoint(
   2099 	    __throw_on_error{"basic_socket_acceptor::local_endpoint"});
   2100       }
   2101 
   2102       endpoint_type
   2103       local_endpoint(error_code& __ec) const
   2104       { return __base::local_endpoint(__ec); }
   2105 
   2106       void
   2107       enable_connection_aborted(bool __mode)
   2108       { __base::_M_bits.enable_connection_aborted = __mode; }
   2109 
   2110       bool
   2111       enable_connection_aborted() const
   2112       { return __base::_M_bits.enable_connection_aborted; }
   2113 
   2114       socket_type
   2115       accept()
   2116       { return accept(__throw_on_error{"basic_socket_acceptor::accept"}); }
   2117 
   2118       socket_type
   2119       accept(error_code& __ec)
   2120       { return accept(get_executor().context(), __ec); }
   2121 
   2122       socket_type accept(io_context& __ctx)
   2123       {
   2124 	return accept(__ctx,
   2125 		      __throw_on_error{"basic_socket_acceptor::accept"});
   2126       }
   2127 
   2128       socket_type
   2129       accept(io_context& __ctx, error_code& __ec)
   2130       {
   2131 #ifdef _GLIBCXX_HAVE_SYS_SOCKET_H
   2132 	do
   2133 	  {
   2134 	    int __h = ::accept(native_handle(), nullptr, 0);
   2135 	    if (__h != -1)
   2136 	      {
   2137 		__ec.clear();
   2138 		return socket_type{__ctx, _M_protocol, __h};
   2139 	      }
   2140 	  } while (errno == ECONNABORTED && enable_connection_aborted());
   2141 	__ec.assign(errno, generic_category());
   2142 #else
   2143 	__ec = std::make_error_code(errc::operation_not_supported);
   2144 #endif
   2145 	return socket_type{__ctx};
   2146       }
   2147 
   2148       template<class _CompletionToken>
   2149 	__deduced_t<_CompletionToken, void(error_code, socket_type)>
   2150 	async_accept(_CompletionToken&& __token)
   2151 	{
   2152 	  return async_accept(get_executor().context(),
   2153 			      std::forward<_CompletionToken>(__token));
   2154 	}
   2155 
   2156       template<class _CompletionToken>
   2157 	__deduced_t<_CompletionToken, void(error_code, socket_type)>
   2158 	async_accept(io_context& __ctx, _CompletionToken&& __token)
   2159 	{
   2160           async_completion<_CompletionToken, void(error_code, socket_type)>
   2161             __init{__token};
   2162 
   2163 	  __ctx.async_wait(native_handle(),
   2164 	      (int) socket_base::wait_read,
   2165 	      [__h = std::move(__init.completion_handler),
   2166                __connabort = enable_connection_aborted(),
   2167                __fd = native_handle(),
   2168                __protocol = _M_protocol,
   2169                &__ctx
   2170               ]
   2171               (error_code __ec) mutable {
   2172                   if (__ec)
   2173                     {
   2174                       __h(__ec, socket_type(__ctx));
   2175                       return;
   2176                     }
   2177 #ifdef _GLIBCXX_HAVE_SYS_SOCKET_H
   2178                   do
   2179                     {
   2180                       int __newfd = ::accept(__fd, nullptr, 0);
   2181                       if (__newfd != -1)
   2182                         {
   2183                           __ec.clear();
   2184                           __h(__ec, socket_type{__ctx, __protocol, __newfd});
   2185                           return;
   2186                         }
   2187                     } while (errno == ECONNABORTED && __connabort);
   2188                   __ec.assign(errno, generic_category());
   2189                   __h(__ec, socket_type(__ctx));
   2190 #else
   2191 		  __h(std::make_error_code(errc::operation_not_supported), 0);
   2192 #endif
   2193 	      });
   2194 	  return __init.result.get();
   2195 	}
   2196 
   2197       socket_type
   2198       accept(endpoint_type& __endpoint)
   2199       {
   2200 	return accept(get_executor().context(), __endpoint,
   2201 		      __throw_on_error{"basic_socket_acceptor::accept"});
   2202       }
   2203 
   2204       socket_type
   2205       accept(endpoint_type& __endpoint, error_code& __ec)
   2206       { return accept(get_executor().context(), __endpoint, __ec); }
   2207 
   2208       socket_type
   2209       accept(io_context& __ctx, endpoint_type& __endpoint)
   2210       {
   2211 	return accept(__ctx, __endpoint,
   2212 		      __throw_on_error{"basic_socket_acceptor::accept"});
   2213       }
   2214 
   2215       socket_type
   2216       accept(io_context& __ctx, endpoint_type& __endpoint, error_code& __ec)
   2217       {
   2218 #ifdef _GLIBCXX_HAVE_SYS_SOCKET_H
   2219 	do
   2220 	  {
   2221 	    socklen_t __len = __endpoint.capacity();
   2222 	    int __h = ::accept(native_handle(), (sockaddr*)__endpoint.data(),
   2223 			       &__len);
   2224 	    if (__h != -1)
   2225 	      {
   2226 		__endpoint.resize(__len);
   2227 		return socket_type{__ctx, _M_protocol, __h};
   2228 	      }
   2229 	  } while (errno == ECONNABORTED && enable_connection_aborted());
   2230 	__ec.assign(errno, generic_category());
   2231 #else
   2232 	__ec = std::make_error_code(errc::operation_not_supported);
   2233 #endif
   2234 	return socket_type{__ctx};
   2235       }
   2236 
   2237       template<class _CompletionToken>
   2238 	__deduced_t<_CompletionToken, void(error_code, socket_type)>
   2239 	async_accept(endpoint_type& __endpoint,
   2240 			     _CompletionToken&& __token)
   2241 	{
   2242 	  return async_accept(get_executor().context(), __endpoint,
   2243 			      std::forward<_CompletionToken>(__token));
   2244 	}
   2245 
   2246       template<class _CompletionToken>
   2247 	__deduced_t<_CompletionToken, void(error_code, socket_type)>
   2248 	async_accept(io_context& __ctx, endpoint_type& __endpoint,
   2249 			     _CompletionToken&& __token)
   2250         {
   2251           async_completion<_CompletionToken, void(error_code, socket_type)>
   2252             __init{__token};
   2253 
   2254 	  __ctx.async_wait(native_handle(),
   2255 	      (int) socket_base::wait_read,
   2256 	      [__h = std::move(__init.completion_handler),
   2257               __ep = std::move(__endpoint),
   2258                __connabort = enable_connection_aborted(),
   2259                __fd = native_handle(),
   2260                &__ctx
   2261               ]
   2262               (error_code __ec) mutable {
   2263                   if (__ec)
   2264                     {
   2265                       __h(__ec, socket_type(__ctx));
   2266                       return;
   2267                     }
   2268 #ifdef _GLIBCXX_HAVE_SYS_SOCKET_H
   2269                   do
   2270                     {
   2271                       socklen_t __len = __ep.capacity();
   2272                       int __newfd = ::accept(__fd, __ep.data, &__len);
   2273                       if (__newfd != -1)
   2274                         {
   2275                           __ep.resize(__len);
   2276                           auto __protocol = __ep.protocol();
   2277                           __ec.clear();
   2278                           __h(__ec, socket_type{__ctx, __protocol, __newfd});
   2279                           return;
   2280                         }
   2281                     } while (errno == ECONNABORTED && __connabort);
   2282                   __ec.assign(errno, generic_category());
   2283 #else
   2284 		  __ec = std::make_error_code(errc::operation_not_supported);
   2285 #endif
   2286                   __h(__ec, socket_type(__ctx));
   2287 	      });
   2288 	  return __init.result.get();
   2289         }
   2290 
   2291       void
   2292       wait(wait_type __w)
   2293       { wait(__w, __throw_on_error{"basic_socket_acceptor::wait"}); }
   2294 
   2295       void
   2296       wait(wait_type __w, error_code& __ec)
   2297       {
   2298 #ifdef _GLIBCXX_HAVE_POLL_H
   2299 	::pollfd __fds;
   2300 	__fds.fd = native_handle();
   2301 	__fds.events = __w; // __w | POLLIN;
   2302 	if (::poll(&__fds, 1, -1) == -1)
   2303 	  __ec.assign(errno, generic_category());
   2304 	else
   2305 	  __ec.clear();
   2306 #else
   2307 	__ec = std::make_error_code(errc::operation_not_supported);
   2308 #endif
   2309       }
   2310 
   2311       template<class _CompletionToken>
   2312 	__deduced_t<_CompletionToken, void(error_code)>
   2313 	async_wait(wait_type __w, _CompletionToken&& __token)
   2314         {
   2315 	  async_completion<_CompletionToken, void(error_code)> __init{__token};
   2316 	  get_executor().context().async_wait( native_handle(),
   2317 	      static_cast<int>(__w),
   2318 	      [__h = std::move(__init.completion_handler)]
   2319               (error_code __ec) mutable {
   2320 		  __h(__ec);
   2321 	      });
   2322 	  return __init.result.get();
   2323 	}
   2324 
   2325     private:
   2326       protocol_type _M_protocol;
   2327     };
   2328 
   2329   /// @}
   2330 
   2331   /** @brief Socket streams
   2332    * @{
   2333    */
   2334 
   2335   template<typename _Protocol, typename _Clock, typename _WaitTraits>
   2336     class basic_socket_streambuf : public basic_streambuf<char>
   2337     {
   2338     public:
   2339       // types:
   2340 
   2341       using protocol_type = _Protocol;
   2342       using endpoint_type = typename protocol_type::endpoint;
   2343       using clock_type = _Clock;
   2344       using time_point = typename clock_type::time_point;
   2345       using duration = typename clock_type::duration;
   2346       using wait_traits_type = _WaitTraits;
   2347 
   2348       // construct / copy / destroy:
   2349 
   2350       basic_socket_streambuf() : _M_socket(_S_ctx()) { }
   2351 
   2352       explicit
   2353       basic_socket_streambuf(basic_stream_socket<protocol_type> __s)
   2354       : _M_socket(std::move(__s)) { }
   2355 
   2356       basic_socket_streambuf(const basic_socket_streambuf&) = delete;
   2357 
   2358       basic_socket_streambuf(basic_socket_streambuf&& __rhs); // TODO
   2359 
   2360 
   2361       virtual ~basic_socket_streambuf(); // TODO
   2362 
   2363       basic_socket_streambuf& operator=(const basic_socket_streambuf&) = delete;
   2364 
   2365       basic_socket_streambuf& operator=(basic_socket_streambuf&& __rhs); // TODO
   2366 
   2367       // members:
   2368 
   2369       basic_socket_streambuf* connect(const endpoint_type& __e); // TODO
   2370 
   2371       template<typename... _Args>
   2372 	basic_socket_streambuf* connect(_Args&&... ); // TODO
   2373 
   2374       basic_socket_streambuf* close(); // TODO
   2375 
   2376       basic_socket<protocol_type>& socket() { return _M_socket; }
   2377 
   2378       error_code error() const noexcept { return _M_ec; }
   2379 
   2380       time_point expiry() const { return _M_expiry; }
   2381 
   2382       void
   2383       expires_at(const time_point& __t)
   2384       { _M_expiry = __t; }
   2385 
   2386       void
   2387       expires_after(const duration& __d)
   2388       { expires_at(clock_type::now() + __d); }
   2389 
   2390     protected:
   2391       // overridden virtual functions: // TODO
   2392       virtual int_type underflow() override;
   2393       virtual int_type pbackfail(int_type __c = traits_type::eof()) override;
   2394       virtual int_type overflow(int_type __c = traits_type::eof()) override;
   2395       virtual int sync() override;
   2396       virtual streambuf* setbuf(char_type* __s, streamsize __n) override;
   2397 
   2398     private:
   2399       static io_context&
   2400       _S_ctx()
   2401       {
   2402 	static io_context __ctx;
   2403 	return __ctx;
   2404       }
   2405 
   2406       basic_stream_socket<protocol_type> _M_socket;
   2407       error_code _M_ec;
   2408       time_point _M_expiry{ time_point::max() };
   2409     };
   2410 
   2411   template<typename _Protocol, class _Clock, typename _WaitTraits>
   2412     class basic_socket_iostream : public basic_iostream<char>
   2413     {
   2414       using __streambuf_type
   2415 	= basic_socket_streambuf<_Protocol, _Clock, _WaitTraits>;
   2416 
   2417     public:
   2418       // types:
   2419 
   2420       using protocol_type = _Protocol;
   2421       using endpoint_type = typename protocol_type::endpoint;
   2422       using clock_type = _Clock;
   2423       using time_point = typename clock_type::time_point;
   2424       using duration = typename clock_type::duration;
   2425       using wait_traits_type = _WaitTraits;
   2426 
   2427       // construct / copy / destroy:
   2428 
   2429       // TODO base-from-member ?
   2430       basic_socket_iostream() : basic_iostream(nullptr), _M_sb()
   2431       {
   2432 	this->init(std::addressof(_M_sb));
   2433 	this->setf(std::ios::unitbuf);
   2434       }
   2435 
   2436       explicit
   2437       basic_socket_iostream(basic_stream_socket<protocol_type> __s)
   2438       : basic_iostream(nullptr), _M_sb(std::move(__s))
   2439       {
   2440 	this->init(std::addressof(_M_sb));
   2441 	this->setf(std::ios::unitbuf);
   2442       }
   2443 
   2444       basic_socket_iostream(const basic_socket_iostream&) = delete;
   2445 
   2446       basic_socket_iostream(basic_socket_iostream&& __rhs)
   2447       : basic_iostream(nullptr), _M_sb(std::move(__rhs._M_sb))
   2448 	// XXX ???     ^^^^^^^
   2449       {
   2450 	// XXX ??? this->init(std::addressof(_M_sb));
   2451 	this->set_rbduf(std::addressof(_M_sb));
   2452       }
   2453 
   2454       template<typename... _Args>
   2455 	explicit
   2456 	basic_socket_iostream(_Args&&... __args)
   2457 	: basic_iostream(nullptr), _M_sb()
   2458 	{
   2459 	  this->init(std::addressof(_M_sb));
   2460 	  this->setf(std::ios::unitbuf);
   2461 	  connect(forward<_Args>(__args)...);
   2462 	}
   2463 
   2464       basic_socket_iostream& operator=(const basic_socket_iostream&) = delete;
   2465 
   2466       basic_socket_iostream& operator=(basic_socket_iostream&& __rhs); // TODO
   2467 
   2468       // members:
   2469 
   2470       template<typename... _Args>
   2471 	void
   2472 	connect(_Args&&... __args)
   2473 	{
   2474 	  if (rdbuf()->connect(forward<_Args>(__args)...) == nullptr)
   2475 	    this->setstate(failbit);
   2476 	}
   2477 
   2478       void
   2479       close()
   2480       {
   2481 	if (rdbuf()->close() == nullptr)
   2482 	  this->setstate(failbit);
   2483       }
   2484 
   2485       basic_socket_streambuf<protocol_type, clock_type, wait_traits_type>*
   2486       rdbuf() const
   2487       { return const_cast<__streambuf_type*>(std::addressof(_M_sb)); }
   2488 
   2489       basic_socket<protocol_type>& socket() { return rdbuf()->socket(); }
   2490       error_code error() const noexcept { return rdbuf()->error(); }
   2491 
   2492       time_point expiry() const { return rdbuf()->expiry(); }
   2493       void expires_at(const time_point& __t) { rdbuf()->expires_at(__t); }
   2494       void expires_after(const duration& __d) { rdbuf()->expires_after(__d); }
   2495 
   2496     private:
   2497       __streambuf_type _M_sb;
   2498     };
   2499 
   2500   /// @}
   2501 
   2502   /** @brief synchronous connect operations
   2503    * @{
   2504    */
   2505 
   2506   template<typename _Protocol, typename _EndpointSequence,
   2507 	   typename _ConnectCondition>
   2508     inline typename _Protocol::endpoint
   2509     connect(basic_socket<_Protocol>& __s,
   2510 	    const _EndpointSequence& __endpoints,
   2511 	    _ConnectCondition __c, error_code& __ec)
   2512     {
   2513       __ec.clear();
   2514       bool __found = false;
   2515       for (auto& __ep : __endpoints)
   2516 	{
   2517 	  if (__c(__ec, __ep))
   2518 	    {
   2519 	      __found = true;
   2520 	      __s.close(__ec);
   2521 	      if (!__ec)
   2522 		__s.open(__ep.protocol(), __ec);
   2523 	      if (!__ec)
   2524 		__s.connect(__ep, __ec);
   2525 	      if (!__ec)
   2526 		return __ep;
   2527 	    }
   2528 	}
   2529       if (!__found)
   2530 	__ec = socket_errc::not_found;
   2531       return typename _Protocol::endpoint{};
   2532     }
   2533 
   2534   template<typename _Protocol, typename _InputIterator,
   2535 	   typename _ConnectCondition>
   2536     inline _InputIterator
   2537     connect(basic_socket<_Protocol>& __s,
   2538 	    _InputIterator __first, _InputIterator __last,
   2539 	    _ConnectCondition __c, error_code& __ec)
   2540     {
   2541       __ec.clear();
   2542       bool __found = false;
   2543       for (auto __i = __first; __i != __last; ++__i)
   2544 	{
   2545 	  if (__c(__ec, *__i))
   2546 	    {
   2547 	      __found = true;
   2548 	      __s.close(__ec);
   2549 	      if (!__ec)
   2550 		__s.open(typename _Protocol::endpoint(*__i).protocol(), __ec);
   2551 	      if (!__ec)
   2552 		__s.connect(*__i, __ec);
   2553 	      if (!__ec)
   2554 		return __i;
   2555 	    }
   2556 	}
   2557       if (!__found)
   2558 	__ec = socket_errc::not_found;
   2559       return __last;
   2560     }
   2561 
   2562   template<typename _Protocol, typename _EndpointSequence,
   2563 	   typename _ConnectCondition>
   2564     inline typename _Protocol::endpoint
   2565     connect(basic_socket<_Protocol>& __s,
   2566 	    const _EndpointSequence& __endpoints,
   2567 	    _ConnectCondition __c)
   2568     {
   2569       return net::connect(__s, __endpoints, __c, __throw_on_error{"connect"});
   2570     }
   2571 
   2572   template<typename _Protocol, typename _InputIterator,
   2573 	   typename _ConnectCondition>
   2574     inline _InputIterator
   2575     connect(basic_socket<_Protocol>& __s,
   2576 	    _InputIterator __first, _InputIterator __last,
   2577 	    _ConnectCondition __c)
   2578     {
   2579       return net::connect(__s, __first, __last, __c,
   2580 			  __throw_on_error{"connect"});
   2581     }
   2582 
   2583   template<typename _Protocol, typename _EndpointSequence>
   2584     inline typename _Protocol::endpoint
   2585     connect(basic_socket<_Protocol>& __s,
   2586 	    const _EndpointSequence& __endpoints)
   2587     {
   2588       return net::connect(__s, __endpoints, [](auto, auto){ return true; },
   2589 			  __throw_on_error{"connect"});
   2590     }
   2591 
   2592   template<typename _Protocol, typename _EndpointSequence>
   2593     inline typename _Protocol::endpoint
   2594     connect(basic_socket<_Protocol>& __s,
   2595 	    const _EndpointSequence& __endpoints,
   2596 	    error_code& __ec)
   2597     {
   2598       return net::connect(__s, __endpoints, [](auto, auto){ return true; },
   2599 			  __ec);
   2600     }
   2601 
   2602   template<typename _Protocol, typename _InputIterator>
   2603     inline _InputIterator
   2604     connect(basic_socket<_Protocol>& __s,
   2605 	    _InputIterator __first, _InputIterator __last)
   2606     {
   2607       return net::connect(__s, __first, __last, [](auto, auto){ return true; },
   2608 			  __throw_on_error{"connect"});
   2609     }
   2610 
   2611   template<typename _Protocol, typename _InputIterator>
   2612     inline _InputIterator
   2613     connect(basic_socket<_Protocol>& __s,
   2614 	    _InputIterator __first, _InputIterator __last,
   2615 	    error_code& __ec)
   2616     {
   2617       return net::connect(__s, __first, __last, [](auto, auto){ return true; },
   2618 			  __ec);
   2619     }
   2620 
   2621   /// @}
   2622 
   2623   /** @brief asynchronous connect operations
   2624    * @{
   2625    */
   2626 
   2627   template<typename _Protocol, typename _EndpointSequence,
   2628 	   typename _ConnectCondition, typename _CompletionToken>
   2629     inline
   2630     __deduced_t<_CompletionToken,
   2631 		void(error_code, typename _Protocol::endpoint)>
   2632     async_connect(basic_socket<_Protocol>& __s,
   2633 		  const _EndpointSequence& __endpoints,
   2634 		  _ConnectCondition __c, _CompletionToken&& __token); // TODO
   2635 
   2636   template<typename _Protocol, typename _EndpointSequence,
   2637 	   typename _CompletionToken>
   2638     inline
   2639     __deduced_t<_CompletionToken,
   2640 		void(error_code, typename _Protocol::endpoint)>
   2641     async_connect(basic_socket<_Protocol>& __s,
   2642 		  const _EndpointSequence& __endpoints,
   2643 		  _CompletionToken&& __token)
   2644     {
   2645       return net::async_connect(__s, __endpoints,
   2646 				[](auto, auto){ return true; },
   2647 				forward<_CompletionToken>(__token));
   2648     }
   2649 
   2650   template<typename _Protocol, typename _InputIterator,
   2651 	   typename _ConnectCondition, typename _CompletionToken>
   2652     inline
   2653     __deduced_t<_CompletionToken, void(error_code, _InputIterator)>
   2654     async_connect(basic_socket<_Protocol>& __s,
   2655 		  _InputIterator __first, _InputIterator __last,
   2656 		  _ConnectCondition __c, _CompletionToken&& __token); // TODO
   2657 
   2658   template<typename _Protocol, typename _InputIterator,
   2659 	   typename _CompletionToken>
   2660     inline
   2661     __deduced_t<_CompletionToken, void(error_code, _InputIterator)>
   2662     async_connect(basic_socket<_Protocol>& __s,
   2663 		  _InputIterator __first, _InputIterator __last,
   2664 		  _CompletionToken&& __token)
   2665     {
   2666       return net::async_connect(__s, __first, __last,
   2667 				[](auto, auto){ return true; },
   2668 				forward<_CompletionToken>(__token));
   2669     }
   2670 
   2671   /// @}
   2672 
   2673 #endif  // _GLIBCXX_HAVE_UNISTD_H
   2674 
   2675   /// @}
   2676 
   2677 } // namespace v1
   2678 } // namespace net
   2679 } // namespace experimental
   2680 
   2681 _GLIBCXX_END_NAMESPACE_VERSION
   2682 } // namespace std
   2683 
   2684 #endif // C++14
   2685 
   2686 #endif // _GLIBCXX_EXPERIMENTAL_SOCKET
   2687