1<html> 2<head> 3<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 4<title>Timeouts </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="../using_io.html" title="Networking"> 9<link rel="prev" href="stream_types.html" title="Streams"> 10<link rel="next" href="rate_limiting.html" title="Rate Limiting "> 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="stream_types.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../using_io.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="rate_limiting.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a> 24</div> 25<div class="section"> 26<div class="titlepage"><div><div><h3 class="title"> 27<a name="beast.using_io.timeouts"></a><a class="link" href="timeouts.html" title="Timeouts ">Timeouts </a> 28</h3></div></div></div> 29<p> 30 Network programs must handle adverse connection conditions; the most common 31 is that a connected peer goes offline unexpectedly. Protocols have no way 32 of identifying this reliably: the peer is offline after all, and unable to 33 send a message announcing the absence. A peer can go offline for various 34 reasons: 35 </p> 36<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "> 37<li class="listitem"> 38 The peer experiences a power loss 39 </li> 40<li class="listitem"> 41 The peer becomes disconnected from the network 42 </li> 43<li class="listitem"> 44 The local host becomes disconnected from the network 45 </li> 46<li class="listitem"> 47 The network itself becomes unavailable 48 </li> 49</ul></div> 50<p> 51 To determine when a peer is offline or idle, a program will implement a 52 <a href="https://en.wikipedia.org/wiki/Timeout_(computing)" target="_top">timeout</a> 53 algorithm, which closes the connection after a specified amount of time if 54 some condition is met. For example, if no data is received for the duration. 55 A timeout may be used to: 56 </p> 57<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "> 58<li class="listitem"> 59 Drop malicious or poorly performing hosts 60 </li> 61<li class="listitem"> 62 Close idle connections to free up resources 63 </li> 64<li class="listitem"> 65 Determine if a peer is offline or no longer available 66 </li> 67</ul></div> 68<p> 69 Traditionally, programs use a <a href="../../../../../../doc/html/boost_asio/reference/steady_timer.html" target="_top"><code class="computeroutput"><span class="identifier">net</span><span class="special">::</span><span class="identifier">steady_timer</span></code></a> 70 to determine when a timeout occurs, and then call <a href="../../../../../../doc/html/boost_asio/reference/basic_socket/close/overload2.html" target="_top"><code class="computeroutput"><span class="identifier">close</span></code></a> on the socket to release 71 the resources. The complexity of managing a separate timer is often a source 72 of <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1269r0.html#timers" target="_top">frustration</a> 73 for non-experts. 74 </p> 75<div class="note"><table border="0" summary="Note"> 76<tr> 77<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../../../../doc/src/images/note.png"></td> 78<th align="left">Note</th> 79</tr> 80<tr><td align="left" valign="top"><p> 81 For portability reasons, networking does not provide timeouts or cancellation 82 features for synchronous stream operations. 83 </p></td></tr> 84</table></div> 85<p> 86 To simplify the handling of timeouts, these provided types wrap a <a href="../../../../../../doc/html/boost_asio/reference/basic_stream_socket.html" target="_top"><code class="computeroutput"><span class="identifier">net</span><span class="special">::</span><span class="identifier">basic_stream_socket</span></code></a> 87 to provide additional features: 88 </p> 89<div class="informaltable"><table class="table"> 90<colgroup> 91<col> 92<col> 93</colgroup> 94<thead><tr> 95<th> 96 <p> 97 Name 98 </p> 99 </th> 100<th> 101 <p> 102 Features 103 </p> 104 </th> 105</tr></thead> 106<tbody> 107<tr> 108<td> 109 <p> 110 <a class="link" href="../ref/boost__beast__tcp_stream.html" title="tcp_stream"><code class="computeroutput"><span class="identifier">tcp_stream</span></code></a> 111 </p> 112 </td> 113<td> 114 <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "> 115<li class="listitem"> 116 Timeouts for logical operations 117 </li> 118<li class="listitem"> 119 <a href="../../../../../../doc/html/boost_asio/reference/ip__tcp.html" target="_top"><code class="computeroutput"><span class="identifier">net</span><span class="special">::</span><span class="identifier">ip</span><span class="special">::</span><span class="identifier">tcp</span></code></a> protocol 120 </li> 121<li class="listitem"> 122 <a href="../../../../../../doc/html/boost_asio/reference/executor.html" target="_top"><code class="computeroutput"><span class="identifier">net</span><span class="special">::</span><span class="identifier">executor</span></code></a> executor 123 </li> 124<li class="listitem"> 125 <a class="link" href="../ref/boost__beast__unlimited_rate_policy.html" title="unlimited_rate_policy"><code class="computeroutput"><span class="identifier">unlimited_rate_policy</span></code></a> 126 rate limits 127 </li> 128</ul></div> 129 </td> 130</tr> 131<tr> 132<td> 133 <p> 134 <a class="link" href="../ref/boost__beast__basic_stream.html" title="basic_stream"><code class="computeroutput"><span class="identifier">basic_stream</span></code></a> 135 </p> 136 </td> 137<td> 138 <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "> 139<li class="listitem"> 140 Timeouts for logical operations 141 </li> 142<li class="listitem"> 143 Configurable <a href="../../../../../../doc/html/boost_asio/reference/Protocol.html" target="_top"><span class="emphasis"><em>Protocol</em></span></a> 144 type 145 </li> 146<li class="listitem"> 147 Configurable <a href="../../../../../../doc/html/boost_asio/reference/Executor1.html" target="_top"><span class="emphasis"><em>Executor</em></span></a> 148 type 149 </li> 150<li class="listitem"> 151 Configurable <a class="link" href="../concepts/RatePolicy.html" title="RatePolicy"><span class="emphasis"><em>RatePolicy</em></span></a> 152 type 153 </li> 154</ul></div> 155 </td> 156</tr> 157</tbody> 158</table></div> 159<h5> 160<a name="beast.using_io.timeouts.h0"></a> 161 <span class="phrase"><a name="beast.using_io.timeouts.construction"></a></span><a class="link" href="timeouts.html#beast.using_io.timeouts.construction">Construction</a> 162 </h5> 163<p> 164 The <code class="computeroutput"><span class="identifier">tcp_stream</span></code> is designed 165 as a replacement for <a href="../../../../../../doc/html/boost_asio/reference/ip__tcp/socket.html" target="_top"><code class="computeroutput"><span class="identifier">net</span><span class="special">::</span><span class="identifier">ip</span><span class="special">::</span><span class="identifier">tcp</span><span class="special">::</span><span class="identifier">socket</span></code></a>. Any program which currently 166 uses a socket, can switch to a <code class="computeroutput"><span class="identifier">tcp_stream</span></code> 167 and achieve the features above (although some interfaces are different, see 168 below). Networking now allows I/O objects to construct with any instance 169 of <a href="../../../../../../doc/html/boost_asio/reference/ExecutionContext.html" target="_top"><span class="emphasis"><em>ExecutionContext</em></span></a> 170 or <a href="../../../../../../doc/html/boost_asio/reference/Executor1.html" target="_top"><span class="emphasis"><em>Executor</em></span></a> 171 objects. Here we construct a stream which uses a particular I/O context to 172 dispatch completion handlers: 173 </p> 174<pre class="programlisting"><span class="comment">// `ioc` will be used to dispatch completion handlers</span> 175<span class="identifier">tcp_stream</span> <span class="identifier">stream</span><span class="special">(</span><span class="identifier">ioc</span><span class="special">);</span> 176</pre> 177<p> 178 Alternatively, we can construct the stream from an executor: 179 </p> 180<pre class="programlisting"><span class="comment">// The resolver is used to look up the IP addresses for a domain name</span> 181<span class="identifier">net</span><span class="special">::</span><span class="identifier">ip</span><span class="special">::</span><span class="identifier">tcp</span><span class="special">::</span><span class="identifier">resolver</span> <span class="identifier">resolver</span><span class="special">(</span><span class="identifier">ioc</span><span class="special">);</span> 182 183<span class="comment">// The stream will use the same executor as the resolver</span> 184<span class="identifier">tcp_stream</span> <span class="identifier">stream</span><span class="special">(</span><span class="identifier">resolver</span><span class="special">.</span><span class="identifier">get_executor</span><span class="special">());</span> 185</pre> 186<p> 187 The function <a href="../../../../../../doc/html/boost_asio/reference/make_strand.html" target="_top"><code class="computeroutput"><span class="identifier">make_strand</span></code></a> returns a strand constructed 188 from an execution context or executor. When a <a href="../../../../../../doc/html/boost_asio/reference/strand.html" target="_top"><code class="computeroutput"><span class="identifier">net</span><span class="special">::</span><span class="identifier">strand</span></code></a> 189 is chosen for the stream's executor, all completion handlers which do not 190 already have an associated executor will use the strand. This is both a notational 191 convenience (no need for <code class="computeroutput"><span class="identifier">strand</span><span class="special">::</span><span class="identifier">wrap</span></code> 192 or <code class="computeroutput"><span class="identifier">bind_executor</span></code> at call 193 sites) and a measure of safety, as it is no longer possible to forget to 194 use the strand. 195 </p> 196<pre class="programlisting"><span class="comment">// The strand will be used to invoke all completion handlers</span> 197<span class="identifier">tcp_stream</span> <span class="identifier">stream</span><span class="special">(</span><span class="identifier">net</span><span class="special">::</span><span class="identifier">make_strand</span><span class="special">(</span><span class="identifier">ioc</span><span class="special">));</span> 198</pre> 199<h5> 200<a name="beast.using_io.timeouts.h1"></a> 201 <span class="phrase"><a name="beast.using_io.timeouts.connecting"></a></span><a class="link" href="timeouts.html#beast.using_io.timeouts.connecting">Connecting</a> 202 </h5> 203<p> 204 Before data can be exchanged, the stream needs to be connected to a peer. 205 The following code sets a timeout for an asynchronous connect operation. 206 In Beast, functions to connect to a range of endpoints (such as the range 207 returned by <a href="../../../../../../doc/html/boost_asio/reference/ip__basic_resolver/resolve/overload3.html" target="_top"><code class="computeroutput"><span class="identifier">net</span><span class="special">::</span><span class="identifier">ip</span><span class="special">::</span><span class="identifier">tcp</span><span class="special">::</span><span class="identifier">resolver</span><span class="special">::</span><span class="identifier">resolve</span></code></a>) are members of the class 208 rather than free functions such as <a href="../../../../../../doc/html/boost_asio/reference/async_connect.html" target="_top"><code class="computeroutput"><span class="identifier">net</span><span class="special">::</span><span class="identifier">async_connect</span></code></a>. 209 </p> 210<pre class="programlisting"><span class="comment">// Set the logical operation timer to 30 seconds</span> 211<span class="identifier">stream</span><span class="special">.</span><span class="identifier">expires_after</span> <span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">chrono</span><span class="special">::</span><span class="identifier">seconds</span><span class="special">(</span><span class="number">30</span><span class="special">));</span> 212 213<span class="comment">// If the connection is not established within 30 seconds,</span> 214<span class="comment">// the operation will be canceled and the handler will receive</span> 215<span class="comment">// error::timeout as the error code.</span> 216 217<span class="identifier">stream</span><span class="special">.</span><span class="identifier">async_connect</span><span class="special">(</span><span class="identifier">resolver</span><span class="special">.</span><span class="identifier">resolve</span><span class="special">(</span><span class="string">"www.example.com"</span><span class="special">,</span> <span class="string">"http"</span><span class="special">),</span> 218 <span class="special">[](</span><span class="identifier">error_code</span> <span class="identifier">ec</span><span class="special">,</span> <span class="identifier">net</span><span class="special">::</span><span class="identifier">ip</span><span class="special">::</span><span class="identifier">tcp</span><span class="special">::</span><span class="identifier">endpoint</span> <span class="identifier">ep</span><span class="special">)</span> 219 <span class="special">{</span> 220 <span class="keyword">if</span><span class="special">(</span><span class="identifier">ec</span> <span class="special">==</span> <span class="identifier">error</span><span class="special">::</span><span class="identifier">timeout</span><span class="special">)</span> 221 <span class="identifier">std</span><span class="special">::</span><span class="identifier">cerr</span> <span class="special"><<</span> <span class="string">"async_connect took too long\n"</span><span class="special">;</span> 222 <span class="keyword">else</span> <span class="keyword">if</span><span class="special">(!</span> <span class="identifier">ec</span><span class="special">)</span> 223 <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"Connected to "</span> <span class="special"><<</span> <span class="identifier">ep</span> <span class="special"><<</span> <span class="string">"\n"</span><span class="special">;</span> 224 <span class="special">}</span> 225<span class="special">);</span> 226 227<span class="comment">// The timer is still running. If we don't want the next</span> 228<span class="comment">// operation to time out 30 seconds relative to the previous</span> 229<span class="comment">// call to `expires_after`, we need to turn it off before</span> 230<span class="comment">// starting another asynchronous operation.</span> 231 232<span class="identifier">stream</span><span class="special">.</span><span class="identifier">expires_never</span><span class="special">();</span> 233</pre> 234<p> 235 A server will use an acceptor bound to a particular IP address and port to 236 listen to and receive incoming connection requests. The acceptor returns 237 an ordinary socket. A <code class="computeroutput"><span class="identifier">tcp_stream</span></code> 238 can be move-constructed from the underlying <code class="computeroutput"><span class="identifier">basic_stream_socket</span></code> 239 thusly: 240 </p> 241<pre class="programlisting"><span class="comment">// The acceptor is used to listen and accept incoming connections.</span> 242<span class="comment">// We construct the acceptor to use a new strand, and listen</span> 243<span class="comment">// on the loopback address with an operating-system assigned port.</span> 244 245<span class="identifier">net</span><span class="special">::</span><span class="identifier">ip</span><span class="special">::</span><span class="identifier">tcp</span><span class="special">::</span><span class="identifier">acceptor</span> <span class="identifier">acceptor</span><span class="special">(</span><span class="identifier">net</span><span class="special">::</span><span class="identifier">make_strand</span><span class="special">(</span><span class="identifier">ioc</span><span class="special">));</span> 246<span class="identifier">acceptor</span><span class="special">.</span><span class="identifier">bind</span><span class="special">(</span><span class="identifier">net</span><span class="special">::</span><span class="identifier">ip</span><span class="special">::</span><span class="identifier">tcp</span><span class="special">::</span><span class="identifier">endpoint</span><span class="special">(</span><span class="identifier">net</span><span class="special">::</span><span class="identifier">ip</span><span class="special">::</span><span class="identifier">make_address_v4</span><span class="special">(</span><span class="string">"127.0.0.1"</span><span class="special">),</span> <span class="number">0</span><span class="special">));</span> 247<span class="identifier">acceptor</span><span class="special">.</span><span class="identifier">listen</span><span class="special">(</span><span class="number">0</span><span class="special">);</span> 248 249<span class="comment">// This blocks until a new incoming connection is established.</span> 250<span class="comment">// Upon success, the function returns a new socket which is</span> 251<span class="comment">// connected to the peer. The socket will have its own executor,</span> 252<span class="comment">// which in the call below is a new strand for the I/O context.</span> 253 254<span class="identifier">net</span><span class="special">::</span><span class="identifier">ip</span><span class="special">::</span><span class="identifier">tcp</span><span class="special">::</span><span class="identifier">socket</span> <span class="identifier">s</span> <span class="special">=</span> <span class="identifier">acceptor</span><span class="special">.</span><span class="identifier">accept</span><span class="special">(</span><span class="identifier">net</span><span class="special">::</span><span class="identifier">make_strand</span><span class="special">(</span><span class="identifier">ioc</span><span class="special">));</span> 255 256<span class="comment">// Construct a new tcp_stream from the connected socket.</span> 257<span class="comment">// The stream will use the strand created when the connection</span> 258<span class="comment">// was accepted.</span> 259 260<span class="identifier">tcp_stream</span> <span class="identifier">stream</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">s</span><span class="special">));</span> 261</pre> 262<h5> 263<a name="beast.using_io.timeouts.h2"></a> 264 <span class="phrase"><a name="beast.using_io.timeouts.reading_and_writing"></a></span><a class="link" href="timeouts.html#beast.using_io.timeouts.reading_and_writing">Reading 265 and Writing</a> 266 </h5> 267<p> 268 Timeouts apply to the logical operation, expressed as a series of asynchronous 269 calls, rather than just the next call. This code reads a line from the stream 270 and writes it back. Both the read and the write must complete within 30 seconds 271 from when the timeout was set; the timer is not reset between operations. 272 </p> 273<pre class="programlisting"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">s</span><span class="special">;</span> 274 275<span class="comment">// Set the logical operation timer to 30 seconds.</span> 276<span class="identifier">stream</span><span class="special">.</span><span class="identifier">expires_after</span> <span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">chrono</span><span class="special">::</span><span class="identifier">seconds</span><span class="special">(</span><span class="number">30</span><span class="special">));</span> 277 278<span class="comment">// Read a line from the stream into the string.</span> 279<span class="identifier">net</span><span class="special">::</span><span class="identifier">async_read_until</span><span class="special">(</span><span class="identifier">stream</span><span class="special">,</span> <span class="identifier">net</span><span class="special">::</span><span class="identifier">dynamic_buffer</span><span class="special">(</span><span class="identifier">s</span><span class="special">),</span> <span class="char">'\n'</span><span class="special">,</span> 280 <span class="special">[&</span><span class="identifier">s</span><span class="special">,</span> <span class="special">&</span><span class="identifier">stream</span><span class="special">](</span><span class="identifier">error_code</span> <span class="identifier">ec</span><span class="special">,</span> <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> 281 <span class="special">{</span> 282 <span class="keyword">if</span><span class="special">(</span><span class="identifier">ec</span><span class="special">)</span> 283 <span class="keyword">return</span><span class="special">;</span> 284 285 <span class="comment">// read_until can read past the '\n', these will end up in</span> 286 <span class="comment">// our buffer but we don't want to echo those extra received</span> 287 <span class="comment">// bytes. `bytes_transferred` will be the number of bytes</span> 288 <span class="comment">// up to and including the '\n'. We use `buffers_prefix` so</span> 289 <span class="comment">// that extra data is not written.</span> 290 291 <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> <span class="identifier">buffers_prefix</span><span class="special">(</span><span class="identifier">bytes_transferred</span><span class="special">,</span> <span class="identifier">net</span><span class="special">::</span><span class="identifier">buffer</span><span class="special">(</span><span class="identifier">s</span><span class="special">)),</span> 292 <span class="special">[&</span><span class="identifier">s</span><span class="special">](</span><span class="identifier">error_code</span> <span class="identifier">ec</span><span class="special">,</span> <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> 293 <span class="special">{</span> 294 <span class="comment">// Consume the line from the buffer</span> 295 <span class="identifier">s</span><span class="special">.</span><span class="identifier">erase</span><span class="special">(</span><span class="identifier">s</span><span class="special">.</span><span class="identifier">begin</span><span class="special">(),</span> <span class="identifier">s</span><span class="special">.</span><span class="identifier">begin</span><span class="special">()</span> <span class="special">+</span> <span class="identifier">bytes_transferred</span><span class="special">);</span> 296 297 <span class="keyword">if</span><span class="special">(</span><span class="identifier">ec</span><span class="special">)</span> 298 <span class="identifier">std</span><span class="special">::</span><span class="identifier">cerr</span> <span class="special"><<</span> <span class="string">"Error: "</span> <span class="special"><<</span> <span class="identifier">ec</span><span class="special">.</span><span class="identifier">message</span><span class="special">()</span> <span class="special"><<</span> <span class="string">"\n"</span><span class="special">;</span> 299 <span class="special">});</span> 300 <span class="special">});</span> 301</pre> 302<p> 303 Since reads and writes can take place concurrently, it is possible to have 304 two simultaneous logical operations where each operation either only reads, 305 or only writes. The beginning of a new read or write operation will use the 306 most recently set timeout. This will not affect operations that are already 307 outstanding. 308 </p> 309<pre class="programlisting"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">s1</span><span class="special">;</span> 310<span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">s2</span><span class="special">;</span> 311 312<span class="comment">// Set the logical operation timer to 15 seconds.</span> 313<span class="identifier">stream</span><span class="special">.</span><span class="identifier">expires_after</span> <span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">chrono</span><span class="special">::</span><span class="identifier">seconds</span><span class="special">(</span><span class="number">15</span><span class="special">));</span> 314 315<span class="comment">// Read another line from the stream into our dynamic buffer.</span> 316<span class="comment">// The operation will time out after 15 seconds.</span> 317 318<span class="identifier">net</span><span class="special">::</span><span class="identifier">async_read_until</span><span class="special">(</span><span class="identifier">stream</span><span class="special">,</span> <span class="identifier">net</span><span class="special">::</span><span class="identifier">dynamic_buffer</span><span class="special">(</span><span class="identifier">s1</span><span class="special">),</span> <span class="char">'\n'</span><span class="special">,</span> <span class="identifier">handler</span><span class="special">);</span> 319 320<span class="comment">// Set the logical operation timer to 30 seconds.</span> 321<span class="identifier">stream</span><span class="special">.</span><span class="identifier">expires_after</span> <span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">chrono</span><span class="special">::</span><span class="identifier">seconds</span><span class="special">(</span><span class="number">30</span><span class="special">));</span> 322 323<span class="comment">// Write the contents of the other buffer.</span> 324<span class="comment">// This operation will time out after 30 seconds.</span> 325 326<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> <span class="identifier">net</span><span class="special">::</span><span class="identifier">buffer</span><span class="special">(</span><span class="identifier">s2</span><span class="special">),</span> <span class="identifier">handler</span><span class="special">);</span> 327</pre> 328<p> 329 When a timeout is set, it cancels any previous read or write timeout for 330 which no outstanding operation is in progress. Algorithms which loop over 331 logical operations simply need to set the timeout once before the logical 332 operation, it is not necessary to call <code class="computeroutput"><span class="identifier">expires_never</span></code> 333 in this case. Here we implement an algorithm which continuously echoes lines 334 back, with a timeout. This example is implemented as a complete function. 335 </p> 336<pre class="programlisting"><span class="comment">/** This function echoes back received lines from a peer, with a timeout. 337 338 The algorithm terminates upon any error (including timeout). 339*/</span> 340<span class="keyword">template</span> <span class="special"><</span><span class="keyword">class</span> <span class="identifier">Protocol</span><span class="special">,</span> <span class="keyword">class</span> <span class="identifier">Executor</span><span class="special">></span> 341<span class="keyword">void</span> <span class="identifier">do_async_echo</span> <span class="special">(</span><span class="identifier">basic_stream</span><span class="special"><</span><span class="identifier">Protocol</span><span class="special">,</span> <span class="identifier">Executor</span><span class="special">>&</span> <span class="identifier">stream</span><span class="special">)</span> 342<span class="special">{</span> 343 <span class="comment">// This object will hold our state when reading the line.</span> 344 345 <span class="keyword">struct</span> <span class="identifier">echo_line</span> 346 <span class="special">{</span> 347 <span class="identifier">basic_stream</span><span class="special"><</span><span class="identifier">Protocol</span><span class="special">,</span> <span class="identifier">Executor</span><span class="special">>&</span> <span class="identifier">stream</span><span class="special">;</span> 348 349 <span class="comment">// The shared pointer is used to extend the lifetime of the</span> 350 <span class="comment">// string until the last asynchronous operation completes.</span> 351 <span class="identifier">std</span><span class="special">::</span><span class="identifier">shared_ptr</span><span class="special"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">></span> <span class="identifier">s</span><span class="special">;</span> 352 353 <span class="comment">// This starts a new operation to read and echo a line</span> 354 <span class="keyword">void</span> <span class="keyword">operator</span><span class="special">()()</span> 355 <span class="special">{</span> 356 <span class="comment">// If a line is not sent and received within 30 seconds, then</span> 357 <span class="comment">// the connection will be closed and this algorithm will terminate.</span> 358 359 <span class="identifier">stream</span><span class="special">.</span><span class="identifier">expires_after</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">chrono</span><span class="special">::</span><span class="identifier">seconds</span><span class="special">(</span><span class="number">30</span><span class="special">));</span> 360 361 <span class="comment">// Read a line from the stream into our dynamic buffer, with a timeout</span> 362 <span class="identifier">net</span><span class="special">::</span><span class="identifier">async_read_until</span><span class="special">(</span><span class="identifier">stream</span><span class="special">,</span> <span class="identifier">net</span><span class="special">::</span><span class="identifier">dynamic_buffer</span><span class="special">(*</span><span class="identifier">s</span><span class="special">),</span> <span class="char">'\n'</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> 363 <span class="special">}</span> 364 365 <span class="comment">// This function is called when the read completes</span> 366 <span class="keyword">void</span> <span class="keyword">operator</span><span class="special">()(</span><span class="identifier">error_code</span> <span class="identifier">ec</span><span class="special">,</span> <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> 367 <span class="special">{</span> 368 <span class="keyword">if</span><span class="special">(</span><span class="identifier">ec</span><span class="special">)</span> 369 <span class="keyword">return</span><span class="special">;</span> 370 371 <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> <span class="identifier">buffers_prefix</span><span class="special">(</span><span class="identifier">bytes_transferred</span><span class="special">,</span> <span class="identifier">net</span><span class="special">::</span><span class="identifier">buffer</span><span class="special">(*</span><span class="identifier">s</span><span class="special">)),</span> 372 <span class="special">[</span><span class="keyword">this</span><span class="special">](</span><span class="identifier">error_code</span> <span class="identifier">ec</span><span class="special">,</span> <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> 373 <span class="special">{</span> 374 <span class="identifier">s</span><span class="special">-></span><span class="identifier">erase</span><span class="special">(</span><span class="identifier">s</span><span class="special">-></span><span class="identifier">begin</span><span class="special">(),</span> <span class="identifier">s</span><span class="special">-></span><span class="identifier">begin</span><span class="special">()</span> <span class="special">+</span> <span class="identifier">bytes_transferred</span><span class="special">);</span> 375 376 <span class="keyword">if</span><span class="special">(!</span> <span class="identifier">ec</span><span class="special">)</span> 377 <span class="special">{</span> 378 <span class="comment">// Run this algorithm again</span> 379 <span class="identifier">echo_line</span><span class="special">{</span><span class="identifier">stream</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">s</span><span class="special">)}();</span> 380 <span class="special">}</span> 381 <span class="keyword">else</span> 382 <span class="special">{</span> 383 <span class="identifier">std</span><span class="special">::</span><span class="identifier">cerr</span> <span class="special"><<</span> <span class="string">"Error: "</span> <span class="special"><<</span> <span class="identifier">ec</span><span class="special">.</span><span class="identifier">message</span><span class="special">()</span> <span class="special"><<</span> <span class="string">"\n"</span><span class="special">;</span> 384 <span class="special">}</span> 385 <span class="special">});</span> 386 <span class="special">}</span> 387 <span class="special">};</span> 388 389 <span class="comment">// Create the operation and run it</span> 390 <span class="identifier">echo_line</span><span class="special">{</span><span class="identifier">stream</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">make_shared</span><span class="special"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">>()}();</span> 391<span class="special">}</span> 392</pre> 393<h5> 394<a name="beast.using_io.timeouts.h3"></a> 395 <span class="phrase"><a name="beast.using_io.timeouts.https_get"></a></span><a class="link" href="timeouts.html#beast.using_io.timeouts.https_get">https_get</a> 396 </h5> 397<p> 398 It is important to note that all of the examples thus far which perform reads 399 and writes with a timeout, make use of the existing networking stream algorithms. 400 As these algorithms are written generically to work with any object meeting 401 the stream requirements, they transparently support timeouts when used with 402 <code class="computeroutput"><span class="identifier">tcp_stream</span></code>. This can be used 403 to enable timeouts for stream wrappers that do not currently support timeouts. 404 </p> 405<p> 406 The following code establishes an encrypted connection, writes an HTTP request, 407 reads the HTTP response, and closes the connection gracefully. If these operations 408 take longer than 30 seconds total, a timeout occurs. This code is intended 409 to show how <code class="computeroutput"><span class="identifier">tcp_stream</span></code> can 410 be used to enable timeouts across unmodified stream algorithms which were 411 not originally written to support timing out, and how a blocking algorithm 412 may be written from asynchronous intermediate operations. 413 </p> 414<pre class="programlisting"><span class="comment">/** Request an HTTP resource from a TLS host and return it as a string, with a timeout. 415 416 This example uses fibers (stackful coroutines) and its own I/O context. 417*/</span> 418<span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> 419<span class="identifier">https_get</span> <span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">host</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">target</span><span class="special">,</span> <span class="identifier">error_code</span><span class="special">&</span> <span class="identifier">ec</span><span class="special">)</span> 420<span class="special">{</span> 421 <span class="comment">// It is the responsibility of the algorithm to clear the error first.</span> 422 <span class="identifier">ec</span> <span class="special">=</span> <span class="special">{};</span> 423 424 <span class="comment">// We use our own I/O context, to make this function blocking.</span> 425 <span class="identifier">net</span><span class="special">::</span><span class="identifier">io_context</span> <span class="identifier">ioc</span><span class="special">;</span> 426 427 <span class="comment">// This context is used to hold client and server certificates.</span> 428 <span class="comment">// We do not perform certificate verification in this example.</span> 429 430 <span class="identifier">net</span><span class="special">::</span><span class="identifier">ssl</span><span class="special">::</span><span class="identifier">context</span> <span class="identifier">ctx</span><span class="special">(</span><span class="identifier">net</span><span class="special">::</span><span class="identifier">ssl</span><span class="special">::</span><span class="identifier">context</span><span class="special">::</span><span class="identifier">tlsv12</span><span class="special">);</span> 431 432 <span class="comment">// This string will hold the body of the HTTP response, if any.</span> 433 <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">result</span><span class="special">;</span> 434 435 <span class="comment">// Note that Networking TS does not come with spawn. This function</span> 436 <span class="comment">// launches a "fiber" which is a coroutine that has its own separately</span> 437 <span class="comment">// allocated stack.</span> 438 439 <span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">spawn</span><span class="special">(</span><span class="identifier">ioc</span><span class="special">,</span> 440 <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_context</span> <span class="identifier">yield</span><span class="special">)</span> 441 <span class="special">{</span> 442 <span class="comment">// We use the Beast ssl_stream wrapped around a beast tcp_stream.</span> 443 <span class="identifier">ssl_stream</span><span class="special"><</span><span class="identifier">tcp_stream</span><span class="special">></span> <span class="identifier">stream</span><span class="special">(</span><span class="identifier">ioc</span><span class="special">,</span> <span class="identifier">ctx</span><span class="special">);</span> 444 445 <span class="comment">// The resolver will be used to look up the IP addresses for the host name</span> 446 <span class="identifier">net</span><span class="special">::</span><span class="identifier">ip</span><span class="special">::</span><span class="identifier">tcp</span><span class="special">::</span><span class="identifier">resolver</span> <span class="identifier">resolver</span><span class="special">(</span><span class="identifier">ioc</span><span class="special">);</span> 447 448 <span class="comment">// First, look up the name. Networking has its own timeout for this.</span> 449 <span class="comment">// The `yield` object is a CompletionToken which specializes the</span> 450 <span class="comment">// `net::async_result` customization point to make the fiber work.</span> 451 <span class="comment">//</span> 452 <span class="comment">// This call will appear to "block" until the operation completes.</span> 453 <span class="comment">// It isn't really blocking. Instead, the fiber implementation saves</span> 454 <span class="comment">// the call stack and suspends the function until the asynchronous</span> 455 <span class="comment">// operation is complete. Then it restores the call stack, and resumes</span> 456 <span class="comment">// the function to the statement following the async_resolve. This</span> 457 <span class="comment">// allows an asynchronous algorithm to be expressed synchronously.</span> 458 459 <span class="keyword">auto</span> <span class="keyword">const</span> <span class="identifier">endpoints</span> <span class="special">=</span> <span class="identifier">resolver</span><span class="special">.</span><span class="identifier">async_resolve</span><span class="special">(</span><span class="identifier">host</span><span class="special">,</span> <span class="string">"https"</span><span class="special">,</span> <span class="special">{},</span> <span class="identifier">yield</span><span class="special">[</span><span class="identifier">ec</span><span class="special">]);</span> 460 <span class="keyword">if</span><span class="special">(</span><span class="identifier">ec</span><span class="special">)</span> 461 <span class="keyword">return</span><span class="special">;</span> 462 463 <span class="comment">// The function `get_lowest_layer` retrieves the "bottom most" object</span> 464 <span class="comment">// in the stack of stream layers. In this case it will be the tcp_stream.</span> 465 <span class="comment">// This timeout will apply to all subsequent operations collectively.</span> 466 <span class="comment">// That is to say, they must all complete within the same 30 second</span> 467 <span class="comment">// window.</span> 468 469 <span class="identifier">get_lowest_layer</span><span class="special">(</span><span class="identifier">stream</span><span class="special">).</span><span class="identifier">expires_after</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">chrono</span><span class="special">::</span><span class="identifier">seconds</span><span class="special">(</span><span class="number">30</span><span class="special">));</span> 470 471 <span class="comment">// `tcp_stream` range connect algorithms are member functions, unlike net::</span> 472 <span class="identifier">get_lowest_layer</span><span class="special">(</span><span class="identifier">stream</span><span class="special">).</span><span class="identifier">async_connect</span><span class="special">(</span><span class="identifier">endpoints</span><span class="special">,</span> <span class="identifier">yield</span><span class="special">[</span><span class="identifier">ec</span><span class="special">]);</span> 473 <span class="keyword">if</span><span class="special">(</span><span class="identifier">ec</span><span class="special">)</span> 474 <span class="keyword">return</span><span class="special">;</span> 475 476 <span class="comment">// Perform the TLS handshake</span> 477 <span class="identifier">stream</span><span class="special">.</span><span class="identifier">async_handshake</span><span class="special">(</span><span class="identifier">net</span><span class="special">::</span><span class="identifier">ssl</span><span class="special">::</span><span class="identifier">stream_base</span><span class="special">::</span><span class="identifier">client</span><span class="special">,</span> <span class="identifier">yield</span><span class="special">[</span><span class="identifier">ec</span><span class="special">]);</span> 478 <span class="keyword">if</span><span class="special">(</span><span class="identifier">ec</span><span class="special">)</span> 479 <span class="keyword">return</span><span class="special">;</span> 480 481 <span class="comment">// Send an HTTP GET request for the target</span> 482 <span class="special">{</span> 483 <span class="identifier">http</span><span class="special">::</span><span class="identifier">request</span><span class="special"><</span><span class="identifier">http</span><span class="special">::</span><span class="identifier">empty_body</span><span class="special">></span> <span class="identifier">req</span><span class="special">;</span> 484 <span class="identifier">req</span><span class="special">.</span><span class="identifier">method</span><span class="special">(</span><span class="identifier">http</span><span class="special">::</span><span class="identifier">verb</span><span class="special">::</span><span class="identifier">get</span><span class="special">);</span> 485 <span class="identifier">req</span><span class="special">.</span><span class="identifier">target</span><span class="special">(</span><span class="identifier">target</span><span class="special">);</span> 486 <span class="identifier">req</span><span class="special">.</span><span class="identifier">version</span><span class="special">(</span><span class="number">11</span><span class="special">);</span> 487 <span class="identifier">req</span><span class="special">.</span><span class="identifier">set</span><span class="special">(</span><span class="identifier">http</span><span class="special">::</span><span class="identifier">field</span><span class="special">::</span><span class="identifier">host</span><span class="special">,</span> <span class="identifier">host</span><span class="special">);</span> 488 <span class="identifier">req</span><span class="special">.</span><span class="identifier">set</span><span class="special">(</span><span class="identifier">http</span><span class="special">::</span><span class="identifier">field</span><span class="special">::</span><span class="identifier">user_agent</span><span class="special">,</span> <span class="string">"Beast"</span><span class="special">);</span> 489 <span class="identifier">http</span><span class="special">::</span><span class="identifier">async_write</span><span class="special">(</span><span class="identifier">stream</span><span class="special">,</span> <span class="identifier">req</span><span class="special">,</span> <span class="identifier">yield</span><span class="special">[</span><span class="identifier">ec</span><span class="special">]);</span> 490 <span class="keyword">if</span><span class="special">(</span><span class="identifier">ec</span><span class="special">)</span> 491 <span class="keyword">return</span><span class="special">;</span> 492 <span class="special">}</span> 493 494 <span class="comment">// Now read the response</span> 495 <span class="identifier">flat_buffer</span> <span class="identifier">buffer</span><span class="special">;</span> 496 <span class="identifier">http</span><span class="special">::</span><span class="identifier">response</span><span class="special"><</span><span class="identifier">http</span><span class="special">::</span><span class="identifier">string_body</span><span class="special">></span> <span class="identifier">res</span><span class="special">;</span> 497 <span class="identifier">http</span><span class="special">::</span><span class="identifier">async_read</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">res</span><span class="special">,</span> <span class="identifier">yield</span><span class="special">[</span><span class="identifier">ec</span><span class="special">]);</span> 498 <span class="keyword">if</span><span class="special">(</span><span class="identifier">ec</span><span class="special">)</span> 499 <span class="keyword">return</span><span class="special">;</span> 500 501 <span class="comment">// Try to perform the TLS shutdown handshake</span> 502 <span class="identifier">stream</span><span class="special">.</span><span class="identifier">async_shutdown</span><span class="special">(</span><span class="identifier">yield</span><span class="special">[</span><span class="identifier">ec</span><span class="special">]);</span> 503 504 <span class="comment">// `net::ssl::error::stream_truncated`, also known as an SSL "short read",</span> 505 <span class="comment">// indicates the peer closed the connection without performing the</span> 506 <span class="comment">// required closing handshake (for example, Google does this to</span> 507 <span class="comment">// improve performance). Generally this can be a security issue,</span> 508 <span class="comment">// but if your communication protocol is self-terminated (as</span> 509 <span class="comment">// it is with both HTTP and WebSocket) then you may simply</span> 510 <span class="comment">// ignore the lack of close_notify:</span> 511 <span class="comment">//</span> 512 <span class="comment">// https://github.com/boostorg/beast/issues/38</span> 513 <span class="comment">//</span> 514 <span class="comment">// https://security.stackexchange.com/questions/91435/how-to-handle-a-malicious-ssl-tls-shutdown</span> 515 <span class="comment">//</span> 516 <span class="comment">// When a short read would cut off the end of an HTTP message,</span> 517 <span class="comment">// Beast returns the error beast::http::error::partial_message.</span> 518 <span class="comment">// Therefore, if we see a short read here, it has occurred</span> 519 <span class="comment">// after the message has been completed, so it is safe to ignore it.</span> 520 521 <span class="keyword">if</span><span class="special">(</span><span class="identifier">ec</span> <span class="special">==</span> <span class="identifier">net</span><span class="special">::</span><span class="identifier">ssl</span><span class="special">::</span><span class="identifier">error</span><span class="special">::</span><span class="identifier">stream_truncated</span><span class="special">)</span> 522 <span class="identifier">ec</span> <span class="special">=</span> <span class="special">{};</span> 523 <span class="keyword">else</span> <span class="keyword">if</span><span class="special">(</span><span class="identifier">ec</span><span class="special">)</span> 524 <span class="keyword">return</span><span class="special">;</span> 525 526 <span class="comment">// Set the string to return to the caller</span> 527 <span class="identifier">result</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">res</span><span class="special">.</span><span class="identifier">body</span><span class="special">());</span> 528 <span class="special">});</span> 529 530 <span class="comment">// `run` will dispatch completion handlers, and block until there is</span> 531 <span class="comment">// no more "work" remaining. When this call returns, the operations</span> 532 <span class="comment">// are complete and we can give the caller the result.</span> 533 <span class="identifier">ioc</span><span class="special">.</span><span class="identifier">run</span><span class="special">();</span> 534 535 <span class="keyword">return</span> <span class="identifier">result</span><span class="special">;</span> 536<span class="special">}</span> 537</pre> 538</div> 539<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr> 540<td align="left"></td> 541<td align="right"><div class="copyright-footer">Copyright © 2016-2019 Vinnie 542 Falco<p> 543 Distributed under the Boost Software License, Version 1.0. (See accompanying 544 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>) 545 </p> 546</div></td> 547</tr></table> 548<hr> 549<div class="spirit-nav"> 550<a accesskey="p" href="stream_types.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../using_io.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="rate_limiting.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a> 551</div> 552</body> 553</html> 554