3 <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
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 💡">
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>
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>
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>
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
36 <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
38 The peer experiences a power loss
41 The peer becomes disconnected from the network
44 The local host becomes disconnected from the network
47 The network itself becomes unavailable
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:
57 <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
59 Drop malicious or poorly performing hosts
62 Close idle connections to free up resources
65 Determine if a peer is offline or no longer available
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>
75 <div class="note"><table border="0" summary="Note">
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>
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.
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:
89 <div class="informaltable"><table class="table">
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>
114 <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
115 <li class="listitem">
116 Timeouts for logical operations
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
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
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>
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>
138 <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
139 <li class="listitem">
140 Timeouts for logical operations
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>
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>
150 <li class="listitem">
151 Configurable <a class="link" href="../concepts/RatePolicy.html" title="RatePolicy"><span class="emphasis"><em>RatePolicy</em></span></a>
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>
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:
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>
178 Alternatively, we can construct the stream from an executor:
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>
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>
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
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>
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>
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>.
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>
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>
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>
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>
232 <span class="identifier">stream</span><span class="special">.</span><span class="identifier">expires_never</span><span class="special">();</span>
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>
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>
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>
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>
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>
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>
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>
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
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.
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>
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>
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>
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>
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>
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>
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
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>
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>
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>
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>
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>
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>
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>
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.
336 <pre class="programlisting"><span class="comment">/** This function echoes back received lines from a peer, with a timeout.
338 The algorithm terminates upon any error (including timeout).
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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.
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.
414 <pre class="programlisting"><span class="comment">/** Request an HTTP resource from a TLS host and return it as a string, with a timeout.
416 This example uses fibers (stackful coroutines) and its own I/O context.
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
535 <span class="keyword">return</span> <span class="identifier">result</span><span class="special">;</span>
536 <span class="special">}</span>
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
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>)
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>