stream_traits.hpp 16 KB

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