1<html> 2<head> 3<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 4<title>Echo </title> 5<link rel="stylesheet" href="../../../../../../../doc/src/boostbook.css" type="text/css"> 6<meta name="generator" content="DocBook XSL Stylesheets V1.79.1"> 7<link rel="home" href="../../../index.html" title="Chapter 1. Boost.Beast"> 8<link rel="up" href="../writing_composed_operations.html" title="Writing Composed Operations"> 9<link rel="prev" href="../writing_composed_operations.html" title="Writing Composed Operations"> 10<link rel="next" href="detect_ssl.html" title="Detect SSL "> 11</head> 12<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"> 13<table cellpadding="2" width="100%"><tr> 14<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../../boost.png"></td> 15<td align="center"><a href="../../../../../../../index.html">Home</a></td> 16<td align="center"><a href="../../../../../../../libs/libraries.htm">Libraries</a></td> 17<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td> 18<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td> 19<td align="center"><a href="../../../../../../../more/index.htm">More</a></td> 20</tr></table> 21<hr> 22<div class="spirit-nav"> 23<a accesskey="p" href="../writing_composed_operations.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../writing_composed_operations.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="detect_ssl.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a> 24</div> 25<div class="section"> 26<div class="titlepage"><div><div><h4 class="title"> 27<a name="beast.using_io.writing_composed_operations.echo"></a><a class="link" href="echo.html" title="Echo ">Echo 28 </a> 29</h4></div></div></div> 30<p> 31 This example develops an initiating function called <span class="bold"><strong>echo</strong></span>. 32 The operation will read up to the first newline on a stream, and then write 33 the same line including the newline back on the stream. First we define 34 the input parameters and results, then declare our initiation function. 35 For our echo operation the only inputs are the stream and the completion 36 token. The output is the error code which is usually included in all completion 37 handler signatures. 38 </p> 39<pre class="programlisting"><span class="comment">/** Asynchronously read a line and echo it back. 40 41 This function is used to asynchronously read a line ending 42 in a newline (`"\n"`) from the stream, and then write 43 it back. 44 45 This call always returns immediately. The asynchronous operation 46 will continue until one of the following conditions is true: 47 48 @li A line was read in and written back on the stream 49 50 @li An error occurs. 51 52 The algorithm, known as a <em>composed asynchronous operation</em>, 53 is implemented in terms of calls to the stream's `async_read_some` 54 and `async_write_some` function. The program must ensure that no 55 other reads or writes are performed until this operation completes. 56 57 Since the length of the line is not known ahead of time, the 58 implementation may read additional characters that lie past the 59 first line. These characters are stored in the dynamic buffer_. 60 The same dynamic buffer must be presented again in each call, 61 to provide the implementation with any leftover bytes. 62 63 @param stream The stream to operate on. The type must meet the 64 requirements of <em>AsyncReadStream</em> and @AsyncWriteStream 65 66 @param buffer A dynamic buffer to hold implementation-defined 67 temporary data. Ownership is not transferred; the caller is 68 responsible for ensuring that the lifetime of this object is 69 extended least until the completion handler is invoked. 70 71 @param token The handler to be called when the operation completes. 72 The implementation takes ownership of the handler by performing a decay-copy. 73 The handler must be invocable with this signature: 74 @code 75 void handler( 76 beast::error_code error // Result of operation. 77 ); 78 @endcode 79 80 Regardless of whether the asynchronous operation completes immediately or 81 not, the handler will not be invoked from within this function. Invocation 82 of the handler will be performed in a manner equivalent to using 83 `net::post`. 84*/</span> 85<span class="keyword">template</span><span class="special"><</span> 86 <span class="keyword">class</span> <span class="identifier">AsyncStream</span><span class="special">,</span> 87 <span class="keyword">class</span> <span class="identifier">DynamicBuffer</span><span class="special">,</span> 88 <span class="keyword">class</span> <span class="identifier">CompletionToken</span><span class="special">></span> 89<span class="keyword">auto</span> 90<span class="identifier">async_echo</span> <span class="special">(</span> 91 <span class="identifier">AsyncStream</span><span class="special">&</span> <span class="identifier">stream</span><span class="special">,</span> 92 <span class="identifier">DynamicBuffer</span><span class="special">&</span> <span class="identifier">buffer</span><span class="special">,</span> <a class="co" name="beast.using_io.writing_composed_operations.echo.c0" href="echo.html#beast.using_io.writing_composed_operations.echo.c1"><img src="../../../../../../../doc/src/images/callouts/1.png" alt="1" border="0"></a> 93 <span class="identifier">CompletionToken</span><span class="special">&&</span> <span class="identifier">token</span><span class="special">)</span> <span class="special">-></span> 94 <span class="keyword">typename</span> <span class="identifier">net</span><span class="special">::</span><span class="identifier">async_result</span><span class="special"><</span> <a class="co" name="beast.using_io.writing_composed_operations.echo.c2" href="echo.html#beast.using_io.writing_composed_operations.echo.c3"><img src="../../../../../../../doc/src/images/callouts/2.png" alt="2" border="0"></a> 95 <span class="keyword">typename</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">decay</span><span class="special"><</span><span class="identifier">CompletionToken</span><span class="special">>::</span><span class="identifier">type</span><span class="special">,</span> 96 <span class="keyword">void</span><span class="special">(</span><span class="identifier">beast</span><span class="special">::</span><span class="identifier">error_code</span><span class="special">)</span> <a class="co" name="beast.using_io.writing_composed_operations.echo.c4" href="echo.html#beast.using_io.writing_composed_operations.echo.c5"><img src="../../../../../../../doc/src/images/callouts/3.png" alt="3" border="0"></a> 97 <span class="special">>::</span><span class="identifier">return_type</span><span class="special">;</span> 98</pre> 99<div class="calloutlist"><table border="0" summary="Callout list"> 100<tr> 101<td width="5%" valign="top" align="left"><p><a name="beast.using_io.writing_composed_operations.echo.c1"></a><a href="#beast.using_io.writing_composed_operations.echo.c0"><img src="../../../../../../../doc/src/images/callouts/1.png" alt="1" border="0"></a> </p></td> 102<td valign="top" align="left"><p> 103 Unlike Asio, we pass by non-const reference instead of rvalue-ref 104 </p></td> 105</tr> 106<tr> 107<td width="5%" valign="top" align="left"><p><a name="beast.using_io.writing_composed_operations.echo.c3"></a><a href="#beast.using_io.writing_composed_operations.echo.c2"><img src="../../../../../../../doc/src/images/callouts/2.png" alt="2" border="0"></a> </p></td> 108<td valign="top" align="left"><p> 109 <code class="computeroutput"><span class="identifier">async_result</span></code> deduces 110 the return type from the completion handler 111 </p></td> 112</tr> 113<tr> 114<td width="5%" valign="top" align="left"><p><a name="beast.using_io.writing_composed_operations.echo.c5"></a><a href="#beast.using_io.writing_composed_operations.echo.c4"><img src="../../../../../../../doc/src/images/callouts/3.png" alt="3" border="0"></a> </p></td> 115<td valign="top" align="left"><p> 116 The completion handler signature goes here 117 </p></td> 118</tr> 119</table></div> 120<p> 121 Now that we have a declaration, we will define the body of the function. 122 We want to achieve the following goals: perform static type checking on 123 the input parameters, set up the return value as per <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3747.pdf" target="_top"><span class="bold"><strong>N3747</strong></span></a>, and launch the composed operation 124 by constructing an intermediate, stateful completion handler and invoking 125 it. 126 </p> 127<p> 128 The initiating function contains a few relatively simple parts. There is 129 the customization of the return value type, static type checking, building 130 the return value type using the helper, and creating and launching the 131 <code class="computeroutput"><span class="identifier">echo_op</span></code> composed operation 132 object. 133 </p> 134<p> 135 The implementation strategy is to make the composed object meet the requirements 136 of a completion handler by being movable, and by making it invocable so 137 it can be used as a continuation for the asynchronous operations it launches. 138 Rather than using <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">bind</span></code> or <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">bind</span></code>, 139 which destroys the type information and therefore breaks the allocation 140 and invocation hooks, we will simply pass <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">move</span><span class="special">(*</span><span class="keyword">this</span><span class="special">)</span></code> 141 as the completion handler parameter for any operations that we initiate. 142 For the move to work correctly, care must be taken to ensure that no access 143 to data members are made after the move takes place. Here is the complete 144 implementation of our composed operation: 145 </p> 146<pre class="programlisting"><span class="keyword">template</span><span class="special"><</span><span class="keyword">class</span> <span class="identifier">AsyncStream</span><span class="special">,</span> <span class="keyword">class</span> <span class="identifier">Handler</span><span class="special">></span> 147<span class="keyword">class</span> <span class="identifier">echo_op</span><span class="special">;</span> 148 149<span class="comment">// This example uses the Asio's stackless "fauxroutines", implemented</span> 150<span class="comment">// using a macro-based solution. It makes the code easier to write and</span> 151<span class="comment">// easier to read. This include file defines the necessary macros and types.</span> 152<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">asio</span><span class="special">/</span><span class="identifier">yield</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> 153 154<span class="comment">// Read a line and echo it back</span> 155<span class="comment">//</span> 156<span class="keyword">template</span><span class="special"><</span> 157 <span class="keyword">class</span> <span class="identifier">AsyncStream</span><span class="special">,</span> 158 <span class="keyword">class</span> <span class="identifier">DynamicBuffer</span><span class="special">,</span> 159 <span class="keyword">class</span> <span class="identifier">CompletionToken</span><span class="special">></span> 160<span class="keyword">auto</span> 161<span class="identifier">async_echo</span><span class="special">(</span> 162 <span class="identifier">AsyncStream</span><span class="special">&</span> <span class="identifier">stream</span><span class="special">,</span> 163 <span class="identifier">DynamicBuffer</span><span class="special">&</span> <span class="identifier">buffer</span><span class="special">,</span> 164 <span class="identifier">CompletionToken</span><span class="special">&&</span> <span class="identifier">token</span><span class="special">)</span> <span class="special">-></span> 165 <span class="keyword">typename</span> <span class="identifier">net</span><span class="special">::</span><span class="identifier">async_result</span><span class="special"><</span> 166 <span class="keyword">typename</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">decay</span><span class="special"><</span><span class="identifier">CompletionToken</span><span class="special">>::</span><span class="identifier">type</span><span class="special">,</span> 167 <span class="keyword">void</span><span class="special">(</span><span class="identifier">beast</span><span class="special">::</span><span class="identifier">error_code</span><span class="special">)>::</span><span class="identifier">return_type</span> <a class="co" name="beast.using_io.writing_composed_operations.echo.c6" href="echo.html#beast.using_io.writing_composed_operations.echo.c7"><img src="../../../../../../../doc/src/images/callouts/1.png" alt="1" border="0"></a> 168<span class="special">{</span> 169 <span class="comment">// Perform some type checks using static assert, this helps</span> 170 <span class="comment">// with more friendly error messages when passing the wrong types.</span> 171 <span class="keyword">static_assert</span><span class="special">(</span> 172 <span class="identifier">beast</span><span class="special">::</span><span class="identifier">is_async_stream</span><span class="special"><</span><span class="identifier">AsyncStream</span><span class="special">>::</span><span class="identifier">value</span><span class="special">,</span> 173 <span class="string">"AsyncStream type requirements not met"</span><span class="special">);</span> 174 <span class="keyword">static_assert</span><span class="special">(</span> 175 <span class="identifier">net</span><span class="special">::</span><span class="identifier">is_dynamic_buffer</span><span class="special"><</span><span class="identifier">DynamicBuffer</span><span class="special">>::</span><span class="identifier">value</span><span class="special">,</span> 176 <span class="string">"DynamicBuffer type requirements not met"</span><span class="special">);</span> 177 178 <span class="comment">// This class template deduces the actual handler type from a</span> 179 <span class="comment">// CompletionToken, captures a local reference to the handler,</span> 180 <span class="comment">// and creates the `async_result` object which becomes the</span> 181 <span class="comment">// return value of this initiating function.</span> 182 183 <span class="identifier">net</span><span class="special">::</span><span class="identifier">async_completion</span><span class="special"><</span><span class="identifier">CompletionToken</span><span class="special">,</span> <span class="keyword">void</span><span class="special">(</span><span class="identifier">beast</span><span class="special">::</span><span class="identifier">error_code</span><span class="special">)></span> <span class="identifier">init</span><span class="special">(</span><span class="identifier">token</span><span class="special">);</span> 184 185 <span class="comment">// The helper macro BOOST_ASIO_HANDLER_TYPE converts the completion</span> 186 <span class="comment">// token type into a concrete handler type of the correct signature.</span> 187 188 <span class="keyword">using</span> <span class="identifier">handler_type</span> <span class="special">=</span> <span class="identifier">BOOST_ASIO_HANDLER_TYPE</span><span class="special">(</span><span class="identifier">CompletionToken</span><span class="special">,</span> <span class="keyword">void</span><span class="special">(</span><span class="identifier">beast</span><span class="special">::</span><span class="identifier">error_code</span><span class="special">));</span> 189 190 <span class="comment">// The class template `async_base` holds the caller's completion</span> 191 <span class="comment">// handler for us, and provides all of the boilerplate for forwarding</span> 192 <span class="comment">// the associated allocator and associated executor from the caller's</span> 193 <span class="comment">// handler to our operation. It also maintains a `net::executor_work_guard`</span> 194 <span class="comment">// for the executor associated with the stream. This work guard is</span> 195 <span class="comment">// inexpensive, and prevents the execution context from running out</span> 196 <span class="comment">// of work. It is usually necessary although rarely it can be skipped</span> 197 <span class="comment">// depending on the operation (this echo example needs it because it</span> 198 <span class="comment">// performs more than one asynchronous operation in a row).</span> 199 <span class="comment">// We declare this type alias to make the code easier to read.</span> 200 201 <span class="keyword">using</span> <span class="identifier">base_type</span> <span class="special">=</span> <span class="identifier">beast</span><span class="special">::</span><span class="identifier">async_base</span><span class="special"><</span> 202 <span class="identifier">handler_type</span><span class="special">,</span> <a class="co" name="beast.using_io.writing_composed_operations.echo.c8" href="echo.html#beast.using_io.writing_composed_operations.echo.c9"><img src="../../../../../../../doc/src/images/callouts/2.png" alt="2" border="0"></a> 203 <span class="identifier">beast</span><span class="special">::</span><span class="identifier">executor_type</span><span class="special"><</span><span class="identifier">AsyncStream</span><span class="special">></span> <a class="co" name="beast.using_io.writing_composed_operations.echo.c10" href="echo.html#beast.using_io.writing_composed_operations.echo.c11"><img src="../../../../../../../doc/src/images/callouts/3.png" alt="3" border="0"></a> 204 <span class="special">>;</span> 205 206 <span class="comment">// This nested class implements the echo composed operation as a</span> 207 <span class="comment">// stateful completion handler. We derive from `async_base` to</span> 208 <span class="comment">// take care of boilerplate and we derived from asio::coroutine to</span> 209 <span class="comment">// allow the reenter and yield keywords to work.</span> 210 211 <span class="keyword">struct</span> <span class="identifier">echo_op</span> <span class="special">:</span> <span class="identifier">base_type</span><span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">coroutine</span> 212 <span class="special">{</span> 213 <span class="identifier">AsyncStream</span><span class="special">&</span> <span class="identifier">stream_</span><span class="special">;</span> 214 <span class="identifier">DynamicBuffer</span><span class="special">&</span> <span class="identifier">buffer_</span><span class="special">;</span> 215 216 <span class="identifier">echo_op</span><span class="special">(</span> 217 <span class="identifier">AsyncStream</span><span class="special">&</span> <span class="identifier">stream</span><span class="special">,</span> 218 <span class="identifier">DynamicBuffer</span><span class="special">&</span> <span class="identifier">buffer</span><span class="special">,</span> 219 <span class="identifier">handler_type</span><span class="special">&&</span> <span class="identifier">handler</span><span class="special">)</span> 220 <span class="special">:</span> <span class="identifier">base_type</span><span class="special">(</span> 221 <span class="identifier">std</span><span class="special">::</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">handler</span><span class="special">),</span> <a class="co" name="beast.using_io.writing_composed_operations.echo.c12" href="echo.html#beast.using_io.writing_composed_operations.echo.c13"><img src="../../../../../../../doc/src/images/callouts/4.png" alt="4" border="0"></a> 222 <span class="identifier">stream</span><span class="special">.</span><span class="identifier">get_executor</span><span class="special">())</span> <a class="co" name="beast.using_io.writing_composed_operations.echo.c14" href="echo.html#beast.using_io.writing_composed_operations.echo.c15"><img src="../../../../../../../doc/src/images/callouts/5.png" alt="5" border="0"></a> 223 <span class="special">,</span> <span class="identifier">stream_</span><span class="special">(</span><span class="identifier">stream</span><span class="special">)</span> 224 <span class="special">,</span> <span class="identifier">buffer_</span><span class="special">(</span><span class="identifier">buffer</span><span class="special">)</span> 225 <span class="special">{</span> 226 <span class="comment">// Launch the operation directly from the constructor. We</span> 227 <span class="comment">// pass `false` for `cont` to indicate that the calling</span> 228 <span class="comment">// thread does not represent a continuation of our</span> 229 <span class="comment">// asynchronous control flow.</span> 230 <span class="special">(*</span><span class="keyword">this</span><span class="special">)({},</span> <span class="number">0</span><span class="special">,</span> <span class="keyword">false</span><span class="special">);</span> 231 <span class="special">}</span> 232 233 <span class="comment">// If a newline is present in the buffer sequence, this function returns</span> 234 <span class="comment">// the number of characters from the beginning of the buffer up to the</span> 235 <span class="comment">// newline, including the newline character. Otherwise it returns zero.</span> 236 237 <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> 238 <span class="identifier">find_newline</span><span class="special">(</span><span class="keyword">typename</span> <span class="identifier">DynamicBuffer</span><span class="special">::</span><span class="identifier">const_buffers_type</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">buffers</span><span class="special">)</span> 239 <span class="special">{</span> 240 <span class="comment">// The `buffers_iterator` class template provides random-access</span> 241 <span class="comment">// iterators into a buffer sequence. Use the standard algorithm</span> 242 <span class="comment">// to look for the new line if it exists.</span> 243 244 <span class="keyword">auto</span> <span class="identifier">begin</span> <span class="special">=</span> <span class="identifier">net</span><span class="special">::</span><span class="identifier">buffers_iterator</span><span class="special"><</span> 245 <span class="keyword">typename</span> <span class="identifier">DynamicBuffer</span><span class="special">::</span><span class="identifier">const_buffers_type</span><span class="special">>::</span><span class="identifier">begin</span><span class="special">(</span><span class="identifier">buffers</span><span class="special">);</span> 246 <span class="keyword">auto</span> <span class="identifier">end</span> <span class="special">=</span> <span class="identifier">net</span><span class="special">::</span><span class="identifier">buffers_iterator</span><span class="special"><</span> 247 <span class="keyword">typename</span> <span class="identifier">DynamicBuffer</span><span class="special">::</span><span class="identifier">const_buffers_type</span><span class="special">>::</span><span class="identifier">end</span><span class="special">(</span><span class="identifier">buffers</span><span class="special">);</span> 248 <span class="keyword">auto</span> <span class="identifier">result</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">find</span><span class="special">(</span><span class="identifier">begin</span><span class="special">,</span> <span class="identifier">end</span><span class="special">,</span> <span class="char">'\n'</span><span class="special">);</span> 249 250 <span class="keyword">if</span><span class="special">(</span><span class="identifier">result</span> <span class="special">==</span> <span class="identifier">end</span><span class="special">)</span> 251 <span class="keyword">return</span> <span class="number">0</span><span class="special">;</span> <span class="comment">// not found</span> 252 253 <span class="keyword">return</span> <span class="identifier">result</span> <span class="special">+</span> <span class="number">1</span> <span class="special">-</span> <span class="identifier">begin</span><span class="special">;</span> 254 <span class="special">}</span> 255 256 <span class="comment">// This is the entry point of our completion handler. Every time an</span> 257 <span class="comment">// asynchronous operation completes, this function will be invoked.</span> 258 259 <span class="keyword">void</span> 260 <span class="keyword">operator</span><span class="special">()(</span> 261 <span class="identifier">beast</span><span class="special">::</span><span class="identifier">error_code</span> <span class="identifier">ec</span><span class="special">,</span> 262 <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">bytes_transferred</span> <span class="special">=</span> <span class="number">0</span><span class="special">,</span> 263 <span class="keyword">bool</span> <span class="identifier">cont</span> <span class="special">=</span> <span class="keyword">true</span><span class="special">)</span> <span class="comment">/*< Second and subsequent invocations will seee `cont=true`. */</span> 264 <span class="special">{</span> 265 <span class="comment">// The `reenter` keyword transfers control to the last</span> 266 <span class="comment">// yield point, or to the beginning of the scope if</span> 267 <span class="comment">// this is the first time.</span> 268 269 <span class="identifier">reenter</span><span class="special">(*</span><span class="keyword">this</span><span class="special">)</span> 270 <span class="special">{</span> 271 <span class="keyword">for</span><span class="special">(;;)</span> 272 <span class="special">{</span> 273 <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">pos</span><span class="special">;</span> 274 275 <span class="comment">// Search for a newline in the readable bytes of the buffer</span> 276 <span class="identifier">pos</span> <span class="special">=</span> <span class="identifier">find_newline</span><span class="special">(</span><span class="identifier">buffer_</span><span class="special">.</span><span class="identifier">data</span><span class="special">());</span> 277 278 <span class="comment">// If we don't have the newline, then read more</span> 279 <span class="keyword">if</span><span class="special">(</span><span class="identifier">pos</span> <span class="special">==</span> <span class="number">0</span><span class="special">)</span> 280 <span class="special">{</span> 281 <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">bytes_to_read</span><span class="special">;</span> 282 283 <span class="comment">// Determine the number of bytes to read,</span> 284 <span class="comment">// using available capacity in the buffer first.</span> 285 286 <span class="identifier">bytes_to_read</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">min</span><span class="special"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span><span class="special">>(</span> 287 <span class="identifier">std</span><span class="special">::</span><span class="identifier">max</span><span class="special"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span><span class="special">>(</span><span class="number">512</span><span class="special">,</span> <span class="comment">// under 512 is too little,</span> 288 <span class="identifier">buffer_</span><span class="special">.</span><span class="identifier">capacity</span><span class="special">()</span> <span class="special">-</span> <span class="identifier">buffer_</span><span class="special">.</span><span class="identifier">size</span><span class="special">()),</span> 289 <span class="identifier">std</span><span class="special">::</span><span class="identifier">min</span><span class="special"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span><span class="special">>(</span><span class="number">65536</span><span class="special">,</span> <span class="comment">// and over 65536 is too much.</span> 290 <span class="identifier">buffer_</span><span class="special">.</span><span class="identifier">max_size</span><span class="special">()</span> <span class="special">-</span> <span class="identifier">buffer_</span><span class="special">.</span><span class="identifier">size</span><span class="special">()));</span> 291 292 <span class="comment">// Read some data into our dynamic buffer_. We transfer</span> 293 <span class="comment">// ownership of the composed operation by using the</span> 294 <span class="comment">// `std::move(*this)` idiom. The `yield` keyword causes</span> 295 <span class="comment">// the function to return immediately after the initiating</span> 296 <span class="comment">// function returns.</span> 297 298 <span class="identifier">yield</span> <span class="identifier">stream_</span><span class="special">.</span><span class="identifier">async_read_some</span><span class="special">(</span> 299 <span class="identifier">buffer_</span><span class="special">.</span><span class="identifier">prepare</span><span class="special">(</span><span class="identifier">bytes_to_read</span><span class="special">),</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">move</span><span class="special">(*</span><span class="keyword">this</span><span class="special">));</span> 300 301 <span class="comment">// After the `async_read_some` completes, control is</span> 302 <span class="comment">// transferred to this line by the `reenter` keyword.</span> 303 304 <span class="comment">// Move the bytes read from the writable area to the</span> 305 <span class="comment">// readable area.</span> 306 307 <span class="identifier">buffer_</span><span class="special">.</span><span class="identifier">commit</span><span class="special">(</span><span class="identifier">bytes_transferred</span><span class="special">);</span> 308 309 <span class="comment">// If an error occurs, deliver it to the caller's completion handler.</span> 310 <span class="keyword">if</span><span class="special">(</span><span class="identifier">ec</span><span class="special">)</span> 311 <span class="keyword">break</span><span class="special">;</span> 312 313 <span class="comment">// Keep looping until we get the newline</span> 314 <span class="keyword">continue</span><span class="special">;</span> 315 <span class="special">}</span> 316 317 <span class="comment">// We have our newline, so send the first `pos` bytes of the</span> 318 <span class="comment">// buffers. The function `buffers_prefix` returns the front part</span> 319 <span class="comment">// of the buffers we want.</span> 320 321 <span class="identifier">yield</span> <span class="identifier">net</span><span class="special">::</span><span class="identifier">async_write</span><span class="special">(</span><span class="identifier">stream_</span><span class="special">,</span> 322 <span class="identifier">beast</span><span class="special">::</span><span class="identifier">buffers_prefix</span><span class="special">(</span><span class="identifier">pos</span><span class="special">,</span> <span class="identifier">buffer_</span><span class="special">.</span><span class="identifier">data</span><span class="special">()),</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">move</span><span class="special">(*</span><span class="keyword">this</span><span class="special">));</span> 323 324 <span class="comment">// After the `async_write` completes, our completion handler will</span> 325 <span class="comment">// be invoked with the error and the number of bytes transferred,</span> 326 <span class="comment">// and the `reenter` statement above will cause control to jump</span> 327 <span class="comment">// to the following line. The variable `pos` is no longer valid</span> 328 <span class="comment">// (remember that we returned from the function using `yield` above)</span> 329 <span class="comment">// but we can use `bytes_transferred` to know how much of the buffer</span> 330 <span class="comment">// to consume. With "real" coroutines this will be easier and more</span> 331 <span class="comment">// natural.</span> 332 333 <span class="identifier">buffer_</span><span class="special">.</span><span class="identifier">consume</span><span class="special">(</span><span class="identifier">bytes_transferred</span><span class="special">);</span> 334 335 <span class="comment">// The loop terminates here, and we will either deliver a</span> 336 <span class="comment">// successful result or an error to the caller's completion handler.</span> 337 338 <span class="keyword">break</span><span class="special">;</span> 339 <span class="special">}</span> 340 341 <span class="comment">// When a composed operation completes immediately, it must not</span> 342 <span class="comment">// directly invoke the completion handler otherwise it could</span> 343 <span class="comment">// lead to unfairness, starvation, or stack overflow. Therefore,</span> 344 <span class="comment">// if cont == false (meaning, that the call stack still includes</span> 345 <span class="comment">// the frame of the initiating function) then we need to use</span> 346 <span class="comment">// `net::post` to cause us to be called again after the initiating</span> 347 <span class="comment">// function. The function `async_base::invoke` takes care of</span> 348 <span class="comment">// calling the final completion handler, using post if the</span> 349 <span class="comment">// first argument is false, otherwise invoking it directly.</span> 350 351 <span class="keyword">this</span><span class="special">-></span><span class="identifier">complete</span><span class="special">(</span><span class="identifier">cont</span><span class="special">,</span> <span class="identifier">ec</span><span class="special">);</span> 352 <span class="special">}</span> 353 <span class="special">}</span> 354 <span class="special">};</span> 355 356 <span class="comment">// Create the composed operation and launch it. This is a constructor</span> 357 <span class="comment">// call followed by invocation of operator(). We use BOOST_ASIO_HANDLER_TYPE</span> 358 <span class="comment">// to convert the completion token into the correct handler type,</span> 359 <span class="comment">// allowing user-defined specializations of the async_result template</span> 360 <span class="comment">// to be used.</span> 361 362 <span class="identifier">echo_op</span><span class="special">(</span><span class="identifier">stream</span><span class="special">,</span> <span class="identifier">buffer</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">init</span><span class="special">.</span><span class="identifier">completion_handler</span><span class="special">));</span> 363 364 <span class="comment">// This hook lets the caller see a return value when appropriate.</span> 365 <span class="comment">// For example this might return std::future<error_code> if</span> 366 <span class="comment">// CompletionToken is net::use_future, or this might</span> 367 <span class="comment">// return an error code if CompletionToken specifies a coroutine.</span> 368 369 <span class="keyword">return</span> <span class="identifier">init</span><span class="special">.</span><span class="identifier">result</span><span class="special">.</span><span class="identifier">get</span><span class="special">();</span> 370<span class="special">}</span> 371 372<span class="comment">// Including this file undefines the macros used by the stackless fauxroutines.</span> 373<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">asio</span><span class="special">/</span><span class="identifier">unyield</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> 374</pre> 375<div class="calloutlist"><table border="0" summary="Callout list"> 376<tr> 377<td width="5%" valign="top" align="left"><p><a name="beast.using_io.writing_composed_operations.echo.c7"></a><a href="#beast.using_io.writing_composed_operations.echo.c6"><img src="../../../../../../../doc/src/images/callouts/1.png" alt="1" border="0"></a> </p></td> 378<td valign="top" align="left"><p> 379 The completion handler signature goes here 380 </p></td> 381</tr> 382<tr> 383<td width="5%" valign="top" align="left"><p><a name="beast.using_io.writing_composed_operations.echo.c9"></a><a href="#beast.using_io.writing_composed_operations.echo.c8"><img src="../../../../../../../doc/src/images/callouts/2.png" alt="2" border="0"></a> </p></td> 384<td valign="top" align="left"><p> 385 The type of the completion handler obtained from the token 386 </p></td> 387</tr> 388<tr> 389<td width="5%" valign="top" align="left"><p><a name="beast.using_io.writing_composed_operations.echo.c11"></a><a href="#beast.using_io.writing_composed_operations.echo.c10"><img src="../../../../../../../doc/src/images/callouts/3.png" alt="3" border="0"></a> </p></td> 390<td valign="top" align="left"><p> 391 The type of executor used by the stream to dispatch asynchronous operations 392 </p></td> 393</tr> 394<tr> 395<td width="5%" valign="top" align="left"><p><a name="beast.using_io.writing_composed_operations.echo.c13"></a><a href="#beast.using_io.writing_composed_operations.echo.c12"><img src="../../../../../../../doc/src/images/callouts/4.png" alt="4" border="0"></a> </p></td> 396<td valign="top" align="left"><p> 397 The <code class="computeroutput"><span class="identifier">async_base</span></code> helper 398 takes ownership of the handler, 399 </p></td> 400</tr> 401<tr> 402<td width="5%" valign="top" align="left"><p><a name="beast.using_io.writing_composed_operations.echo.c15"></a><a href="#beast.using_io.writing_composed_operations.echo.c14"><img src="../../../../../../../doc/src/images/callouts/5.png" alt="5" border="0"></a> </p></td> 403<td valign="top" align="left"><p> 404 and also needs to know which executor to use. 405 </p></td> 406</tr> 407</table></div> 408<p> 409 There are some common mistakes that should be avoided when writing composed 410 operations: 411 </p> 412<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "> 413<li class="listitem"> 414 Type erasing the final handler. This will cause undefined behavior. 415 </li> 416<li class="listitem"> 417 Forgetting to include a return statement after calling an initiating 418 function. 419 </li> 420<li class="listitem"> 421 Calling a synchronous function by accident. In general composed operations 422 should not block for long periods of time, since this ties up a thread 423 running on the <a href="../../../../../../../doc/html/boost_asio/reference/io_context.html" target="_top"><code class="computeroutput"><span class="identifier">net</span><span class="special">::</span><span class="identifier">io_context</span></code></a>. 424 </li> 425<li class="listitem"> 426 Forgetting to provide <code class="computeroutput"><span class="identifier">executor_type</span></code> 427 and <code class="computeroutput"><span class="identifier">get_executor</span></code> for 428 the composed operation. This will cause undefined behavior. For example, 429 if someone calls the initiating function with a strand-wrapped function 430 object, and there is more than thread running on the <a href="../../../../../../../doc/html/boost_asio/reference/io_context.html" target="_top"><code class="computeroutput"><span class="identifier">net</span><span class="special">::</span><span class="identifier">io_context</span></code></a>, the underlying 431 stream may be accessed in a fashion that violates safety guarantees. 432 Beast provides class templates to take care of this boilerplate for 433 you. 434 </li> 435<li class="listitem"> 436 Forgetting to create an object of type <a href="../../../../../../../doc/html/boost_asio/reference/executor_work_guard.html" target="_top"><code class="computeroutput"><span class="identifier">net</span><span class="special">::</span><span class="identifier">executor_work_guard</span></code></a> with 437 the type of executor returned by the stream's <code class="computeroutput"><span class="identifier">get_executor</span></code> 438 member function. 439 </li> 440<li class="listitem"> 441 For operations which complete immediately (i.e. without calling an 442 intermediate initiating function), forgetting to use <a href="../../../../../../../doc/html/boost_asio/reference/post.html" target="_top"><code class="computeroutput"><span class="identifier">net</span><span class="special">::</span><span class="identifier">post</span></code></a> to invoke the final 443 handler. This breaks the following initiating function guarantee: 444 <span class="emphasis"><em>Regardless of whether the asynchronous operation completes 445 immediately or not, the handler will not be invoked from within this 446 function. Invocation of the handler will be performed in a manner equivalent 447 to using <a href="../../../../../../../doc/html/boost_asio/reference/post.html" target="_top"><code class="computeroutput"><span class="identifier">net</span><span class="special">::</span><span class="identifier">post</span></code></a></em></span>. The function 448 <a class="link" href="../../ref/boost__beast__bind_handler.html" title="bind_handler"><code class="computeroutput"><span class="identifier">bind_handler</span></code></a> is provided for 449 this purpose. 450 </li> 451</ul></div> 452<p> 453 The listing for a complete, runnable version of this example is in <a href="../../../../../example/echo-op/echo_op.cpp" target="_top">echo_op.cpp</a>. 454 </p> 455</div> 456<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr> 457<td align="left"></td> 458<td align="right"><div class="copyright-footer">Copyright © 2016-2019 Vinnie 459 Falco<p> 460 Distributed under the Boost Software License, Version 1.0. (See accompanying 461 file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>) 462 </p> 463</div></td> 464</tr></table> 465<hr> 466<div class="spirit-nav"> 467<a accesskey="p" href="../writing_composed_operations.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../writing_composed_operations.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="detect_ssl.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a> 468</div> 469</body> 470</html> 471