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