1 //
2 // ssl/stream.hpp
3 // ~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6 //
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 //
10 
11 #ifndef BOOST_ASIO_SSL_STREAM_HPP
12 #define BOOST_ASIO_SSL_STREAM_HPP
13 
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
15 # pragma once
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17 
18 #include <boost/asio/detail/config.hpp>
19 
20 #include <boost/asio/async_result.hpp>
21 #include <boost/asio/detail/buffer_sequence_adapter.hpp>
22 #include <boost/asio/detail/handler_type_requirements.hpp>
23 #include <boost/asio/detail/non_const_lvalue.hpp>
24 #include <boost/asio/detail/noncopyable.hpp>
25 #include <boost/asio/detail/type_traits.hpp>
26 #include <boost/asio/ssl/context.hpp>
27 #include <boost/asio/ssl/detail/buffered_handshake_op.hpp>
28 #include <boost/asio/ssl/detail/handshake_op.hpp>
29 #include <boost/asio/ssl/detail/io.hpp>
30 #include <boost/asio/ssl/detail/read_op.hpp>
31 #include <boost/asio/ssl/detail/shutdown_op.hpp>
32 #include <boost/asio/ssl/detail/stream_core.hpp>
33 #include <boost/asio/ssl/detail/write_op.hpp>
34 #include <boost/asio/ssl/stream_base.hpp>
35 
36 #include <boost/asio/detail/push_options.hpp>
37 
38 namespace boost {
39 namespace asio {
40 namespace ssl {
41 
42 /// Provides stream-oriented functionality using SSL.
43 /**
44  * The stream class template provides asynchronous and blocking stream-oriented
45  * functionality using SSL.
46  *
47  * @par Thread Safety
48  * @e Distinct @e objects: Safe.@n
49  * @e Shared @e objects: Unsafe. The application must also ensure that all
50  * asynchronous operations are performed within the same implicit or explicit
51  * strand.
52  *
53  * @par Example
54  * To use the SSL stream template with an ip::tcp::socket, you would write:
55  * @code
56  * boost::asio::io_context my_context;
57  * boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23);
58  * boost::asio::ssl::stream<asio:ip::tcp::socket> sock(my_context, ctx);
59  * @endcode
60  *
61  * @par Concepts:
62  * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
63  */
64 template <typename Stream>
65 class stream :
66   public stream_base,
67   private noncopyable
68 {
69 public:
70   /// The native handle type of the SSL stream.
71   typedef SSL* native_handle_type;
72 
73   /// Structure for use with deprecated impl_type.
74   struct impl_struct
75   {
76     SSL* ssl;
77   };
78 
79   /// The type of the next layer.
80   typedef typename remove_reference<Stream>::type next_layer_type;
81 
82   /// The type of the lowest layer.
83   typedef typename next_layer_type::lowest_layer_type lowest_layer_type;
84 
85   /// The type of the executor associated with the object.
86   typedef typename lowest_layer_type::executor_type executor_type;
87 
88 #if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
89   /// Construct a stream.
90   /**
91    * This constructor creates a stream and initialises the underlying stream
92    * object.
93    *
94    * @param arg The argument to be passed to initialise the underlying stream.
95    *
96    * @param ctx The SSL context to be used for the stream.
97    */
98   template <typename Arg>
stream(Arg && arg,context & ctx)99   stream(Arg&& arg, context& ctx)
100     : next_layer_(BOOST_ASIO_MOVE_CAST(Arg)(arg)),
101       core_(ctx.native_handle(), next_layer_.lowest_layer().get_executor())
102   {
103   }
104 #else // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
105   template <typename Arg>
stream(Arg & arg,context & ctx)106   stream(Arg& arg, context& ctx)
107     : next_layer_(arg),
108       core_(ctx.native_handle(), next_layer_.lowest_layer().get_executor())
109   {
110   }
111 #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
112 
113 #if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
114   /// Move-construct a stream from another.
115   /**
116    * @param other The other stream object from which the move will occur. Must
117    * have no outstanding asynchronous operations associated with it. Following
118    * the move, @c other has a valid but unspecified state where the only safe
119    * operation is destruction.
120    */
stream(stream && other)121   stream(stream&& other)
122     : next_layer_(BOOST_ASIO_MOVE_CAST(Stream)(other.next_layer_)),
123       core_(BOOST_ASIO_MOVE_CAST(detail::stream_core)(other.core_))
124   {
125   }
126 #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
127 
128   /// Destructor.
129   /**
130    * @note A @c stream object must not be destroyed while there are pending
131    * asynchronous operations associated with it.
132    */
~stream()133   ~stream()
134   {
135   }
136 
137   /// Get the executor associated with the object.
138   /**
139    * This function may be used to obtain the executor object that the stream
140    * uses to dispatch handlers for asynchronous operations.
141    *
142    * @return A copy of the executor that stream will use to dispatch handlers.
143    */
get_executor()144   executor_type get_executor() BOOST_ASIO_NOEXCEPT
145   {
146     return next_layer_.lowest_layer().get_executor();
147   }
148 
149   /// Get the underlying implementation in the native type.
150   /**
151    * This function may be used to obtain the underlying implementation of the
152    * context. This is intended to allow access to context functionality that is
153    * not otherwise provided.
154    *
155    * @par Example
156    * The native_handle() function returns a pointer of type @c SSL* that is
157    * suitable for passing to functions such as @c SSL_get_verify_result and
158    * @c SSL_get_peer_certificate:
159    * @code
160    * boost::asio::ssl::stream<asio:ip::tcp::socket> sock(my_context, ctx);
161    *
162    * // ... establish connection and perform handshake ...
163    *
164    * if (X509* cert = SSL_get_peer_certificate(sock.native_handle()))
165    * {
166    *   if (SSL_get_verify_result(sock.native_handle()) == X509_V_OK)
167    *   {
168    *     // ...
169    *   }
170    * }
171    * @endcode
172    */
native_handle()173   native_handle_type native_handle()
174   {
175     return core_.engine_.native_handle();
176   }
177 
178   /// Get a reference to the next layer.
179   /**
180    * This function returns a reference to the next layer in a stack of stream
181    * layers.
182    *
183    * @return A reference to the next layer in the stack of stream layers.
184    * Ownership is not transferred to the caller.
185    */
next_layer() const186   const next_layer_type& next_layer() const
187   {
188     return next_layer_;
189   }
190 
191   /// Get a reference to the next layer.
192   /**
193    * This function returns a reference to the next layer in a stack of stream
194    * layers.
195    *
196    * @return A reference to the next layer in the stack of stream layers.
197    * Ownership is not transferred to the caller.
198    */
next_layer()199   next_layer_type& next_layer()
200   {
201     return next_layer_;
202   }
203 
204   /// Get a reference to the lowest layer.
205   /**
206    * This function returns a reference to the lowest layer in a stack of
207    * stream layers.
208    *
209    * @return A reference to the lowest layer in the stack of stream layers.
210    * Ownership is not transferred to the caller.
211    */
lowest_layer()212   lowest_layer_type& lowest_layer()
213   {
214     return next_layer_.lowest_layer();
215   }
216 
217   /// Get a reference to the lowest layer.
218   /**
219    * This function returns a reference to the lowest layer in a stack of
220    * stream layers.
221    *
222    * @return A reference to the lowest layer in the stack of stream layers.
223    * Ownership is not transferred to the caller.
224    */
lowest_layer() const225   const lowest_layer_type& lowest_layer() const
226   {
227     return next_layer_.lowest_layer();
228   }
229 
230   /// Set the peer verification mode.
231   /**
232    * This function may be used to configure the peer verification mode used by
233    * the stream. The new mode will override the mode inherited from the context.
234    *
235    * @param v A bitmask of peer verification modes. See @ref verify_mode for
236    * available values.
237    *
238    * @throws boost::system::system_error Thrown on failure.
239    *
240    * @note Calls @c SSL_set_verify.
241    */
set_verify_mode(verify_mode v)242   void set_verify_mode(verify_mode v)
243   {
244     boost::system::error_code ec;
245     set_verify_mode(v, ec);
246     boost::asio::detail::throw_error(ec, "set_verify_mode");
247   }
248 
249   /// Set the peer verification mode.
250   /**
251    * This function may be used to configure the peer verification mode used by
252    * the stream. The new mode will override the mode inherited from the context.
253    *
254    * @param v A bitmask of peer verification modes. See @ref verify_mode for
255    * available values.
256    *
257    * @param ec Set to indicate what error occurred, if any.
258    *
259    * @note Calls @c SSL_set_verify.
260    */
set_verify_mode(verify_mode v,boost::system::error_code & ec)261   BOOST_ASIO_SYNC_OP_VOID set_verify_mode(
262       verify_mode v, boost::system::error_code& ec)
263   {
264     core_.engine_.set_verify_mode(v, ec);
265     BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
266   }
267 
268   /// Set the peer verification depth.
269   /**
270    * This function may be used to configure the maximum verification depth
271    * allowed by the stream.
272    *
273    * @param depth Maximum depth for the certificate chain verification that
274    * shall be allowed.
275    *
276    * @throws boost::system::system_error Thrown on failure.
277    *
278    * @note Calls @c SSL_set_verify_depth.
279    */
set_verify_depth(int depth)280   void set_verify_depth(int depth)
281   {
282     boost::system::error_code ec;
283     set_verify_depth(depth, ec);
284     boost::asio::detail::throw_error(ec, "set_verify_depth");
285   }
286 
287   /// Set the peer verification depth.
288   /**
289    * This function may be used to configure the maximum verification depth
290    * allowed by the stream.
291    *
292    * @param depth Maximum depth for the certificate chain verification that
293    * shall be allowed.
294    *
295    * @param ec Set to indicate what error occurred, if any.
296    *
297    * @note Calls @c SSL_set_verify_depth.
298    */
set_verify_depth(int depth,boost::system::error_code & ec)299   BOOST_ASIO_SYNC_OP_VOID set_verify_depth(
300       int depth, boost::system::error_code& ec)
301   {
302     core_.engine_.set_verify_depth(depth, ec);
303     BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
304   }
305 
306   /// Set the callback used to verify peer certificates.
307   /**
308    * This function is used to specify a callback function that will be called
309    * by the implementation when it needs to verify a peer certificate.
310    *
311    * @param callback The function object to be used for verifying a certificate.
312    * The function signature of the handler must be:
313    * @code bool verify_callback(
314    *   bool preverified, // True if the certificate passed pre-verification.
315    *   verify_context& ctx // The peer certificate and other context.
316    * ); @endcode
317    * The return value of the callback is true if the certificate has passed
318    * verification, false otherwise.
319    *
320    * @throws boost::system::system_error Thrown on failure.
321    *
322    * @note Calls @c SSL_set_verify.
323    */
324   template <typename VerifyCallback>
set_verify_callback(VerifyCallback callback)325   void set_verify_callback(VerifyCallback callback)
326   {
327     boost::system::error_code ec;
328     this->set_verify_callback(callback, ec);
329     boost::asio::detail::throw_error(ec, "set_verify_callback");
330   }
331 
332   /// Set the callback used to verify peer certificates.
333   /**
334    * This function is used to specify a callback function that will be called
335    * by the implementation when it needs to verify a peer certificate.
336    *
337    * @param callback The function object to be used for verifying a certificate.
338    * The function signature of the handler must be:
339    * @code bool verify_callback(
340    *   bool preverified, // True if the certificate passed pre-verification.
341    *   verify_context& ctx // The peer certificate and other context.
342    * ); @endcode
343    * The return value of the callback is true if the certificate has passed
344    * verification, false otherwise.
345    *
346    * @param ec Set to indicate what error occurred, if any.
347    *
348    * @note Calls @c SSL_set_verify.
349    */
350   template <typename VerifyCallback>
set_verify_callback(VerifyCallback callback,boost::system::error_code & ec)351   BOOST_ASIO_SYNC_OP_VOID set_verify_callback(VerifyCallback callback,
352       boost::system::error_code& ec)
353   {
354     core_.engine_.set_verify_callback(
355         new detail::verify_callback<VerifyCallback>(callback), ec);
356     BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
357   }
358 
359   /// Perform SSL handshaking.
360   /**
361    * This function is used to perform SSL handshaking on the stream. The
362    * function call will block until handshaking is complete or an error occurs.
363    *
364    * @param type The type of handshaking to be performed, i.e. as a client or as
365    * a server.
366    *
367    * @throws boost::system::system_error Thrown on failure.
368    */
handshake(handshake_type type)369   void handshake(handshake_type type)
370   {
371     boost::system::error_code ec;
372     handshake(type, ec);
373     boost::asio::detail::throw_error(ec, "handshake");
374   }
375 
376   /// Perform SSL handshaking.
377   /**
378    * This function is used to perform SSL handshaking on the stream. The
379    * function call will block until handshaking is complete or an error occurs.
380    *
381    * @param type The type of handshaking to be performed, i.e. as a client or as
382    * a server.
383    *
384    * @param ec Set to indicate what error occurred, if any.
385    */
handshake(handshake_type type,boost::system::error_code & ec)386   BOOST_ASIO_SYNC_OP_VOID handshake(handshake_type type,
387       boost::system::error_code& ec)
388   {
389     detail::io(next_layer_, core_, detail::handshake_op(type), ec);
390     BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
391   }
392 
393   /// Perform SSL handshaking.
394   /**
395    * This function is used to perform SSL handshaking on the stream. The
396    * function call will block until handshaking is complete or an error occurs.
397    *
398    * @param type The type of handshaking to be performed, i.e. as a client or as
399    * a server.
400    *
401    * @param buffers The buffered data to be reused for the handshake.
402    *
403    * @throws boost::system::system_error Thrown on failure.
404    */
405   template <typename ConstBufferSequence>
handshake(handshake_type type,const ConstBufferSequence & buffers)406   void handshake(handshake_type type, const ConstBufferSequence& buffers)
407   {
408     boost::system::error_code ec;
409     handshake(type, buffers, ec);
410     boost::asio::detail::throw_error(ec, "handshake");
411   }
412 
413   /// Perform SSL handshaking.
414   /**
415    * This function is used to perform SSL handshaking on the stream. The
416    * function call will block until handshaking is complete or an error occurs.
417    *
418    * @param type The type of handshaking to be performed, i.e. as a client or as
419    * a server.
420    *
421    * @param buffers The buffered data to be reused for the handshake.
422    *
423    * @param ec Set to indicate what error occurred, if any.
424    */
425   template <typename ConstBufferSequence>
handshake(handshake_type type,const ConstBufferSequence & buffers,boost::system::error_code & ec)426   BOOST_ASIO_SYNC_OP_VOID handshake(handshake_type type,
427       const ConstBufferSequence& buffers, boost::system::error_code& ec)
428   {
429     detail::io(next_layer_, core_,
430         detail::buffered_handshake_op<ConstBufferSequence>(type, buffers), ec);
431     BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
432   }
433 
434   /// Start an asynchronous SSL handshake.
435   /**
436    * This function is used to asynchronously perform an SSL handshake on the
437    * stream. This function call always returns immediately.
438    *
439    * @param type The type of handshaking to be performed, i.e. as a client or as
440    * a server.
441    *
442    * @param handler The handler to be called when the handshake operation
443    * completes. Copies will be made of the handler as required. The equivalent
444    * function signature of the handler must be:
445    * @code void handler(
446    *   const boost::system::error_code& error // Result of operation.
447    * ); @endcode
448    */
449   template <
450       BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code))
451         HandshakeHandler
452           BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(HandshakeHandler,void (boost::system::error_code))453   BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(HandshakeHandler,
454       void (boost::system::error_code))
455   async_handshake(handshake_type type,
456       BOOST_ASIO_MOVE_ARG(HandshakeHandler) handler
457         BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
458   {
459     return async_initiate<HandshakeHandler,
460       void (boost::system::error_code)>(
461         initiate_async_handshake(this), handler, type);
462   }
463 
464   /// Start an asynchronous SSL handshake.
465   /**
466    * This function is used to asynchronously perform an SSL handshake on the
467    * stream. This function call always returns immediately.
468    *
469    * @param type The type of handshaking to be performed, i.e. as a client or as
470    * a server.
471    *
472    * @param buffers The buffered data to be reused for the handshake. Although
473    * the buffers object may be copied as necessary, ownership of the underlying
474    * buffers is retained by the caller, which must guarantee that they remain
475    * valid until the handler is called.
476    *
477    * @param handler The handler to be called when the handshake operation
478    * completes. Copies will be made of the handler as required. The equivalent
479    * function signature of the handler must be:
480    * @code void handler(
481    *   const boost::system::error_code& error, // Result of operation.
482    *   std::size_t bytes_transferred // Amount of buffers used in handshake.
483    * ); @endcode
484    */
485   template <typename ConstBufferSequence,
486       BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
487         std::size_t)) BufferedHandshakeHandler
488           BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(BufferedHandshakeHandler,void (boost::system::error_code,std::size_t))489   BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(BufferedHandshakeHandler,
490       void (boost::system::error_code, std::size_t))
491   async_handshake(handshake_type type, const ConstBufferSequence& buffers,
492       BOOST_ASIO_MOVE_ARG(BufferedHandshakeHandler) handler
493         BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
494   {
495     return async_initiate<BufferedHandshakeHandler,
496       void (boost::system::error_code, std::size_t)>(
497         initiate_async_buffered_handshake(this), handler, type, buffers);
498   }
499 
500   /// Shut down SSL on the stream.
501   /**
502    * This function is used to shut down SSL on the stream. The function call
503    * will block until SSL has been shut down or an error occurs.
504    *
505    * @throws boost::system::system_error Thrown on failure.
506    */
shutdown()507   void shutdown()
508   {
509     boost::system::error_code ec;
510     shutdown(ec);
511     boost::asio::detail::throw_error(ec, "shutdown");
512   }
513 
514   /// Shut down SSL on the stream.
515   /**
516    * This function is used to shut down SSL on the stream. The function call
517    * will block until SSL has been shut down or an error occurs.
518    *
519    * @param ec Set to indicate what error occurred, if any.
520    */
shutdown(boost::system::error_code & ec)521   BOOST_ASIO_SYNC_OP_VOID shutdown(boost::system::error_code& ec)
522   {
523     detail::io(next_layer_, core_, detail::shutdown_op(), ec);
524     BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
525   }
526 
527   /// Asynchronously shut down SSL on the stream.
528   /**
529    * This function is used to asynchronously shut down SSL on the stream. This
530    * function call always returns immediately.
531    *
532    * @param handler The handler to be called when the handshake operation
533    * completes. Copies will be made of the handler as required. The equivalent
534    * function signature of the handler must be:
535    * @code void handler(
536    *   const boost::system::error_code& error // Result of operation.
537    * ); @endcode
538    */
539   template <
540       BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code))
541         ShutdownHandler
542           BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ShutdownHandler,void (boost::system::error_code))543   BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ShutdownHandler,
544       void (boost::system::error_code))
545   async_shutdown(
546       BOOST_ASIO_MOVE_ARG(ShutdownHandler) handler
547         BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
548   {
549     return async_initiate<ShutdownHandler,
550       void (boost::system::error_code)>(
551         initiate_async_shutdown(this), handler);
552   }
553 
554   /// Write some data to the stream.
555   /**
556    * This function is used to write data on the stream. The function call will
557    * block until one or more bytes of data has been written successfully, or
558    * until an error occurs.
559    *
560    * @param buffers The data to be written.
561    *
562    * @returns The number of bytes written.
563    *
564    * @throws boost::system::system_error Thrown on failure.
565    *
566    * @note The write_some operation may not transmit all of the data to the
567    * peer. Consider using the @ref write function if you need to ensure that all
568    * data is written before the blocking operation completes.
569    */
570   template <typename ConstBufferSequence>
write_some(const ConstBufferSequence & buffers)571   std::size_t write_some(const ConstBufferSequence& buffers)
572   {
573     boost::system::error_code ec;
574     std::size_t n = write_some(buffers, ec);
575     boost::asio::detail::throw_error(ec, "write_some");
576     return n;
577   }
578 
579   /// Write some data to the stream.
580   /**
581    * This function is used to write data on the stream. The function call will
582    * block until one or more bytes of data has been written successfully, or
583    * until an error occurs.
584    *
585    * @param buffers The data to be written to the stream.
586    *
587    * @param ec Set to indicate what error occurred, if any.
588    *
589    * @returns The number of bytes written. Returns 0 if an error occurred.
590    *
591    * @note The write_some operation may not transmit all of the data to the
592    * peer. Consider using the @ref write function if you need to ensure that all
593    * data is written before the blocking operation completes.
594    */
595   template <typename ConstBufferSequence>
write_some(const ConstBufferSequence & buffers,boost::system::error_code & ec)596   std::size_t write_some(const ConstBufferSequence& buffers,
597       boost::system::error_code& ec)
598   {
599     return detail::io(next_layer_, core_,
600         detail::write_op<ConstBufferSequence>(buffers), ec);
601   }
602 
603   /// Start an asynchronous write.
604   /**
605    * This function is used to asynchronously write one or more bytes of data to
606    * the stream. The function call always returns immediately.
607    *
608    * @param buffers The data to be written to the stream. Although the buffers
609    * object may be copied as necessary, ownership of the underlying buffers is
610    * retained by the caller, which must guarantee that they remain valid until
611    * the handler is called.
612    *
613    * @param handler The handler to be called when the write operation completes.
614    * Copies will be made of the handler as required. The equivalent function
615    * signature of the handler must be:
616    * @code void handler(
617    *   const boost::system::error_code& error, // Result of operation.
618    *   std::size_t bytes_transferred           // Number of bytes written.
619    * ); @endcode
620    *
621    * @note The async_write_some operation may not transmit all of the data to
622    * the peer. Consider using the @ref async_write function if you need to
623    * ensure that all data is written before the asynchronous operation
624    * completes.
625    */
626   template <typename ConstBufferSequence,
627       BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
628         std::size_t)) WriteHandler
629           BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,void (boost::system::error_code,std::size_t))630   BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
631       void (boost::system::error_code, std::size_t))
632   async_write_some(const ConstBufferSequence& buffers,
633       BOOST_ASIO_MOVE_ARG(WriteHandler) handler
634         BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
635   {
636     return async_initiate<WriteHandler,
637       void (boost::system::error_code, std::size_t)>(
638         initiate_async_write_some(this), handler, buffers);
639   }
640 
641   /// Read some data from the stream.
642   /**
643    * This function is used to read data from the stream. The function call will
644    * block until one or more bytes of data has been read successfully, or until
645    * an error occurs.
646    *
647    * @param buffers The buffers into which the data will be read.
648    *
649    * @returns The number of bytes read.
650    *
651    * @throws boost::system::system_error Thrown on failure.
652    *
653    * @note The read_some operation may not read all of the requested number of
654    * bytes. Consider using the @ref read function if you need to ensure that the
655    * requested amount of data is read before the blocking operation completes.
656    */
657   template <typename MutableBufferSequence>
read_some(const MutableBufferSequence & buffers)658   std::size_t read_some(const MutableBufferSequence& buffers)
659   {
660     boost::system::error_code ec;
661     std::size_t n = read_some(buffers, ec);
662     boost::asio::detail::throw_error(ec, "read_some");
663     return n;
664   }
665 
666   /// Read some data from the stream.
667   /**
668    * This function is used to read data from the stream. The function call will
669    * block until one or more bytes of data has been read successfully, or until
670    * an error occurs.
671    *
672    * @param buffers The buffers into which the data will be read.
673    *
674    * @param ec Set to indicate what error occurred, if any.
675    *
676    * @returns The number of bytes read. Returns 0 if an error occurred.
677    *
678    * @note The read_some operation may not read all of the requested number of
679    * bytes. Consider using the @ref read function if you need to ensure that the
680    * requested amount of data is read before the blocking operation completes.
681    */
682   template <typename MutableBufferSequence>
read_some(const MutableBufferSequence & buffers,boost::system::error_code & ec)683   std::size_t read_some(const MutableBufferSequence& buffers,
684       boost::system::error_code& ec)
685   {
686     return detail::io(next_layer_, core_,
687         detail::read_op<MutableBufferSequence>(buffers), ec);
688   }
689 
690   /// Start an asynchronous read.
691   /**
692    * This function is used to asynchronously read one or more bytes of data from
693    * the stream. The function call always returns immediately.
694    *
695    * @param buffers The buffers into which the data will be read. Although the
696    * buffers object may be copied as necessary, ownership of the underlying
697    * buffers is retained by the caller, which must guarantee that they remain
698    * valid until the handler is called.
699    *
700    * @param handler The handler to be called when the read operation completes.
701    * Copies will be made of the handler as required. The equivalent function
702    * signature of the handler must be:
703    * @code void handler(
704    *   const boost::system::error_code& error, // Result of operation.
705    *   std::size_t bytes_transferred           // Number of bytes read.
706    * ); @endcode
707    *
708    * @note The async_read_some operation may not read all of the requested
709    * number of bytes. Consider using the @ref async_read function if you need to
710    * ensure that the requested amount of data is read before the asynchronous
711    * operation completes.
712    */
713   template <typename MutableBufferSequence,
714       BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
715         std::size_t)) ReadHandler
716           BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,void (boost::system::error_code,std::size_t))717   BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
718       void (boost::system::error_code, std::size_t))
719   async_read_some(const MutableBufferSequence& buffers,
720       BOOST_ASIO_MOVE_ARG(ReadHandler) handler
721         BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
722   {
723     return async_initiate<ReadHandler,
724       void (boost::system::error_code, std::size_t)>(
725         initiate_async_read_some(this), handler, buffers);
726   }
727 
728 private:
729   class initiate_async_handshake
730   {
731   public:
732     typedef typename stream::executor_type executor_type;
733 
initiate_async_handshake(stream * self)734     explicit initiate_async_handshake(stream* self)
735       : self_(self)
736     {
737     }
738 
get_executor() const739     executor_type get_executor() const BOOST_ASIO_NOEXCEPT
740     {
741       return self_->get_executor();
742     }
743 
744     template <typename HandshakeHandler>
operator ()(BOOST_ASIO_MOVE_ARG (HandshakeHandler)handler,handshake_type type) const745     void operator()(BOOST_ASIO_MOVE_ARG(HandshakeHandler) handler,
746         handshake_type type) const
747     {
748       // If you get an error on the following line it means that your handler
749       // does not meet the documented type requirements for a HandshakeHandler.
750       BOOST_ASIO_HANDSHAKE_HANDLER_CHECK(HandshakeHandler, handler) type_check;
751 
752       boost::asio::detail::non_const_lvalue<HandshakeHandler> handler2(handler);
753       detail::async_io(self_->next_layer_, self_->core_,
754           detail::handshake_op(type), handler2.value);
755     }
756 
757   private:
758     stream* self_;
759   };
760 
761   class initiate_async_buffered_handshake
762   {
763   public:
764     typedef typename stream::executor_type executor_type;
765 
initiate_async_buffered_handshake(stream * self)766     explicit initiate_async_buffered_handshake(stream* self)
767       : self_(self)
768     {
769     }
770 
get_executor() const771     executor_type get_executor() const BOOST_ASIO_NOEXCEPT
772     {
773       return self_->get_executor();
774     }
775 
776     template <typename BufferedHandshakeHandler, typename ConstBufferSequence>
operator ()(BOOST_ASIO_MOVE_ARG (BufferedHandshakeHandler)handler,handshake_type type,const ConstBufferSequence & buffers) const777     void operator()(BOOST_ASIO_MOVE_ARG(BufferedHandshakeHandler) handler,
778         handshake_type type, const ConstBufferSequence& buffers) const
779     {
780       // If you get an error on the following line it means that your
781       // handler does not meet the documented type requirements for a
782       // BufferedHandshakeHandler.
783       BOOST_ASIO_BUFFERED_HANDSHAKE_HANDLER_CHECK(
784           BufferedHandshakeHandler, handler) type_check;
785 
786       boost::asio::detail::non_const_lvalue<
787           BufferedHandshakeHandler> handler2(handler);
788       detail::async_io(self_->next_layer_, self_->core_,
789           detail::buffered_handshake_op<ConstBufferSequence>(type, buffers),
790           handler2.value);
791     }
792 
793   private:
794     stream* self_;
795   };
796 
797   class initiate_async_shutdown
798   {
799   public:
800     typedef typename stream::executor_type executor_type;
801 
initiate_async_shutdown(stream * self)802     explicit initiate_async_shutdown(stream* self)
803       : self_(self)
804     {
805     }
806 
get_executor() const807     executor_type get_executor() const BOOST_ASIO_NOEXCEPT
808     {
809       return self_->get_executor();
810     }
811 
812     template <typename ShutdownHandler>
operator ()(BOOST_ASIO_MOVE_ARG (ShutdownHandler)handler) const813     void operator()(BOOST_ASIO_MOVE_ARG(ShutdownHandler) handler) const
814     {
815       // If you get an error on the following line it means that your handler
816       // does not meet the documented type requirements for a ShutdownHandler.
817       BOOST_ASIO_HANDSHAKE_HANDLER_CHECK(ShutdownHandler, handler) type_check;
818 
819       boost::asio::detail::non_const_lvalue<ShutdownHandler> handler2(handler);
820       detail::async_io(self_->next_layer_, self_->core_,
821           detail::shutdown_op(), handler2.value);
822     }
823 
824   private:
825     stream* self_;
826   };
827 
828   class initiate_async_write_some
829   {
830   public:
831     typedef typename stream::executor_type executor_type;
832 
initiate_async_write_some(stream * self)833     explicit initiate_async_write_some(stream* self)
834       : self_(self)
835     {
836     }
837 
get_executor() const838     executor_type get_executor() const BOOST_ASIO_NOEXCEPT
839     {
840       return self_->get_executor();
841     }
842 
843     template <typename WriteHandler, typename ConstBufferSequence>
operator ()(BOOST_ASIO_MOVE_ARG (WriteHandler)handler,const ConstBufferSequence & buffers) const844     void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler,
845         const ConstBufferSequence& buffers) const
846     {
847       // If you get an error on the following line it means that your handler
848       // does not meet the documented type requirements for a WriteHandler.
849       BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
850 
851       boost::asio::detail::non_const_lvalue<WriteHandler> handler2(handler);
852       detail::async_io(self_->next_layer_, self_->core_,
853           detail::write_op<ConstBufferSequence>(buffers), handler2.value);
854     }
855 
856   private:
857     stream* self_;
858   };
859 
860   class initiate_async_read_some
861   {
862   public:
863     typedef typename stream::executor_type executor_type;
864 
initiate_async_read_some(stream * self)865     explicit initiate_async_read_some(stream* self)
866       : self_(self)
867     {
868     }
869 
get_executor() const870     executor_type get_executor() const BOOST_ASIO_NOEXCEPT
871     {
872       return self_->get_executor();
873     }
874 
875     template <typename ReadHandler, typename MutableBufferSequence>
operator ()(BOOST_ASIO_MOVE_ARG (ReadHandler)handler,const MutableBufferSequence & buffers) const876     void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler,
877         const MutableBufferSequence& buffers) const
878     {
879       // If you get an error on the following line it means that your handler
880       // does not meet the documented type requirements for a ReadHandler.
881       BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
882 
883       boost::asio::detail::non_const_lvalue<ReadHandler> handler2(handler);
884       detail::async_io(self_->next_layer_, self_->core_,
885           detail::read_op<MutableBufferSequence>(buffers), handler2.value);
886     }
887 
888   private:
889     stream* self_;
890   };
891 
892   Stream next_layer_;
893   detail::stream_core core_;
894 };
895 
896 } // namespace ssl
897 } // namespace asio
898 } // namespace boost
899 
900 #include <boost/asio/detail/pop_options.hpp>
901 
902 #endif // BOOST_ASIO_SSL_STREAM_HPP
903