1 //
2 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // Official repository: https://github.com/boostorg/beast
8 //
9 
10 #ifndef BOOST_BEAST_STREAM_TRAITS_HPP
11 #define BOOST_BEAST_STREAM_TRAITS_HPP
12 
13 #include <boost/beast/core/detail/config.hpp>
14 #include <boost/beast/core/detail/static_const.hpp>
15 #include <boost/beast/core/detail/stream_traits.hpp>
16 #include <boost/asio/basic_socket.hpp>
17 
18 namespace boost {
19 namespace beast {
20 
21 /** A trait to determine the lowest layer type of a stack of stream layers.
22 
23     If `t.next_layer()` is well-defined for an object `t` of type `T`,
24     then `lowest_layer_type<T>` will be an alias for
25     `lowest_layer_type<decltype(t.next_layer())>`,
26     otherwise it will be the type
27     `std::remove_reference<T>`.
28 
29     @param T The type to determine the lowest layer type of.
30 
31     @return The type of the lowest layer.
32 */
33 template<class T>
34 #if BOOST_BEAST_DOXYGEN
35 using lowest_layer_type = __see_below__;
36 #else
37 using lowest_layer_type = detail::lowest_layer_type<T>;
38 #endif
39 
40 /** Return the lowest layer in a stack of stream layers.
41 
42     If `t.next_layer()` is well-defined, returns
43     `get_lowest_layer(t.next_layer())`. Otherwise, it returns `t`.
44 
45     A stream layer is an object of class type which wraps another object through
46     composition, and meets some or all of the named requirements of the wrapped
47     type while optionally changing behavior. Examples of stream layers include
48     `net::ssl::stream` or @ref beast::websocket::stream. The owner of a stream
49     layer can interact directly with the wrapper, by passing it to stream
50     algorithms. Or, the owner can obtain a reference to the wrapped object by
51     calling `next_layer()` and accessing its members. This is necessary when it is
52     desired to access functionality in the next layer which is not available
53     in the wrapper. For example, @ref websocket::stream permits reading and
54     writing, but in order to establish the underlying connection, members
55     of the wrapped stream (such as `connect`) must be invoked directly.
56 
57     Usually the last object in the chain of composition is the concrete socket
58     object (for example, a `net::basic_socket` or a class derived from it).
59     The function @ref get_lowest_layer exists to easily obtain the concrete
60     socket when it is desired to perform an action that is not prescribed by
61     a named requirement, such as changing a socket option, cancelling all
62     pending asynchronous I/O, or closing the socket (perhaps by using
63     @ref close_socket).
64 
65     @par Example
66     @code
67     // Set non-blocking mode on a stack of stream
68     // layers with a regular socket at the lowest layer.
69     template <class Stream>
70     void set_non_blocking (Stream& stream)
71     {
72         error_code ec;
73         // A compile error here means your lowest layer is not the right type!
74         get_lowest_layer(stream).non_blocking(true, ec);
75         if(ec)
76             throw system_error{ec};
77     }
78     @endcode
79 
80     @param t The layer in a stack of layered objects for which the lowest layer is returned.
81 
82     @see close_socket, lowest_layer_type
83 */
84 template<class T>
85 lowest_layer_type<T>&
get_lowest_layer(T & t)86 get_lowest_layer(T& t) noexcept
87 {
88     return detail::get_lowest_layer_impl(
89         t, detail::has_next_layer<T>{});
90 }
91 
92 //------------------------------------------------------------------------------
93 
94 /** A trait to determine the return type of get_executor.
95 
96     This type alias will be the type of values returned by
97     by calling member `get_exector` on an object of type `T&`.
98 
99     @param T The type to query
100 
101     @return The type of values returned from `get_executor`.
102 */
103 // Workaround for ICE on gcc 4.8
104 #if BOOST_BEAST_DOXYGEN
105 template<class T>
106 using executor_type = __see_below__;
107 #elif BOOST_WORKAROUND(BOOST_GCC, < 40900)
108 template<class T>
109 using executor_type =
110     typename std::decay<T>::type::executor_type;
111 #else
112 template<class T>
113 using executor_type =
114     decltype(std::declval<T&>().get_executor());
115 #endif
116 
117 /** Determine if `T` has the `get_executor` member function.
118 
119     Metafunctions are used to perform compile time checking of template
120     types. This type will be `std::true_type` if `T` has the member
121     function with the correct signature, else type will be `std::false_type`.
122 
123     @par Example
124 
125     Use with tag dispatching:
126 
127     @code
128     template<class T>
129     void maybe_hello(T const& t, std::true_type)
130     {
131         net::post(
132             t.get_executor(),
133             []
134             {
135                 std::cout << "Hello, world!" << std::endl;
136             });
137     }
138 
139     template<class T>
140     void maybe_hello(T const&, std::false_type)
141     {
142         // T does not have get_executor
143     }
144 
145     template<class T>
146     void maybe_hello(T const& t)
147     {
148         maybe_hello(t, has_get_executor<T>{});
149     }
150     @endcode
151 
152     Use with `static_assert`:
153 
154     @code
155     struct stream
156     {
157         using executor_type = net::io_context::executor_type;
158         executor_type get_executor() noexcept;
159     };
160 
161     static_assert(has_get_executor<stream>::value, "Missing get_executor member");
162     @endcode
163 */
164 #if BOOST_BEAST_DOXYGEN
165 template<class T>
166 using has_get_executor = __see_below__;
167 #else
168 template<class T, class = void>
169 struct has_get_executor : std::false_type {};
170 
171 template<class T>
172 struct has_get_executor<T, boost::void_t<decltype(
173     std::declval<T&>().get_executor())>> : std::true_type {};
174 #endif
175 
176 //------------------------------------------------------------------------------
177 
178 /** Determine if at type meets the requirements of <em>SyncReadStream</em>.
179 
180     Metafunctions are used to perform compile time checking of template
181     types. This type will be `std::true_type` if `T` meets the requirements,
182     else the type will be `std::false_type`.
183 
184     @par Example
185     Use with `static_assert`:
186     @code
187     template<class SyncReadStream>
188     void f(SyncReadStream& stream)
189     {
190         static_assert(is_sync_read_stream<SyncReadStream>::value,
191             "SyncReadStream type requirements not met");
192     ...
193     @endcode
194 
195     Use with `std::enable_if` (SFINAE):
196     @code
197     template<class SyncReadStream>
198     typename std::enable_if<is_sync_read_stream<SyncReadStream>::value>::type
199     f(SyncReadStream& stream);
200     @endcode
201 */
202 #if BOOST_BEAST_DOXYGEN
203 template<class T>
204 using is_sync_read_stream = __see_below__;
205 #else
206 template<class T, class = void>
207 struct is_sync_read_stream : std::false_type {};
208 
209 template<class T>
210 struct is_sync_read_stream<T, boost::void_t<decltype(
211     std::declval<std::size_t&>() = std::declval<T&>().read_some(
212         std::declval<detail::MutableBufferSequence>()),
213     std::declval<std::size_t&>() = std::declval<T&>().read_some(
214         std::declval<detail::MutableBufferSequence>(),
215         std::declval<boost::system::error_code&>())
216             )>> : std::true_type {};
217 #endif
218 
219 /** Determine if `T` meets the requirements of <em>SyncWriteStream</em>.
220 
221     Metafunctions are used to perform compile time checking of template
222     types. This type will be `std::true_type` if `T` meets the requirements,
223     else the type will be `std::false_type`.
224 
225     @par Example
226 
227     Use with `static_assert`:
228 
229     @code
230     template<class SyncReadStream>
231     void f(SyncReadStream& stream)
232     {
233         static_assert(is_sync_read_stream<SyncReadStream>::value,
234             "SyncReadStream type requirements not met");
235     ...
236     @endcode
237 
238     Use with `std::enable_if` (SFINAE):
239 
240     @code
241     template<class SyncReadStream>
242     typename std::enable_if<is_sync_read_stream<SyncReadStream>::value>::type
243     f(SyncReadStream& stream);
244     @endcode
245 */
246 #if BOOST_BEAST_DOXYGEN
247 template<class T>
248 using is_sync_write_stream = __see_below__;
249 #else
250 template<class T, class = void>
251 struct is_sync_write_stream : std::false_type {};
252 
253 template<class T>
254 struct is_sync_write_stream<T, boost::void_t<decltype(
255     (
256     std::declval<std::size_t&>() = std::declval<T&>().write_some(
257         std::declval<detail::ConstBufferSequence>()))
258     ,std::declval<std::size_t&>() = std::declval<T&>().write_some(
259         std::declval<detail::ConstBufferSequence>(),
260         std::declval<boost::system::error_code&>())
261             )>> : std::true_type {};
262 #endif
263 
264 /** Determine if `T` meets the requirements of @b SyncStream.
265 
266     Metafunctions are used to perform compile time checking of template
267     types. This type will be `std::true_type` if `T` meets the requirements,
268     else the type will be `std::false_type`.
269 
270     @par Example
271 
272     Use with `static_assert`:
273 
274     @code
275     template<class SyncStream>
276     void f(SyncStream& stream)
277     {
278         static_assert(is_sync_stream<SyncStream>::value,
279             "SyncStream type requirements not met");
280     ...
281     @endcode
282 
283     Use with `std::enable_if` (SFINAE):
284 
285     @code
286     template<class SyncStream>
287     typename std::enable_if<is_sync_stream<SyncStream>::value>::type
288     f(SyncStream& stream);
289     @endcode
290 */
291 #if BOOST_BEAST_DOXYGEN
292 template<class T>
293 using is_sync_stream = __see_below__;
294 #else
295 template<class T>
296 using is_sync_stream = std::integral_constant<bool,
297     is_sync_read_stream<T>::value && is_sync_write_stream<T>::value>;
298 #endif
299 
300 //------------------------------------------------------------------------------
301 
302 /** Determine if `T` meets the requirements of <em>AsyncReadStream</em>.
303 
304     Metafunctions are used to perform compile time checking of template
305     types. This type will be `std::true_type` if `T` meets the requirements,
306     else the type will be `std::false_type`.
307 
308     @par Example
309 
310     Use with `static_assert`:
311 
312     @code
313     template<class AsyncReadStream>
314     void f(AsyncReadStream& stream)
315     {
316         static_assert(is_async_read_stream<AsyncReadStream>::value,
317             "AsyncReadStream type requirements not met");
318     ...
319     @endcode
320 
321     Use with `std::enable_if` (SFINAE):
322 
323     @code
324         template<class AsyncReadStream>
325         typename std::enable_if<is_async_read_stream<AsyncReadStream>::value>::type
326         f(AsyncReadStream& stream);
327     @endcode
328 */
329 #if BOOST_BEAST_DOXYGEN
330 template<class T>
331 using is_async_read_stream = __see_below__;
332 #else
333 template<class T, class = void>
334 struct is_async_read_stream : std::false_type {};
335 
336 template<class T>
337 struct is_async_read_stream<T, boost::void_t<decltype(
338     std::declval<T&>().async_read_some(
339         std::declval<detail::MutableBufferSequence>(),
340         std::declval<detail::ReadHandler>())
341             )>> : std::integral_constant<bool,
342     has_get_executor<T>::value
343         > {};
344 #endif
345 
346 /** Determine if `T` meets the requirements of <em>AsyncWriteStream</em>.
347 
348     Metafunctions are used to perform compile time checking of template
349     types. This type will be `std::true_type` if `T` meets the requirements,
350     else the type will be `std::false_type`.
351 
352     @par Example
353 
354     Use with `static_assert`:
355 
356     @code
357     template<class AsyncWriteStream>
358     void f(AsyncWriteStream& stream)
359     {
360         static_assert(is_async_write_stream<AsyncWriteStream>::value,
361             "AsyncWriteStream type requirements not met");
362     ...
363     @endcode
364 
365     Use with `std::enable_if` (SFINAE):
366 
367     @code
368     template<class AsyncWriteStream>
369     typename std::enable_if<is_async_write_stream<AsyncWriteStream>::value>::type
370     f(AsyncWriteStream& stream);
371     @endcode
372 */
373 #if BOOST_BEAST_DOXYGEN
374 template<class T>
375 using is_async_write_stream = __see_below__;
376 #else
377 template<class T, class = void>
378 struct is_async_write_stream : std::false_type {};
379 
380 template<class T>
381 struct is_async_write_stream<T, boost::void_t<decltype(
382     std::declval<T&>().async_write_some(
383         std::declval<detail::ConstBufferSequence>(),
384         std::declval<detail::WriteHandler>())
385             )>> : std::integral_constant<bool,
386     has_get_executor<T>::value
387         > {};
388 #endif
389 
390 /** Determine if `T` meets the requirements of @b AsyncStream.
391 
392     Metafunctions are used to perform compile time checking of template
393     types. This type will be `std::true_type` if `T` meets the requirements,
394     else the type will be `std::false_type`.
395 
396     @par Example
397 
398     Use with `static_assert`:
399 
400     @code
401     template<class AsyncStream>
402     void f(AsyncStream& stream)
403     {
404         static_assert(is_async_stream<AsyncStream>::value,
405             "AsyncStream type requirements not met");
406     ...
407     @endcode
408 
409     Use with `std::enable_if` (SFINAE):
410 
411     @code
412     template<class AsyncStream>
413     typename std::enable_if<is_async_stream<AsyncStream>::value>::type
414     f(AsyncStream& stream);
415     @endcode
416 */
417 #if BOOST_BEAST_DOXYGEN
418 template<class T>
419 using is_async_stream = __see_below__;
420 #else
421 template<class T>
422 using is_async_stream = std::integral_constant<bool,
423     is_async_read_stream<T>::value && is_async_write_stream<T>::value>;
424 #endif
425 
426 //------------------------------------------------------------------------------
427 
428 /** Default socket close function.
429 
430     This function is not meant to be called directly. Instead, it
431     is called automatically when using @ref close_socket. To enable
432     closure of user-defined types or classes derived from a particular
433     user-defined type, this function should be overloaded in the
434     corresponding namespace for the type in question.
435 
436     @see close_socket
437 */
438 template<
439     class Protocol,
440     class Executor>
441 void
beast_close_socket(net::basic_socket<Protocol,Executor> & sock)442 beast_close_socket(
443     net::basic_socket<
444         Protocol, Executor>& sock)
445 {
446     boost::system::error_code ec;
447     sock.close(ec);
448 }
449 
450 namespace detail {
451 
452 struct close_socket_impl
453 {
454     template<class T>
455     void
operator ()boost::beast::detail::close_socket_impl456     operator()(T& t) const
457     {
458         using beast::beast_close_socket;
459         beast_close_socket(t);
460     }
461 };
462 
463 } // detail
464 
465 /** Close a socket or socket-like object.
466 
467     This function attempts to close an object representing a socket.
468     In this context, a socket is an object for which an unqualified
469     call to the function `void beast_close_socket(Socket&)` is
470     well-defined. The function `beast_close_socket` is a
471     <em>customization point</em>, allowing user-defined types to
472     provide an algorithm for performing the close operation by
473     overloading this function for the type in question.
474 
475     Since the customization point is a function call, the normal
476     rules for finding the correct overload are applied including
477     the rules for argument-dependent lookup ("ADL"). This permits
478     classes derived from a type for which a customization is provided
479     to inherit the customization point.
480 
481     An overload for the networking class template `net::basic_socket`
482     is provided, which implements the close algorithm for all socket-like
483     objects (hence the name of this customization point). When used
484     in conjunction with @ref get_lowest_layer, a generic algorithm
485     operating on a layered stream can perform a closure of the underlying
486     socket without knowing the exact list of concrete types.
487 
488     @par Example 1
489     The following generic function synchronously sends a message
490     on the stream, then closes the socket.
491     @code
492     template <class WriteStream>
493     void hello_and_close (WriteStream& stream)
494     {
495         net::write(stream, net::const_buffer("Hello, world!", 13));
496         close_socket(get_lowest_layer(stream));
497     }
498     @endcode
499 
500     To enable closure of user defined types, it is necessary to provide
501     an overload of the function `beast_close_socket` for the type.
502 
503     @par Example 2
504     The following code declares a user-defined type which contains a
505     private socket, and provides an overload of the customization
506     point which closes the private socket.
507     @code
508     class my_socket
509     {
510         net::ip::tcp::socket sock_;
511 
512     public:
513         my_socket(net::io_context& ioc)
514             : sock_(ioc)
515         {
516         }
517 
518         friend void beast_close_socket(my_socket& s)
519         {
520             error_code ec;
521             s.sock_.close(ec);
522             // ignore the error
523         }
524     };
525     @endcode
526 
527     @param sock The socket to close. If the customization point is not
528     defined for the type of this object, or one of its base classes,
529     then a compiler error results.
530 
531     @see beast_close_socket
532 */
533 #if BOOST_BEAST_DOXYGEN
534 template<class Socket>
535 void
536 close_socket(Socket& sock);
537 #else
538 BOOST_BEAST_INLINE_VARIABLE(close_socket, detail::close_socket_impl)
539 #endif
540 
541 } // beast
542 } // boost
543 
544 #endif
545