xref: /netbsd-src/external/gpl3/gcc/dist/libstdc++-v3/include/experimental/bits/net.h (revision b1e838363e3c6fc78a55519254d99869742dd33c)
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 
_GLIBCXX_VISIBILITY(default)45 namespace std _GLIBCXX_VISIBILITY(default)
46 {
47 _GLIBCXX_BEGIN_NAMESPACE_VERSION
48 namespace experimental
49 {
50 namespace net
51 {
52 inline 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 
188 namespace __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