1// Networking implementation details -*- C++ -*-
2
3// Copyright (C) 2015-2022 Free Software Foundation, Inc.
4//
5// This file is part of the GNU ISO C++ Library.  This library is free
6// software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 3, or (at your option)
9// any later version.
10
11// This library is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14// GNU General Public License for more details.
15
16// Under Section 7 of GPL version 3, you are granted additional
17// permissions described in the GCC Runtime Library Exception, version
18// 3.1, as published by the Free Software Foundation.
19
20// You should have received a copy of the GNU General Public License and
21// a copy of the GCC Runtime Library Exception along with this program;
22// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23// <http://www.gnu.org/licenses/>.
24
25/** @file experimental/bits/net.h
26 *  This is an internal header file, included by other library headers.
27 *  Do not attempt to use it directly. @headername{experimental/net}
28 */
29
30#ifndef _GLIBCXX_EXPERIMENTAL_NET_H
31#define _GLIBCXX_EXPERIMENTAL_NET_H 1
32
33#pragma GCC system_header
34
35#if __cplusplus >= 201402L
36
37#include <type_traits>
38#include <system_error>
39#include <experimental/netfwd>
40
41#if __cplusplus > 201703L
42# include <concepts>
43#endif
44
45namespace std _GLIBCXX_VISIBILITY(default)
46{
47_GLIBCXX_BEGIN_NAMESPACE_VERSION
48namespace experimental
49{
50namespace net
51{
52inline namespace v1
53{
54
55  /** @addtogroup networking-ts
56   *  @{
57   */
58
59  template<typename _CompletionToken, typename _Signature, typename>
60    class async_result;
61
62  /// @cond undocumented
63
64  // A type denoted by DEDUCED in the TS.
65  template<typename _CompletionToken, typename _Signature>
66    using __deduced_t = typename
67      async_result<decay_t<_CompletionToken>, _Signature, void>::return_type;
68
69  // Trait to check for construction from const/non-const lvalue/rvalue.
70  template<typename _Tp>
71    using __is_value_constructible = typename __and_<
72      is_copy_constructible<_Tp>, is_move_constructible<_Tp>,
73      is_constructible<_Tp, _Tp&>, is_constructible<_Tp, const _Tp&&>
74      >::type;
75
76  struct __throw_on_error
77  {
78    explicit
79    __throw_on_error(const char* __msg) : _M_msg(__msg) { }
80
81    ~__throw_on_error() noexcept(false)
82    {
83      if (_M_ec)
84	_GLIBCXX_THROW_OR_ABORT(system_error(_M_ec, _M_msg));
85    }
86
87    __throw_on_error(const __throw_on_error&) = delete;
88    __throw_on_error& operator=(const __throw_on_error&) = delete;
89
90    operator error_code&() noexcept { return _M_ec; }
91
92    const char* _M_msg;
93    error_code _M_ec;
94  };
95
96  /// @endcond
97
98  // Base class for types meeting both GettableSocketOption and
99  // SettableSocketOption requirements.
100  // The bool parameter allows __sockopt_base<bool> to have a
101  // __sockopt_base<int, B> base class (so that its _M_value is an int)
102  // but to have that be a distinct type from __sockopt_base<int>.
103  template<typename _Tp, bool = true>
104    struct __sockopt_base
105    {
106      __sockopt_base() = default;
107
108      explicit
109      __sockopt_base(_Tp __val) noexcept(noexcept(_Tp(std::declval<_Tp&>())))
110      : _M_value(__val)
111      { }
112
113      template<typename _Protocol>
114	void*
115	data(const _Protocol&) noexcept
116	{ return std::addressof(_M_value); }
117
118      template<typename _Protocol>
119	const void*
120	data(const _Protocol&) const noexcept
121	{ return std::addressof(_M_value); }
122
123      template<typename _Protocol>
124	size_t
125	size(const _Protocol&) const noexcept
126	{ return sizeof(_M_value); }
127
128      template<typename _Protocol>
129	void
130	resize(const _Protocol&, size_t __s)
131	{
132	  if (__s != sizeof(_M_value))
133	    __throw_length_error("invalid value for socket option resize");
134	}
135
136    protected:
137      _Tp _M_value { };
138    };
139
140  // Base class for types meeting BooleanSocketOption requirements.
141  template<>
142    struct __sockopt_base<bool> : __sockopt_base<int, false>
143    {
144      __sockopt_base() = default;
145
146      explicit
147      __sockopt_base(bool __val) noexcept
148      : __sockopt_base<int, false>(__val)
149      { }
150
151      bool value() const noexcept { return this->_M_value; }
152      explicit operator bool() const noexcept { return value(); }
153      bool operator!() const noexcept { return !value(); }
154    };
155
156  // Base class for types meeting IntegerSocketOption requirements.
157  template<>
158    struct __sockopt_base<int> : __sockopt_base<int, false>
159    {
160      using __sockopt_base<int, false>::__sockopt_base;
161
162      int value() const noexcept { return this->_M_value; }
163    };
164
165  template<typename _Derived, typename _Tp = int>
166    struct __sockopt_crtp : __sockopt_base<_Tp>
167    {
168      using __sockopt_base<_Tp>::__sockopt_base;
169
170      _Derived&
171      operator=(_Tp __value) noexcept(noexcept(__value = __value))
172      {
173	__sockopt_base<_Tp>::_M_value = __value;
174	return static_cast<_Derived&>(*this);
175      }
176
177      template<typename _Protocol>
178	int
179	level(const _Protocol&) const noexcept
180	{ return _Derived::_S_level; }
181
182      template<typename _Protocol>
183	int
184	name(const _Protocol&) const noexcept
185	{ return _Derived::_S_name; }
186    };
187
188namespace __detail
189{
190#if __cpp_lib_concepts
191  template<typename _Tp>
192    concept __protocol_like
193      = copyable<_Tp> && requires { typename _Tp::endpoint; };
194
195  // Endpoint requirements for non-extensible implementations.
196  template<typename _Tp>
197    concept __endpoint_base = semiregular<_Tp>
198      && requires  { typename _Tp::protocol_type; }
199      && __protocol_like<typename _Tp::protocol_type>
200      && requires(const _Tp __a) {
201	{ __a.protocol() } -> same_as<typename _Tp::protocol_type>;
202      };
203
204  // Endpoint requirements for extensible implementations.
205  template<typename _Tp>
206    concept __endpoint = __endpoint_base<_Tp>
207      && requires (const _Tp& __a, _Tp& __b, size_t __s)
208      {
209	{ __a.data() } -> same_as<const void*>;
210	{ __b.data() } -> same_as<void*>;
211	{ __b.size() } -> same_as<size_t>;
212	__b.resize(__s);
213	{ __a.capacity() } -> same_as<size_t>;
214      };
215
216  // Protocol requirements for non-extensible implementations.
217  template<typename _Tp>
218    concept __protocol_base = __protocol_like<_Tp>
219      && __endpoint_base<typename _Tp::endpoint>
220      && same_as<typename _Tp::endpoint::protocol_type, _Tp>;
221
222  // Protocol requirements for extensible implementations.
223  template<typename _Tp>
224    concept __protocol =  __protocol_base<_Tp>
225      && __endpoint<typename _Tp::endpoint>
226      && requires (const _Tp __a) {
227	{ __a.family() } -> same_as<int>;
228	{ __a.type() } -> same_as<int>;
229	{ __a.protocol() } -> same_as<int>;
230      };
231
232  template<typename _Tp>
233    concept __acceptable_protocol = __protocol<_Tp>
234      && requires { typename _Tp::socket; }
235      && move_constructible<typename _Tp::socket>
236      && derived_from<typename _Tp::socket, basic_socket<_Tp>>;
237
238  template<typename _Tp>
239    concept __inet_protocol = __acceptable_protocol<_Tp>
240      && equality_comparable<_Tp> && requires {
241	{ _Tp::v4() } -> same_as<_Tp>;
242	{ _Tp::v6() } -> same_as<_Tp>;
243	typename _Tp::resolver;
244      }
245      && same_as<typename _Tp::resolver, ip::basic_resolver<_Tp>>;
246
247#else
248  // Check Endpoint requirements for extensible implementations
249  template<typename _Tp, typename = void>
250    struct __is_endpoint : false_type
251    { };
252
253  template<typename _Tp>
254    auto
255    __endpoint_reqs(const _Tp* __a = nullptr, _Tp* __b = nullptr)
256    -> enable_if_t<__and_<
257      is_default_constructible<_Tp>, __is_value_constructible<_Tp>,
258      is_same<decltype(__a->protocol()), typename _Tp::protocol_type>,
259      is_same<decltype(__a->data()), const void*>,
260      is_same<decltype(__b->data()), void*>,
261      is_same<decltype(__a->size()), size_t>,
262      is_same<decltype(__a->capacity()), size_t>
263      >::value,
264    __void_t< typename _Tp::protocol_type::endpoint,
265	      decltype(__b->resize(std::declval<size_t>())) >>;
266
267  template<typename _Tp>
268    struct __is_endpoint<_Tp, decltype(__detail::__endpoint_reqs<_Tp>())>
269    : true_type
270    { };
271
272  // Check Protocol requirements for extensible implementations.
273  template<typename _Tp, typename = void>
274    struct __is_protocol
275    : false_type { };
276
277  template<typename _Tp>
278    auto
279    __protocol_reqs(const _Tp* __a = nullptr)
280    -> enable_if_t<__and_<
281      is_copy_constructible<_Tp>, is_copy_assignable<_Tp>,
282      __is_endpoint<typename _Tp::endpoint>,
283      is_same<decltype(__a->family()), int>,
284      is_same<decltype(__a->type()), int>,
285      is_same<decltype(__a->protocol()), int>
286      >::value>;
287
288  template<typename _Tp>
289    struct __is_protocol<_Tp, decltype(__detail::__protocol_reqs<_Tp>())>
290    : true_type
291    { };
292
293  // Check AcceptableProtocol requirements
294  template<typename _Tp, typename = void>
295    struct __is_acceptable_protocol
296    : false_type { };
297
298  template<typename _Tp>
299    struct __is_acceptable_protocol<_Tp, __void_t<typename _Tp::socket>>
300    : __and_<__is_protocol<_Tp>, is_move_constructible<typename _Tp::socket>,
301	     is_convertible<typename _Tp::socket*, basic_socket<_Tp>*>>::type
302    { };
303
304  // Check InternetProtocol requirements
305  template<typename _Tp, typename = void>
306    struct __is_inet_protocol
307    : false_type { };
308
309  template<typename _Tp>
310    auto
311    __inet_proto_reqs(const _Tp* __a = nullptr)
312    -> enable_if_t<__and_<
313      __is_acceptable_protocol<_Tp>,
314      is_same<typename _Tp::resolver, ip::basic_resolver<_Tp>>,
315      is_same<decltype(_Tp::v4()), _Tp>,
316      is_same<decltype(_Tp::v6()), _Tp>,
317      is_convertible<decltype(*__a == *__a), bool>,
318      is_convertible<decltype(*__a != *__a), bool>
319      >::value>;
320
321  template<typename _Tp>
322    struct __is_inet_protocol<_Tp, decltype(__inet_proto_reqs<_Tp>())>
323    : true_type { };
324
325  // Variable templates for requirements (with same names as concepts above).
326
327  template<typename _Tp>
328    constexpr bool __endpoint = __is_endpoint<_Tp>::value;
329  template<typename _Tp>
330    constexpr bool __protocol = __is_protocol<_Tp>::value;
331  template<typename _Tp>
332    constexpr bool __acceptable_protocol = __is_acceptable_protocol<_Tp>::value;
333#endif
334} // namespace __detail
335
336  /// @}
337
338} // namespace v1
339} // namespace net
340} // namespace experimental
341_GLIBCXX_END_NAMESPACE_VERSION
342} // namespace std
343
344#endif // C++14
345
346#endif // _GLIBCXX_EXPERIMENTAL_NET_H
347