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_CORE_FLAT_STREAM_HPP 11 #define BOOST_BEAST_CORE_FLAT_STREAM_HPP 12 13 #include <boost/beast/core/detail/config.hpp> 14 #include <boost/beast/core/error.hpp> 15 #include <boost/beast/core/flat_buffer.hpp> 16 #include <boost/beast/core/stream_traits.hpp> 17 #include <boost/beast/core/detail/flat_stream.hpp> 18 #include <boost/asio/async_result.hpp> 19 #include <cstdlib> 20 #include <utility> 21 22 namespace boost { 23 namespace beast { 24 25 /** Stream wrapper to improve write performance. 26 27 This wrapper flattens writes for buffer sequences having length 28 greater than 1 and total size below a predefined amount, using 29 a dynamic memory allocation. It is primarily designed to overcome 30 a performance limitation of the current version of `net::ssl::stream`, 31 which does not use OpenSSL's scatter/gather interface for its 32 low-level read some and write some operations. 33 34 It is normally not necessary to use this class directly if you 35 are already using @ref ssl_stream. The following examples shows 36 how to use this class with the ssl stream that comes with 37 networking: 38 39 @par Example 40 41 To use the @ref flat_stream template with SSL streams, declare 42 a variable of the correct type. Parameters passed to the constructor 43 will be forwarded to the next layer's constructor: 44 45 @code 46 flat_stream<net::ssl::stream<ip::tcp::socket>> fs{ioc, ctx}; 47 @endcode 48 Alternatively you can write 49 @code 50 ssl::stream<ip::tcp::socket> ss{ioc, ctx}; 51 flat_stream<net::ssl::stream<ip::tcp::socket>&> fs{ss}; 52 @endcode 53 54 The resulting stream may be passed to any stream algorithms which 55 operate on synchronous or asynchronous read or write streams, 56 examples include: 57 58 @li `net::read`, `net::async_read` 59 60 @li `net::write`, `net::async_write` 61 62 @li `net::read_until`, `net::async_read_until` 63 64 The stream may also be used as a template parameter in other 65 stream wrappers, such as for websocket: 66 @code 67 websocket::stream<flat_stream<net::ssl::stream<ip::tcp::socket>>> ws{ioc, ctx}; 68 @endcode 69 70 @tparam NextLayer The type representing the next layer, to which 71 data will be read and written during operations. For synchronous 72 operations, the type must support the @b SyncStream concept. For 73 asynchronous operations, the type must support the @b AsyncStream 74 concept. This type will usually be some variation of 75 `net::ssl::stream`. 76 77 @par Concepts 78 @li SyncStream 79 @li AsyncStream 80 81 @see 82 @li https://github.com/boostorg/asio/issues/100 83 @li https://github.com/boostorg/beast/issues/1108 84 @li https://stackoverflow.com/questions/38198638/openssl-ssl-write-from-multiple-buffers-ssl-writev 85 @li https://stackoverflow.com/questions/50026167/performance-drop-on-port-from-beast-1-0-0-b66-to-boost-1-67-0-beast 86 */ 87 template<class NextLayer> 88 class flat_stream 89 #if ! BOOST_BEAST_DOXYGEN 90 : private detail::flat_stream_base 91 #endif 92 { 93 NextLayer stream_; 94 flat_buffer buffer_; 95 96 BOOST_STATIC_ASSERT(has_get_executor<NextLayer>::value); 97 98 struct ops; 99 100 template<class ConstBufferSequence> 101 std::size_t 102 stack_write_some( 103 std::size_t size, 104 ConstBufferSequence const& buffers, 105 error_code& ec); 106 107 public: 108 /// The type of the next layer. 109 using next_layer_type = 110 typename std::remove_reference<NextLayer>::type; 111 112 /// The type of the executor associated with the object. 113 using executor_type = beast::executor_type<next_layer_type>; 114 115 flat_stream(flat_stream&&) = default; 116 flat_stream(flat_stream const&) = default; 117 flat_stream& operator=(flat_stream&&) = default; 118 flat_stream& operator=(flat_stream const&) = default; 119 120 /** Destructor 121 122 The treatment of pending operations will be the same as that 123 of the next layer. 124 */ 125 ~flat_stream() = default; 126 127 /** Constructor 128 129 Arguments, if any, are forwarded to the next layer's constructor. 130 */ 131 template<class... Args> 132 explicit 133 flat_stream(Args&&... args); 134 135 //-------------------------------------------------------------------------- 136 137 /** Get the executor associated with the object. 138 139 This function may be used to obtain the executor object that the 140 stream uses to dispatch handlers for asynchronous operations. 141 142 @return A copy of the executor that stream will use to dispatch handlers. 143 */ 144 executor_type get_executor()145 get_executor() noexcept 146 { 147 return stream_.get_executor(); 148 } 149 150 /** Get a reference to the next layer 151 152 This function returns a reference to the next layer 153 in a stack of stream layers. 154 155 @return A reference to the next layer in the stack of 156 stream layers. 157 */ 158 next_layer_type& next_layer()159 next_layer() noexcept 160 { 161 return stream_; 162 } 163 164 /** Get a reference to the next layer 165 166 This function returns a reference to the next layer in a 167 stack of stream layers. 168 169 @return A reference to the next layer in the stack of 170 stream layers. 171 */ 172 next_layer_type const& next_layer() const173 next_layer() const noexcept 174 { 175 return stream_; 176 } 177 178 //-------------------------------------------------------------------------- 179 180 /** Read some data from the stream. 181 182 This function is used to read data from the stream. The function call will 183 block until one or more bytes of data has been read successfully, or until 184 an error occurs. 185 186 @param buffers The buffers into which the data will be read. 187 188 @returns The number of bytes read. 189 190 @throws boost::system::system_error Thrown on failure. 191 192 @note The `read_some` operation may not read all of the requested number of 193 bytes. Consider using the function `net::read` if you need to ensure 194 that the requested amount of data is read before the blocking operation 195 completes. 196 */ 197 template<class MutableBufferSequence> 198 std::size_t 199 read_some(MutableBufferSequence const& buffers); 200 201 /** Read some data from the stream. 202 203 This function is used to read data from the stream. The function call will 204 block until one or more bytes of data has been read successfully, or until 205 an error occurs. 206 207 @param buffers The buffers into which the data will be read. 208 209 @param ec Set to indicate what error occurred, if any. 210 211 @returns The number of bytes read. 212 213 @note The `read_some` operation may not read all of the requested number of 214 bytes. Consider using the function `net::read` if you need to ensure 215 that the requested amount of data is read before the blocking operation 216 completes. 217 */ 218 template<class MutableBufferSequence> 219 std::size_t 220 read_some( 221 MutableBufferSequence const& buffers, 222 error_code& ec); 223 224 /** Start an asynchronous read. 225 226 This function is used to asynchronously read one or more bytes of data from 227 the stream. The function call always returns immediately. 228 229 @param buffers The buffers into which the data will be read. Although the 230 buffers object may be copied as necessary, ownership of the underlying 231 buffers is retained by the caller, which must guarantee that they remain 232 valid until the handler is called. 233 234 @param handler The completion handler to invoke when the operation 235 completes. The implementation takes ownership of the handler by 236 performing a decay-copy. The equivalent function signature of 237 the handler must be: 238 @code 239 void handler( 240 error_code const& error, // Result of operation. 241 std::size_t bytes_transferred // Number of bytes read. 242 ); 243 @endcode 244 Regardless of whether the asynchronous operation completes 245 immediately or not, the handler will not be invoked from within 246 this function. Invocation of the handler will be performed in a 247 manner equivalent to using `net::post`. 248 249 @note The `read_some` operation may not read all of the requested number of 250 bytes. Consider using the function `net::async_read` if you need 251 to ensure that the requested amount of data is read before the asynchronous 252 operation completes. 253 */ 254 template< 255 class MutableBufferSequence, 256 BOOST_BEAST_ASYNC_TPARAM2 ReadHandler = 257 net::default_completion_token_t<executor_type>> 258 BOOST_BEAST_ASYNC_RESULT2(ReadHandler) 259 async_read_some( 260 MutableBufferSequence const& buffers, 261 ReadHandler&& handler = 262 net::default_completion_token_t<executor_type>{}); 263 264 /** Write some data to the stream. 265 266 This function is used to write data on the stream. The function call will 267 block until one or more bytes of data has been written successfully, or 268 until an error occurs. 269 270 @param buffers The data to be written. 271 272 @returns The number of bytes written. 273 274 @throws boost::system::system_error Thrown on failure. 275 276 @note The `write_some` operation may not transmit all of the data to the 277 peer. Consider using the function `net::write` if you need to 278 ensure that all data is written before the blocking operation completes. 279 */ 280 template<class ConstBufferSequence> 281 std::size_t 282 write_some(ConstBufferSequence const& buffers); 283 284 /** Write some data to the stream. 285 286 This function is used to write data on the stream. The function call will 287 block until one or more bytes of data has been written successfully, or 288 until an error occurs. 289 290 @param buffers The data to be written. 291 292 @param ec Set to indicate what error occurred, if any. 293 294 @returns The number of bytes written. 295 296 @note The `write_some` operation may not transmit all of the data to the 297 peer. Consider using the function `net::write` if you need to 298 ensure that all data is written before the blocking operation completes. 299 */ 300 template<class ConstBufferSequence> 301 std::size_t 302 write_some( 303 ConstBufferSequence const& buffers, 304 error_code& ec); 305 306 /** Start an asynchronous write. 307 308 This function is used to asynchronously write one or more bytes of data to 309 the stream. The function call always returns immediately. 310 311 @param buffers The data to be written to the stream. Although the buffers 312 object may be copied as necessary, ownership of the underlying buffers is 313 retained by the caller, which must guarantee that they remain valid until 314 the handler is called. 315 316 @param handler The completion handler to invoke when the operation 317 completes. The implementation takes ownership of the handler by 318 performing a decay-copy. The equivalent function signature of 319 the handler must be: 320 @code 321 void handler( 322 error_code const& ec, // Result of operation. 323 std::size_t bytes_transferred // Number of bytes written. 324 ); 325 @endcode 326 Regardless of whether the asynchronous operation completes 327 immediately or not, the handler will not be invoked from within 328 this function. Invocation of the handler will be performed in a 329 manner equivalent to using `net::post`. 330 331 @note The `async_write_some` operation may not transmit all of the data to 332 the peer. Consider using the function `net::async_write` if you need 333 to ensure that all data is written before the asynchronous operation completes. 334 */ 335 template< 336 class ConstBufferSequence, 337 BOOST_BEAST_ASYNC_TPARAM2 WriteHandler = 338 net::default_completion_token_t<executor_type>> 339 BOOST_BEAST_ASYNC_RESULT2(WriteHandler) 340 async_write_some( 341 ConstBufferSequence const& buffers, 342 WriteHandler&& handler = 343 net::default_completion_token_t<executor_type>{}); 344 }; 345 346 } // beast 347 } // boost 348 349 #include <boost/beast/core/impl/flat_stream.hpp> 350 351 #endif 352