From 70e93c3e24cd0fa0f7ee1c5787bbb57936dcc671 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Sun, 13 Mar 2011 21:40:37 +1100 Subject: [PATCH] New SSL implementation. --- asio/include/asio/ssl/basic_context.hpp | 11 +- asio/include/asio/ssl/context.hpp | 373 +++++++++++++- asio/include/asio/ssl/context_base.hpp | 2 +- asio/include/asio/ssl/context_service.hpp | 11 +- asio/include/asio/ssl/detail/buffer_space.hpp | 71 +++ asio/include/asio/ssl/detail/engine.hpp | 117 +++++ asio/include/asio/ssl/detail/handshake_op.hpp | 107 ++++ asio/include/asio/ssl/detail/impl/engine.ipp | 219 +++++++++ .../include/asio/ssl/detail/openssl_types.hpp | 2 +- .../asio/ssl/detail/password_callback.hpp | 72 +++ asio/include/asio/ssl/detail/read_op.hpp | 114 +++++ asio/include/asio/ssl/detail/shutdown_op.hpp | 104 ++++ asio/include/asio/ssl/detail/transport.hpp | 125 +++++ asio/include/asio/ssl/detail/transport_op.hpp | 207 ++++++++ asio/include/asio/ssl/detail/write_op.hpp | 114 +++++ asio/include/asio/ssl/impl/context.hpp | 55 +++ asio/include/asio/ssl/impl/context.ipp | 431 ++++++++++++++++ asio/include/asio/ssl/impl/src.hpp | 2 + asio/include/asio/ssl/stream.hpp | 463 +++++++++++++++++- asio/include/asio/ssl/stream_base.hpp | 2 +- asio/include/asio/ssl/stream_service.hpp | 11 +- asio/src/tests/unit/ssl/stream.cpp | 2 + 22 files changed, 2596 insertions(+), 19 deletions(-) create mode 100644 asio/include/asio/ssl/detail/buffer_space.hpp create mode 100644 asio/include/asio/ssl/detail/engine.hpp create mode 100644 asio/include/asio/ssl/detail/handshake_op.hpp create mode 100644 asio/include/asio/ssl/detail/impl/engine.ipp create mode 100644 asio/include/asio/ssl/detail/password_callback.hpp create mode 100644 asio/include/asio/ssl/detail/read_op.hpp create mode 100644 asio/include/asio/ssl/detail/shutdown_op.hpp create mode 100644 asio/include/asio/ssl/detail/transport.hpp create mode 100644 asio/include/asio/ssl/detail/transport_op.hpp create mode 100644 asio/include/asio/ssl/detail/write_op.hpp create mode 100644 asio/include/asio/ssl/impl/context.hpp create mode 100644 asio/include/asio/ssl/impl/context.ipp diff --git a/asio/include/asio/ssl/basic_context.hpp b/asio/include/asio/ssl/basic_context.hpp index 6e219032..39c18b7b 100644 --- a/asio/include/asio/ssl/basic_context.hpp +++ b/asio/include/asio/ssl/basic_context.hpp @@ -2,8 +2,7 @@ // ssl/basic_context.hpp // ~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com -// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -18,15 +17,21 @@ #include "asio/detail/config.hpp" -#include "asio/ssl/old/basic_context.hpp" +#if defined(ASIO_ENABLE_OLD_SSL) +# include "asio/ssl/old/basic_context.hpp" +#endif // defined(ASIO_ENABLE_OLD_SSL) #include "asio/detail/push_options.hpp" namespace asio { namespace ssl { +#if defined(ASIO_ENABLE_OLD_SSL) + using asio::ssl::old::basic_context; +#endif // defined(ASIO_ENABLE_OLD_SSL) + } // namespace ssl } // namespace asio diff --git a/asio/include/asio/ssl/context.hpp b/asio/include/asio/ssl/context.hpp index 7aedc4db..c0298592 100644 --- a/asio/include/asio/ssl/context.hpp +++ b/asio/include/asio/ssl/context.hpp @@ -2,8 +2,7 @@ // ssl/context.hpp // ~~~~~~~~~~~~~~~ // -// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com -// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -17,16 +16,382 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" -#include "asio/ssl/basic_context.hpp" -#include "asio/ssl/context_service.hpp" + +#if defined(ASIO_ENABLE_OLD_SSL) +# include "asio/ssl/basic_context.hpp" +# include "asio/ssl/context_service.hpp" +#else // defined(ASIO_ENABLE_OLD_SSL) +# include +# include "asio/io_service.hpp" +# include "asio/ssl/context_base.hpp" +# include "asio/ssl/detail/openssl_types.hpp" +# include "asio/ssl/detail/openssl_init.hpp" +# include "asio/ssl/detail/password_callback.hpp" +#endif // defined(ASIO_ENABLE_OLD_SSL) namespace asio { namespace ssl { +#if defined(ASIO_ENABLE_OLD_SSL) + /// Typedef for the typical usage of context. typedef basic_context context; +#else // defined(ASIO_ENABLE_OLD_SSL) + +class context + : public context_base, + private noncopyable +{ +public: + /// The native handle type of the SSL context. + typedef SSL_CTX* native_handle_type; + + /// Constructor. + ASIO_DECL explicit context(method m); + + /// Deprecated constructor taking a reference to an io_service object. + ASIO_DECL context(asio::io_service&, method m); + +#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a context from another. + /** + * This constructor moves an SSL context from one object to another. + * + * @param other The other context object from which the move will occur. + * + * @note Following the move, the following operations only are valid for the + * moved-from object: + * @li Destruction. + * @li As a target for move-assignment. + */ + ASIO_DECL context(context&& other); + + /// Move-assign a context from another. + /** + * This assignment operator moves an SSL context from one object to another. + * + * @param other The other context object from which the move will occur. + * + * @note Following the move, the following operations only are valid for the + * moved-from object: + * @li Destruction. + * @li As a target for move-assignment. + */ + ASIO_DECL context& operator=(context&& other); +#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Destructor. + ASIO_DECL ~context(); + + /// Get the underlying implementation in the native type. + /** + * This function may be used to obtain the underlying implementation of the + * context. This is intended to allow access to context functionality that is + * not otherwise provided. + */ + ASIO_DECL native_handle_type native_handle(); + + /// Set options on the context. + /** + * This function may be used to configure the SSL options used by the context. + * + * @param o A bitmask of options. The available option values are defined in + * the context_base class. The options are bitwise-ored with any existing + * value for the options. + * + * @throws asio::system_error Thrown on failure. + */ + ASIO_DECL void set_options(options o); + + /// Set options on the context. + /** + * This function may be used to configure the SSL options used by the context. + * + * @param o A bitmask of options. The available option values are defined in + * the context_base class. The options are bitwise-ored with any existing + * value for the options. + * + * @param ec Set to indicate what error occurred, if any. + */ + ASIO_DECL asio::error_code set_options(options o, + asio::error_code& ec); + + /// Set the peer verification mode. + /** + * This function may be used to configure the peer verification mode used by + * the context. + * + * @param v A bitmask of peer verification modes. The available verify_mode + * values are defined in the context_base class. + * + * @throws asio::system_error Thrown on failure. + */ + ASIO_DECL void set_verify_mode(verify_mode v); + + /// Set the peer verification mode. + /** + * This function may be used to configure the peer verification mode used by + * the context. + * + * @param v A bitmask of peer verification modes. The available verify_mode + * values are defined in the context_base class. + * + * @param ec Set to indicate what error occurred, if any. + */ + ASIO_DECL asio::error_code set_verify_mode( + verify_mode v, asio::error_code& ec); + + /// Load a certification authority file for performing verification. + /** + * This function is used to load one or more trusted certification authorities + * from a file. + * + * @param filename The name of a file containing certification authority + * certificates in PEM format. + * + * @throws asio::system_error Thrown on failure. + */ + ASIO_DECL void load_verify_file(const std::string& filename); + + /// Load a certification authority file for performing verification. + /** + * This function is used to load the certificates for one or more trusted + * certification authorities from a file. + * + * @param filename The name of a file containing certification authority + * certificates in PEM format. + * + * @param ec Set to indicate what error occurred, if any. + */ + ASIO_DECL asio::error_code load_verify_file( + const std::string& filename, asio::error_code& ec); + + /// Add a directory containing certificate authority files to be used for + /// performing verification. + /** + * This function is used to specify the name of a directory containing + * certification authority certificates. Each file in the directory must + * contain a single certificate. The files must be named using the subject + * name's hash and an extension of ".0". + * + * @param path The name of a directory containing the certificates. + * + * @throws asio::system_error Thrown on failure. + */ + ASIO_DECL void add_verify_path(const std::string& path); + + /// Add a directory containing certificate authority files to be used for + /// performing verification. + /** + * This function is used to specify the name of a directory containing + * certification authority certificates. Each file in the directory must + * contain a single certificate. The files must be named using the subject + * name's hash and an extension of ".0". + * + * @param path The name of a directory containing the certificates. + * + * @param ec Set to indicate what error occurred, if any. + */ + ASIO_DECL asio::error_code add_verify_path( + const std::string& path, asio::error_code& ec); + + /// Use a certificate from a file. + /** + * This function is used to load a certificate into the context from a file. + * + * @param filename The name of the file containing the certificate. + * + * @param format The file format (ASN.1 or PEM). + * + * @throws asio::system_error Thrown on failure. + */ + ASIO_DECL void use_certificate_file( + const std::string& filename, file_format format); + + /// Use a certificate from a file. + /** + * This function is used to load a certificate into the context from a file. + * + * @param filename The name of the file containing the certificate. + * + * @param format The file format (ASN.1 or PEM). + * + * @param ec Set to indicate what error occurred, if any. + */ + ASIO_DECL asio::error_code use_certificate_file( + const std::string& filename, file_format format, + asio::error_code& ec); + + /// Use a certificate chain from a file. + /** + * This function is used to load a certificate chain into the context from a + * file. + * + * @param filename The name of the file containing the certificate. The file + * must use the PEM format. + * + * @throws asio::system_error Thrown on failure. + */ + ASIO_DECL void use_certificate_chain_file(const std::string& filename); + + /// Use a certificate chain from a file. + /** + * This function is used to load a certificate chain into the context from a + * file. + * + * @param filename The name of the file containing the certificate. The file + * must use the PEM format. + * + * @param ec Set to indicate what error occurred, if any. + */ + ASIO_DECL asio::error_code use_certificate_chain_file( + const std::string& filename, asio::error_code& ec); + + /// Use a private key from a file. + /** + * This function is used to load a private key into the context from a file. + * + * @param filename The name of the file containing the private key. + * + * @param format The file format (ASN.1 or PEM). + * + * @throws asio::system_error Thrown on failure. + */ + ASIO_DECL void use_private_key_file( + const std::string& filename, file_format format); + + /// Use a private key from a file. + /** + * This function is used to load a private key into the context from a file. + * + * @param filename The name of the file containing the private key. + * + * @param format The file format (ASN.1 or PEM). + * + * @param ec Set to indicate what error occurred, if any. + */ + ASIO_DECL asio::error_code use_private_key_file( + const std::string& filename, file_format format, + asio::error_code& ec); + + /// Use an RSA private key from a file. + /** + * This function is used to load an RSA private key into the context from a + * file. + * + * @param filename The name of the file containing the RSA private key. + * + * @param format The file format (ASN.1 or PEM). + * + * @throws asio::system_error Thrown on failure. + */ + ASIO_DECL void use_rsa_private_key_file( + const std::string& filename, file_format format); + + /// Use an RSA private key from a file. + /** + * This function is used to load an RSA private key into the context from a + * file. + * + * @param filename The name of the file containing the RSA private key. + * + * @param format The file format (ASN.1 or PEM). + * + * @param ec Set to indicate what error occurred, if any. + */ + ASIO_DECL asio::error_code use_rsa_private_key_file( + const std::string& filename, file_format format, + asio::error_code& ec); + + /// Use the specified file to obtain the temporary Diffie-Hellman parameters. + /** + * This function is used to load Diffie-Hellman parameters into the context + * from a file. + * + * @param filename The name of the file containing the Diffie-Hellman + * parameters. The file must use the PEM format. + * + * @throws asio::system_error Thrown on failure. + */ + ASIO_DECL void use_tmp_dh_file(const std::string& filename); + + /// Use the specified file to obtain the temporary Diffie-Hellman parameters. + /** + * This function is used to load Diffie-Hellman parameters into the context + * from a file. + * + * @param filename The name of the file containing the Diffie-Hellman + * parameters. The file must use the PEM format. + * + * @param ec Set to indicate what error occurred, if any. + */ + ASIO_DECL asio::error_code use_tmp_dh_file( + const std::string& filename, asio::error_code& ec); + + /// Set the password callback. + /** + * This function is used to specify a callback function to obtain password + * information about an encrypted key in PEM format. + * + * @param callback The function object to be used for obtaining the password. + * The function signature of the handler must be: + * @code std::string password_callback( + * std::size_t max_length, // The maximum size for a password. + * password_purpose purpose // Whether password is for reading or writing. + * ); @endcode + * The return value of the callback is a string containing the password. + * + * @throws asio::system_error Thrown on failure. + */ + template + void set_password_callback(PasswordCallback callback); + + /// Set the password callback. + /** + * This function is used to specify a callback function to obtain password + * information about an encrypted key in PEM format. + * + * @param callback The function object to be used for obtaining the password. + * The function signature of the handler must be: + * @code std::string password_callback( + * std::size_t max_length, // The maximum size for a password. + * password_purpose purpose // Whether password is for reading or writing. + * ); @endcode + * The return value of the callback is a string containing the password. + * + * @param ec Set to indicate what error occurred, if any. + */ + template + asio::error_code set_password_callback(PasswordCallback callback, + asio::error_code& ec); + +private: + // Helper function used to set a password callback. + ASIO_DECL asio::error_code do_set_password_callback( + detail::password_callback_base* callback, asio::error_code& ec); + + // Callback used when the SSL implementation wants a password. + ASIO_DECL static int password_callback_function( + char* buf, int size, int purpose, void* data); + + // The underlying native implementation. + native_handle_type handle_; + + // Ensure openssl is initialised. + asio::ssl::detail::openssl_init<> init_; +}; + +#endif // defined(ASIO_ENABLE_OLD_SSL) + } // namespace ssl } // namespace asio +#include "asio/detail/pop_options.hpp" + +#include "asio/ssl/impl/context.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/ssl/impl/context.ipp" +#endif // defined(ASIO_HEADER_ONLY) + #endif // ASIO_SSL_CONTEXT_HPP diff --git a/asio/include/asio/ssl/context_base.hpp b/asio/include/asio/ssl/context_base.hpp index 7636bede..b283cbfc 100644 --- a/asio/include/asio/ssl/context_base.hpp +++ b/asio/include/asio/ssl/context_base.hpp @@ -2,7 +2,7 @@ // ssl/context_base.hpp // ~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/asio/include/asio/ssl/context_service.hpp b/asio/include/asio/ssl/context_service.hpp index 439d23cc..6a09576f 100644 --- a/asio/include/asio/ssl/context_service.hpp +++ b/asio/include/asio/ssl/context_service.hpp @@ -2,8 +2,7 @@ // ssl/context_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com -// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -18,15 +17,21 @@ #include "asio/detail/config.hpp" -#include "asio/ssl/old/context_service.hpp" +#if defined(ASIO_ENABLE_OLD_SSL) +# include "asio/ssl/old/context_service.hpp" +#endif // defined(ASIO_ENABLE_OLD_SSL) #include "asio/detail/push_options.hpp" namespace asio { namespace ssl { +#if defined(ASIO_ENABLE_OLD_SSL) + using asio::ssl::old::context_service; +#endif // defined(ASIO_ENABLE_OLD_SSL) + } // namespace ssl } // namespace asio diff --git a/asio/include/asio/ssl/detail/buffer_space.hpp b/asio/include/asio/ssl/detail/buffer_space.hpp new file mode 100644 index 00000000..e0b96ab9 --- /dev/null +++ b/asio/include/asio/ssl/detail/buffer_space.hpp @@ -0,0 +1,71 @@ +// +// ssl/detail/buffer_space.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_SSL_DETAIL_BUFFER_SPACE_HPP +#define ASIO_SSL_DETAIL_BUFFER_SPACE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_ENABLE_OLD_SSL) +# include +# include "asio/buffer.hpp" +#endif // !defined(ASIO_ENABLE_OLD_SSL) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ssl { +namespace detail { + +#if !defined(ASIO_ENABLE_OLD_SSL) + +struct buffer_space +{ + // Returned by functions to indicate that the engine wants input. The input + // buffer should be updated to point to the data. + static const int want_input = -1; + + // Returned by functions to indicate that the engine wants to write output. + // The output buffer points to the data to be written. + static const int want_output = -2; + + // A buffer that may be used to prepare output intended for the transport. + std::vector output_buffer; + + // The buffer pointing to the data to be written by the transport. + asio::const_buffer output; + + // A buffer that may be used to read input intended for the engine. + std::vector input_buffer; + + // The buffer pointing to the engine's unconsumed input. + asio::const_buffer input; + + // Constructor sets up the buffers. + buffer_space() + : output_buffer(16384), + input_buffer(16384) + { + } +}; + +#endif // !defined(ASIO_ENABLE_OLD_SSL) + +} // namespace detail +} // namespace ssl +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_SSL_DETAIL_BUFFER_SPACE_HPP diff --git a/asio/include/asio/ssl/detail/engine.hpp b/asio/include/asio/ssl/detail/engine.hpp new file mode 100644 index 00000000..7b8e6aa2 --- /dev/null +++ b/asio/include/asio/ssl/detail/engine.hpp @@ -0,0 +1,117 @@ +// +// ssl/detail/engine.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_SSL_DETAIL_ENGINE_HPP +#define ASIO_SSL_DETAIL_ENGINE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_ENABLE_OLD_SSL) +# include "asio/detail/static_mutex.hpp" +# include "asio/ssl/detail/buffer_space.hpp" +# include "asio/ssl/detail/openssl_types.hpp" +# include "asio/ssl/stream_base.hpp" +#endif // !defined(ASIO_ENABLE_OLD_SSL) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ssl { +namespace detail { + +#if !defined(ASIO_ENABLE_OLD_SSL) + +class engine +{ +public: + // Construct a new engine for the specified context. + ASIO_DECL explicit engine(SSL_CTX* context); + + // Destructor. + ASIO_DECL ~engine(); + + // Get the underlying implementation in the native type. + ASIO_DECL SSL* native_handle(); + + // Perform an SSL handshake using either SSL_connect (client-side) or + // SSL_accept (server-side). + ASIO_DECL int handshake(stream_base::handshake_type type, + buffer_space& space, asio::error_code& ec); + + // Perform a graceful shutdown of the SSL session. + ASIO_DECL int shutdown(buffer_space& space, + asio::error_code& ec); + + // Write bytes to the SSL session. + ASIO_DECL int write(const asio::const_buffer& data, + buffer_space& space, asio::error_code& ec); + + // Read bytes from the SSL session. + ASIO_DECL int read(const asio::mutable_buffer& data, + buffer_space& space, asio::error_code& ec); + + // Map an error::eof code returned by the underlying transport according to + // the type and state of the SSL session. Returns a const reference to the + // error code object, suitable for passing to a completion handler. + ASIO_DECL const asio::error_code& map_error_code( + asio::error_code& ec) const; + +private: + // Disallow copying and assignment. + engine(const engine&); + engine& operator=(const engine&); + + // The SSL_accept function may not be thread safe. This mutex is used to + // protect all calls to the SSL_accept function. + ASIO_DECL static asio::detail::static_mutex& accept_mutex(); + + // Perform one operation. Returns >= 0 on success or error, want_read if the + // operation needs more input, or want_write if it needs to write some output + // before the operation can complete. + ASIO_DECL int perform(int (engine::* op)(void*, std::size_t), + void* data, std::size_t length, + buffer_space& space, asio::error_code& ec); + + // Adapt the SSL_accept function to the signature needed for perform(). + ASIO_DECL int do_accept(void*, std::size_t); + + // Adapt the SSL_connect function to the signature needed for perform(). + ASIO_DECL int do_connect(void*, std::size_t); + + // Adapt the SSL_shutdown function to the signature needed for perform(). + ASIO_DECL int do_shutdown(void*, std::size_t); + + // Adapt the SSL_read function to the signature needed for perform(). + ASIO_DECL int do_read(void* data, std::size_t length); + + // Adapt the SSL_write function to the signature needed for perform(). + ASIO_DECL int do_write(void* data, std::size_t length); + + SSL* ssl_; + BIO* ext_bio_; +}; + +#endif // !defined(ASIO_ENABLE_OLD_SSL) + +} // namespace detail +} // namespace ssl +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/ssl/detail/impl/engine.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_SSL_DETAIL_ENGINE_HPP diff --git a/asio/include/asio/ssl/detail/handshake_op.hpp b/asio/include/asio/ssl/detail/handshake_op.hpp new file mode 100644 index 00000000..85cdfcb7 --- /dev/null +++ b/asio/include/asio/ssl/detail/handshake_op.hpp @@ -0,0 +1,107 @@ +// +// ssl/detail/handshake_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_SSL_DETAIL_HANDSHAKE_OP_HPP +#define ASIO_SSL_DETAIL_HANDSHAKE_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_ENABLE_OLD_SSL) +# include "asio/detail/handler_alloc_helpers.hpp" +# include "asio/detail/handler_invoke_helpers.hpp" +# include "asio/ssl/detail/buffer_space.hpp" +# include "asio/ssl/detail/engine.hpp" +# include "asio/ssl/detail/transport.hpp" +#endif // !defined(ASIO_ENABLE_OLD_SSL) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ssl { +namespace detail { + +#if !defined(ASIO_ENABLE_OLD_SSL) + +template +class handshake_op +{ +public: + handshake_op(detail::engine& engine, detail::transport& transport, + detail::buffer_space& space, stream_base::handshake_type type, + HandshakeHandler& handler) + : engine_(engine), + transport_(transport), + space_(space), + type_(type), + handler_(ASIO_MOVE_CAST(HandshakeHandler)(handler)) + { + } + + void operator()(asio::error_code ec, int result, int start = 0) + { + switch (start) + { + case 1: + do + { + result = engine_.handshake(type_, space_, ec); + transport_.async(result, space_, ec, start, *this); + return; default:; + } while (result < 0); + + handler_(engine_.map_error_code(ec)); + } + } + +//private: + detail::engine& engine_; + detail::transport& transport_; + detail::buffer_space& space_; + stream_base::handshake_type type_; + HandshakeHandler handler_; +}; + +template +inline void* asio_handler_allocate(std::size_t size, + handshake_op* this_handler) +{ + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); +} + +template +inline void asio_handler_deallocate(void* pointer, std::size_t size, + handshake_op* this_handler) +{ + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); +} + +template +inline void asio_handler_invoke(const Function& function, + handshake_op* this_handler) +{ + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +} + +#endif // !defined(ASIO_ENABLE_OLD_SSL) + +} // namespace detail +} // namespace ssl +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_SSL_DETAIL_HANDSHAKE_OP_HPP diff --git a/asio/include/asio/ssl/detail/impl/engine.ipp b/asio/include/asio/ssl/detail/impl/engine.ipp new file mode 100644 index 00000000..3f873892 --- /dev/null +++ b/asio/include/asio/ssl/detail/impl/engine.ipp @@ -0,0 +1,219 @@ +// +// ssl/detail/impl/engine.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_SSL_DETAIL_IMPL_ENGINE_IPP +#define ASIO_SSL_DETAIL_IMPL_ENGINE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_ENABLE_OLD_SSL) +# include "asio/ssl/detail/engine.hpp" +#endif // !defined(ASIO_ENABLE_OLD_SSL) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ssl { +namespace detail { + +#if !defined(ASIO_ENABLE_OLD_SSL) + +engine::engine(SSL_CTX* context) + : ssl_(::SSL_new(context)) +{ + accept_mutex().init(); + + ::SSL_set_mode(ssl_, SSL_MODE_ENABLE_PARTIAL_WRITE); + ::SSL_set_mode(ssl_, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); + ::BIO* int_bio = 0; + ::BIO_new_bio_pair(&int_bio, 0, &ext_bio_, 0); + ::SSL_set_bio(ssl_, int_bio, int_bio); +} + +engine::~engine() +{ + ::BIO_free(ext_bio_); + ::SSL_free(ssl_); +} + +SSL* engine::native_handle() +{ + return ssl_; +} + +int engine::handshake(stream_base::handshake_type type, + buffer_space& space, asio::error_code& ec) +{ + return perform((type == asio::ssl::stream_base::client) + ? &engine::do_connect : &engine::do_accept, 0, 0, space, ec); +} + +int engine::shutdown(buffer_space& space, asio::error_code& ec) +{ + return perform(&engine::do_shutdown, 0, 0, space, ec); +} + +int engine::write(const asio::const_buffer& data, + buffer_space& space, asio::error_code& ec) +{ + return perform(&engine::do_write, + const_cast(asio::buffer_cast(data)), + asio::buffer_size(data), space, ec); +} + +int engine::read(const asio::mutable_buffer& data, + buffer_space& space, asio::error_code& ec) +{ + return perform(&engine::do_read, + asio::buffer_cast(data), + asio::buffer_size(data), space, ec); +} + +const asio::error_code& engine::map_error_code( + asio::error_code& ec) const +{ + // We only want to map the error::eof code. + if (ec != asio::error::eof) + return ec; + + // If there's data yet to be read, it's an error. + if (BIO_wpending(ext_bio_)) + { + ec = asio::error_code( + ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SHORT_READ), + asio::error::get_ssl_category()); + return ec; + } + + // SSL v2 doesn't provide a protocol-level shutdown, so an eof on the + // underlying transport is passed through. + if (ssl_ && ssl_->version == SSL2_VERSION) + return ec; + + // Otherwise, the peer should have negotiated a proper shutdown. + ec = asio::error_code( + ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SHORT_READ), + asio::error::get_ssl_category()); + return ec; +} + +asio::detail::static_mutex& engine::accept_mutex() +{ + static asio::detail::static_mutex mutex = ASIO_STATIC_MUTEX_INIT; + return mutex; +} + +int engine::perform(int (engine::* op)(void*, std::size_t), + void* data, std::size_t length, + buffer_space& space, asio::error_code& ec) +{ + for (;;) + { + std::size_t pending_output_before = ::BIO_ctrl_pending(ext_bio_); + int result = (this->*op)(data, length); + int ssl_error = ::SSL_get_error(ssl_, result); + int sys_error = ::ERR_get_error(); + std::size_t pending_output_after = ::BIO_ctrl_pending(ext_bio_); + + if (ssl_error == SSL_ERROR_SSL) + { + ec = asio::error_code(sys_error, + asio::error::get_ssl_category()); + return 0; + } + + if (ssl_error == SSL_ERROR_SYSCALL) + { + ec = asio::error_code(sys_error, + asio::error::get_system_category()); + return 0; + } + + if (pending_output_after > 0 && asio::buffer_size(space.output) == 0) + { + int length = ::BIO_read(ext_bio_, &space.output_buffer[0], 16384); + space.output = asio::buffer(space.output_buffer, length); + } + + if (result > 0) + { + ec = asio::error_code(); + return result; + } + + if (ssl_error == SSL_ERROR_WANT_WRITE + || pending_output_after > pending_output_before) + { + ec = asio::error_code(); + return buffer_space::want_output; + } + else if (ssl_error == SSL_ERROR_WANT_READ) + { + if (asio::buffer_size(space.input) == 0) + { + ec = asio::error_code(); + return buffer_space::want_input; + } + + int length = ::BIO_write(ext_bio_, + asio::buffer_cast(space.input), + static_cast(asio::buffer_size(space.input))); + space.input = space.input + length; + } + else if (::SSL_get_shutdown(ssl_) & SSL_RECEIVED_SHUTDOWN) + { + ec = asio::error::eof; + return 0; + } + } +} + +int engine::do_accept(void*, std::size_t) +{ + asio::detail::static_mutex lock(accept_mutex()); + return ::SSL_accept(ssl_); +} + +int engine::do_connect(void*, std::size_t) +{ + return ::SSL_connect(ssl_); +} + +int engine::do_shutdown(void*, std::size_t) +{ + int result = ::SSL_shutdown(ssl_); + if (result == 0) + result = ::SSL_shutdown(ssl_); + return result; +} + +int engine::do_read(void* data, std::size_t length) +{ + return ::SSL_read(ssl_, data, length < INT_MAX ? length : INT_MAX); +} + +int engine::do_write(void* data, std::size_t length) +{ + return ::SSL_write(ssl_, data, length < INT_MAX ? length : INT_MAX); +} + +#endif // !defined(ASIO_ENABLE_OLD_SSL) + +} // namespace detail +} // namespace ssl +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_SSL_DETAIL_IMPL_ENGINE_IPP diff --git a/asio/include/asio/ssl/detail/openssl_types.hpp b/asio/include/asio/ssl/detail/openssl_types.hpp index fbe1b743..d2e37874 100644 --- a/asio/include/asio/ssl/detail/openssl_types.hpp +++ b/asio/include/asio/ssl/detail/openssl_types.hpp @@ -2,7 +2,7 @@ // ssl/detail/openssl_types.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/asio/include/asio/ssl/detail/password_callback.hpp b/asio/include/asio/ssl/detail/password_callback.hpp new file mode 100644 index 00000000..08be1e43 --- /dev/null +++ b/asio/include/asio/ssl/detail/password_callback.hpp @@ -0,0 +1,72 @@ +// +// ssl/detail/password_callback.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_SSL_DETAIL_PASSWORD_CALLBACK_HPP +#define ASIO_SSL_DETAIL_PASSWORD_CALLBACK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_ENABLE_OLD_SSL) +# include +# include +# include "asio/ssl/context_base.hpp" +#endif // !defined(ASIO_ENABLE_OLD_SSL) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ssl { +namespace detail { + +#if !defined(ASIO_ENABLE_OLD_SSL) + +class password_callback_base +{ +public: + virtual ~password_callback_base() + { + } + + virtual std::string call(std::size_t size, + context_base::password_purpose purpose) = 0; +}; + +template +class password_callback : public password_callback_base +{ +public: + explicit password_callback(PasswordCallback callback) + : callback_(callback) + { + } + + virtual std::string call(std::size_t size, + context_base::password_purpose purpose) + { + return callback_(size, purpose); + } + +private: + PasswordCallback callback_; +}; + +#endif // !defined(ASIO_ENABLE_OLD_SSL) + +} // namespace detail +} // namespace ssl +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_SSL_DETAIL_PASSWORD_CALLBACK_HPP diff --git a/asio/include/asio/ssl/detail/read_op.hpp b/asio/include/asio/ssl/detail/read_op.hpp new file mode 100644 index 00000000..879800df --- /dev/null +++ b/asio/include/asio/ssl/detail/read_op.hpp @@ -0,0 +1,114 @@ +// +// ssl/detail/read_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_SSL_DETAIL_READ_OP_HPP +#define ASIO_SSL_DETAIL_READ_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_ENABLE_OLD_SSL) +# include "asio/detail/buffer_sequence_adapter.hpp" +# include "asio/detail/handler_alloc_helpers.hpp" +# include "asio/detail/handler_invoke_helpers.hpp" +# include "asio/ssl/detail/buffer_space.hpp" +# include "asio/ssl/detail/engine.hpp" +# include "asio/ssl/detail/transport.hpp" +#endif // !defined(ASIO_ENABLE_OLD_SSL) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ssl { +namespace detail { + +#if !defined(ASIO_ENABLE_OLD_SSL) + +template +class read_op +{ +public: + read_op(detail::engine& engine, detail::transport& transport, + detail::buffer_space& space, const MutableBufferSequence& buffers, + ReadHandler& handler) + : engine_(engine), + transport_(transport), + space_(space), + buffers_(buffers), + handler_(ASIO_MOVE_CAST(ReadHandler)(handler)) + { + } + + void operator()(asio::error_code ec, int result, int start = 0) + { + asio::mutable_buffer buffer = + asio::detail::buffer_sequence_adapter::first(buffers_); + + switch (start) + { + case 1: + do + { + result = engine_.read(buffer, space_, ec); + transport_.async(result, space_, ec, start, *this); + return; default:; + } while (result < 0); + + handler_(engine_.map_error_code(ec), + static_cast(result)); + } + } + +//private: + detail::engine& engine_; + detail::transport& transport_; + detail::buffer_space& space_; + MutableBufferSequence buffers_; + ReadHandler handler_; +}; + +template +inline void* asio_handler_allocate(std::size_t size, + read_op* this_handler) +{ + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); +} + +template +inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_op* this_handler) +{ + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); +} + +template +inline void asio_handler_invoke(const Function& function, + read_op* this_handler) +{ + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +} + +#endif // !defined(ASIO_ENABLE_OLD_SSL) + +} // namespace detail +} // namespace ssl +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_SSL_DETAIL_READ_OP_HPP diff --git a/asio/include/asio/ssl/detail/shutdown_op.hpp b/asio/include/asio/ssl/detail/shutdown_op.hpp new file mode 100644 index 00000000..817b7580 --- /dev/null +++ b/asio/include/asio/ssl/detail/shutdown_op.hpp @@ -0,0 +1,104 @@ +// +// ssl/detail/shutdown_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_SSL_DETAIL_SHUTDOWN_OP_HPP +#define ASIO_SSL_DETAIL_SHUTDOWN_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_ENABLE_OLD_SSL) +# include "asio/detail/handler_alloc_helpers.hpp" +# include "asio/detail/handler_invoke_helpers.hpp" +# include "asio/ssl/detail/buffer_space.hpp" +# include "asio/ssl/detail/engine.hpp" +# include "asio/ssl/detail/transport.hpp" +#endif // !defined(ASIO_ENABLE_OLD_SSL) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ssl { +namespace detail { + +#if !defined(ASIO_ENABLE_OLD_SSL) + +template +class shutdown_op +{ +public: + shutdown_op(detail::engine& engine, detail::transport& transport, + detail::buffer_space& space, ShutdownHandler& handler) + : engine_(engine), + transport_(transport), + space_(space), + handler_(ASIO_MOVE_CAST(ShutdownHandler)(handler)) + { + } + + void operator()(asio::error_code ec, int result, int start = 0) + { + switch (start) + { + case 1: + do + { + result = engine_.shutdown(space_, ec); + transport_.async(result, space_, ec, start, *this); + return; default:; + } while (result < 0); + + handler_(engine_.map_error_code(ec)); + } + } + +//private: + detail::engine& engine_; + detail::transport& transport_; + detail::buffer_space& space_; + ShutdownHandler handler_; +}; + +template +inline void* asio_handler_allocate(std::size_t size, + shutdown_op* this_handler) +{ + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); +} + +template +inline void asio_handler_deallocate(void* pointer, std::size_t size, + shutdown_op* this_handler) +{ + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); +} + +template +inline void asio_handler_invoke(const Function& function, + shutdown_op* this_handler) +{ + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +} + +#endif // !defined(ASIO_ENABLE_OLD_SSL) + +} // namespace detail +} // namespace ssl +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_SSL_DETAIL_SHUTDOWN_OP_HPP diff --git a/asio/include/asio/ssl/detail/transport.hpp b/asio/include/asio/ssl/detail/transport.hpp new file mode 100644 index 00000000..e578e22f --- /dev/null +++ b/asio/include/asio/ssl/detail/transport.hpp @@ -0,0 +1,125 @@ +// +// ssl/detail/transport.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_SSL_DETAIL_TRANSPORT_HPP +#define ASIO_SSL_DETAIL_TRANSPORT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_ENABLE_OLD_SSL) +# include "asio/deadline_timer.hpp" +# include "asio/ssl/detail/buffer_space.hpp" +# include "asio/ssl/detail/transport_op.hpp" +# include "asio/write.hpp" +# include +#endif // !defined(ASIO_ENABLE_OLD_SSL) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ssl { +namespace detail { + +#if !defined(ASIO_ENABLE_OLD_SSL) + +template +class transport +{ +public: + // The type of the next layer. + typedef typename boost::remove_reference::type next_layer_type; + + // The type of the lowest layer. + typedef typename next_layer_type::lowest_layer_type lowest_layer_type; + + // Constructor initialises the underlying stream. + template + explicit transport(Arg& arg) + : next_layer_(arg), + pending_read_(next_layer_.lowest_layer().get_io_service()), + pending_write_(next_layer_.lowest_layer().get_io_service()) + { + pending_read_.expires_at(boost::posix_time::neg_infin); + pending_write_.expires_at(boost::posix_time::neg_infin); + } + + asio::io_service& get_io_service() + { + return next_layer_.lowest_layer().get_io_service(); + } + + next_layer_type& next_layer() + { + return next_layer_; + } + + const next_layer_type& next_layer() const + { + return next_layer_; + } + + lowest_layer_type& lowest_layer() + { + return next_layer_.lowest_layer(); + } + + const lowest_layer_type& lowest_layer() const + { + return next_layer_.lowest_layer(); + } + + int sync(int result, buffer_space& space, asio::error_code& ec) + { + switch (result) + { + case detail::buffer_space::want_input: + space.input = asio::buffer(space.input_buffer, + next_layer_.read_some(asio::buffer(space.input_buffer), ec)); + break; + default: + if (ec || asio::buffer_size(space.output) == 0) + break; + case detail::buffer_space::want_output: + space.output = + space.output + asio::write(next_layer_, + asio::buffer(space.output), ec); + break; + } + return ec ? 0 : result; + } + + template + void async(int result, buffer_space& space, + const asio::error_code& ec, int start, Handler& handler) + { + transport_op( + next_layer_, pending_read_, pending_write_, result, space, ec, handler)( + asio::error_code(), 0, start ? -1 : 1); + } + +private: + Stream next_layer_; + asio::deadline_timer pending_read_; + asio::deadline_timer pending_write_; +}; + +#endif // !defined(ASIO_ENABLE_OLD_SSL) + +} // namespace detail +} // namespace ssl +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_SSL_DETAIL_TRANSPORT_HPP diff --git a/asio/include/asio/ssl/detail/transport_op.hpp b/asio/include/asio/ssl/detail/transport_op.hpp new file mode 100644 index 00000000..38ee18f0 --- /dev/null +++ b/asio/include/asio/ssl/detail/transport_op.hpp @@ -0,0 +1,207 @@ +// +// ssl/detail/transport_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_SSL_DETAIL_TRANSPORT_OP_HPP +#define ASIO_SSL_DETAIL_TRANSPORT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_ENABLE_OLD_SSL) +# include "asio/deadline_timer.hpp" +# include "asio/detail/handler_alloc_helpers.hpp" +# include "asio/detail/handler_invoke_helpers.hpp" +# include "asio/ssl/detail/buffer_space.hpp" +# include "asio/ssl/detail/engine.hpp" +# include "asio/ssl/detail/transport.hpp" +# include "asio/write.hpp" +#endif // !defined(ASIO_ENABLE_OLD_SSL) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ssl { +namespace detail { + +#if !defined(ASIO_ENABLE_OLD_SSL) + +template +class transport_op +{ +public: + transport_op(Stream& next_layer, asio::deadline_timer& pending_read, + asio::deadline_timer& pending_write, int result, + detail::buffer_space& space, const asio::error_code& ec, + Handler& handler) + : next_layer_(next_layer), + pending_read_(pending_read), + pending_write_(pending_write), + result_(result), + space_(space), + ec_(ec), + handler_(ASIO_MOVE_CAST(Handler)(handler)) + { + } + + void operator()(const asio::error_code& ec, + std::size_t bytes_transferred = 0, int start = 0) + { + switch (start) + { + case -1: // Called from initiating function. + case 1: // Called after at least one async operation. + switch (result_) + { + case detail::buffer_space::want_input: + // The engine wants more data to be read from input. However, we cannot + // allow more than one read operation at a time on the underlying + // transport. The pending_read_ timer's expiry is to pos_infin if a + // read is in progress, and neg_infin otherwise. + if (pending_read_.expires_at() == boost::posix_time::neg_infin) + { + // Start reading some data from the underlying transport. + next_layer_.async_read_some( + asio::buffer(space_.input_buffer), *this); + + // Prevent other read operations from being started. + pending_read_.expires_at(boost::posix_time::pos_infin); + } + else + { + // Wait until the current read operation completes. + pending_read_.async_wait(*this); + } + break; + + default: + // The SSL operation as done, but there might be some data to be + // written to the output. If there isn't anything to write then we can + // invoke the handler, but we have to keep in mind that this function + // might be being called from the async operation's initiating + // function. In this case we're not allowed to call the handler + // directly. Instead, issue a zero-sized read so that the handler runs + // "as-if" posted using io_service::post(). + if (ec_ || asio::buffer_size(space_.output) == 0) + { + if (start == -1) + { + next_layer_.async_read_some( + asio::buffer(space_.input_buffer, 0), *this); + } + else + { + // Indicate that we should continue on to run handler directly. + start = 0; + } + break; + } + // Fall through to process the pending output. + + case detail::buffer_space::want_output: + // The engine wants some data to be written to the output. However, we + // cannot allow more than one write operation at a time on the + // underlying transport. The pending_write_ timer's expiry is to + // pos_infin if a write is in progress, and neg_infin otherwise. + if (pending_write_.expires_at() == boost::posix_time::neg_infin) + { + // Start writing all the data to the underlying transport. + asio::async_write(next_layer_, + asio::buffer(space_.output), *this); + + // Prevent other write operations from being started. + pending_write_.expires_at(boost::posix_time::pos_infin); + } + else if (result_ == detail::buffer_space::want_output) + { + // Wait until the current write operation completes. + pending_write_.async_wait(*this); + } + break; + } + + // Yield control if an async operation was started. + if (start) return; default: + if (!ec_) ec_ = ec; + + switch (result_) + { + case detail::buffer_space::want_input: + // Add received data to the engine's pending input. + space_.input = asio::buffer(space_.input_buffer, bytes_transferred); + + // Release any waiting read operations. + pending_read_.expires_at(boost::posix_time::neg_infin); + break; + + default: + if (ec || bytes_transferred == 0) + break; + // Fall through to remove the pending output. + + case detail::buffer_space::want_output: + // Remove written data from the engine's pending output. + space_.output = space_.output + bytes_transferred; + + // Release any waiting write operations. + pending_write_.expires_at(boost::posix_time::neg_infin); + break; + } + + handler_(static_cast(ec_), + static_cast(ec ? 0 : result_)); + } + } + +//private: + Stream& next_layer_; + asio::deadline_timer& pending_read_; + asio::deadline_timer& pending_write_; + int result_; + detail::buffer_space& space_; + asio::error_code ec_; + Handler handler_; +}; + +template +inline void* asio_handler_allocate(std::size_t size, + transport_op* this_handler) +{ + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); +} + +template +inline void asio_handler_deallocate(void* pointer, std::size_t size, + transport_op* this_handler) +{ + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); +} + +template +inline void asio_handler_invoke(const Function& function, + transport_op* this_handler) +{ + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +} + +#endif // !defined(ASIO_ENABLE_OLD_SSL) + +} // namespace detail +} // namespace ssl +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_SSL_DETAIL_TRANSPORT_OP_HPP diff --git a/asio/include/asio/ssl/detail/write_op.hpp b/asio/include/asio/ssl/detail/write_op.hpp new file mode 100644 index 00000000..ebcfb9f2 --- /dev/null +++ b/asio/include/asio/ssl/detail/write_op.hpp @@ -0,0 +1,114 @@ +// +// ssl/detail/write_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_SSL_DETAIL_WRITE_OP_HPP +#define ASIO_SSL_DETAIL_WRITE_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_ENABLE_OLD_SSL) +# include "asio/detail/buffer_sequence_adapter.hpp" +# include "asio/detail/handler_alloc_helpers.hpp" +# include "asio/detail/handler_invoke_helpers.hpp" +# include "asio/ssl/detail/buffer_space.hpp" +# include "asio/ssl/detail/engine.hpp" +# include "asio/ssl/detail/transport.hpp" +#endif // !defined(ASIO_ENABLE_OLD_SSL) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ssl { +namespace detail { + +#if !defined(ASIO_ENABLE_OLD_SSL) + +template +class write_op +{ +public: + write_op(detail::engine& engine, detail::transport& transport, + detail::buffer_space& space, const ConstBufferSequence& buffers, + WriteHandler& handler) + : engine_(engine), + transport_(transport), + space_(space), + buffers_(buffers), + handler_(ASIO_MOVE_CAST(WriteHandler)(handler)) + { + } + + void operator()(asio::error_code ec, int result, int start = 0) + { + asio::const_buffer buffer = + asio::detail::buffer_sequence_adapter::first(buffers_); + + switch (start) + { + case 1: + do + { + result = engine_.write(buffer, space_, ec); + transport_.async(result, space_, ec, start, *this); + return; default:; + } while (result < 0); + + handler_(engine_.map_error_code(ec), + static_cast(result)); + } + } + +//private: + detail::engine& engine_; + detail::transport& transport_; + detail::buffer_space& space_; + ConstBufferSequence buffers_; + WriteHandler handler_; +}; + +template +inline void* asio_handler_allocate(std::size_t size, + write_op* this_handler) +{ + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); +} + +template +inline void asio_handler_deallocate(void* pointer, std::size_t size, + write_op* this_handler) +{ + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); +} + +template +inline void asio_handler_invoke(const Function& function, + write_op* this_handler) +{ + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +} + +#endif // !defined(ASIO_ENABLE_OLD_SSL) + +} // namespace detail +} // namespace ssl +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_SSL_DETAIL_WRITE_OP_HPP diff --git a/asio/include/asio/ssl/impl/context.hpp b/asio/include/asio/ssl/impl/context.hpp new file mode 100644 index 00000000..e51748a9 --- /dev/null +++ b/asio/include/asio/ssl/impl/context.hpp @@ -0,0 +1,55 @@ +// +// ssl/impl/context.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com +// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_SSL_IMPL_CONTEXT_HPP +#define ASIO_SSL_IMPL_CONTEXT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_ENABLE_OLD_SSL) +# include "asio/detail/throw_error.hpp" +#endif // !defined(ASIO_ENABLE_OLD_SSL) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ssl { + +#if !defined(ASIO_ENABLE_OLD_SSL) + +template +void context::set_password_callback(PasswordCallback callback) +{ + asio::error_code ec; + this->set_password_callback(callback, ec); + asio::detail::throw_error(ec, "set_password_callback"); +} + +template +asio::error_code context::set_password_callback( + PasswordCallback callback, asio::error_code& ec) +{ + return do_set_password_callback( + new detail::password_callback(callback), ec); +} + +#endif // !defined(ASIO_ENABLE_OLD_SSL) + +} // namespace ssl +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_SSL_IMPL_CONTEXT_HPP diff --git a/asio/include/asio/ssl/impl/context.ipp b/asio/include/asio/ssl/impl/context.ipp new file mode 100644 index 00000000..fc71a22e --- /dev/null +++ b/asio/include/asio/ssl/impl/context.ipp @@ -0,0 +1,431 @@ +// +// ssl/impl/context.ipp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com +// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_SSL_IMPL_CONTEXT_IPP +#define ASIO_SSL_IMPL_CONTEXT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_ENABLE_OLD_SSL) +# include +# include "asio/detail/throw_error.hpp" +# include "asio/error.hpp" +# include "asio/ssl/context.hpp" +# include "asio/ssl/error.hpp" +#endif // !defined(ASIO_ENABLE_OLD_SSL) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ssl { + +#if !defined(ASIO_ENABLE_OLD_SSL) + +context::context(context::method m) + : handle_(0) +{ + switch (m) + { + case context::sslv2: + handle_ = ::SSL_CTX_new(::SSLv2_method()); + break; + case context::sslv2_client: + handle_ = ::SSL_CTX_new(::SSLv2_client_method()); + break; + case context::sslv2_server: + handle_ = ::SSL_CTX_new(::SSLv2_server_method()); + break; + case context::sslv3: + handle_ = ::SSL_CTX_new(::SSLv3_method()); + break; + case context::sslv3_client: + handle_ = ::SSL_CTX_new(::SSLv3_client_method()); + break; + case context::sslv3_server: + handle_ = ::SSL_CTX_new(::SSLv3_server_method()); + break; + case context::tlsv1: + handle_ = ::SSL_CTX_new(::TLSv1_method()); + break; + case context::tlsv1_client: + handle_ = ::SSL_CTX_new(::TLSv1_client_method()); + break; + case context::tlsv1_server: + handle_ = ::SSL_CTX_new(::TLSv1_server_method()); + break; + case context::sslv23: + handle_ = ::SSL_CTX_new(::SSLv23_method()); + break; + case context::sslv23_client: + handle_ = ::SSL_CTX_new(::SSLv23_client_method()); + break; + case context::sslv23_server: + handle_ = ::SSL_CTX_new(::SSLv23_server_method()); + break; + default: + handle_ = ::SSL_CTX_new(0); + break; + } + + if (handle_ == 0) + { + asio::error_code ec(::ERR_get_error(), + asio::error::get_ssl_category()); + asio::detail::throw_error(ec, "context"); + } +} + +context::context(asio::io_service&, context::method m) + : handle_(0) +{ + context tmp(m); + handle_ = tmp.handle_; + tmp.handle_ = 0; +} + +#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) +context::context(context&& other) +{ + handle_ = other.handle_; + other.handle_ = 0; +} + +context& context::operator=(context&& other) +{ + context tmp(ASIO_MOVE_CAST(context)(*this)); + handle_ = other.handle_; + other.handle_ = 0; + return *this; +} +#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + +context::~context() +{ + if (handle_) + { + /*if (handle_->default_passwd_callback_userdata) + { + password_callback_type* callback = + static_cast( + handle_->default_passwd_callback_userdata); + delete callback; + handle_->default_passwd_callback_userdata = 0; + }*/ + + ::SSL_CTX_free(handle_); + } +} + +context::native_handle_type context::native_handle() +{ + return handle_; +} + +void context::set_options(context::options o) +{ + asio::error_code ec; + set_options(o, ec); + asio::detail::throw_error(ec, "set_options"); +} + +asio::error_code context::set_options( + context::options o, asio::error_code& ec) +{ + ::SSL_CTX_set_options(handle_, o); + + ec = asio::error_code(); + return ec; +} + +void context::set_verify_mode(context::verify_mode v) +{ + asio::error_code ec; + set_verify_mode(v, ec); + asio::detail::throw_error(ec, "set_verify_mode"); +} + +asio::error_code context::set_verify_mode( + context::verify_mode v, asio::error_code& ec) +{ + ::SSL_CTX_set_verify(handle_, v, 0); + + ec = asio::error_code(); + return ec; +} + +void context::load_verify_file(const std::string& filename) +{ + asio::error_code ec; + load_verify_file(filename, ec); + asio::detail::throw_error(ec, "load_verify_file"); +} + +asio::error_code context::load_verify_file( + const std::string& filename, asio::error_code& ec) +{ + if (::SSL_CTX_load_verify_locations(handle_, filename.c_str(), 0) != 1) + { + ec = asio::error_code(::ERR_get_error(), + asio::error::get_ssl_category()); + return ec; + } + + ec = asio::error_code(); + return ec; +} + +void context::add_verify_path(const std::string& path) +{ + asio::error_code ec; + add_verify_path(path, ec); + asio::detail::throw_error(ec, "add_verify_path"); +} + +asio::error_code context::add_verify_path( + const std::string& path, asio::error_code& ec) +{ + if (::SSL_CTX_load_verify_locations(handle_, 0, path.c_str()) != 1) + { + ec = asio::error_code(::ERR_get_error(), + asio::error::get_ssl_category()); + return ec; + } + + ec = asio::error_code(); + return ec; +} + +void context::use_certificate_file( + const std::string& filename, file_format format) +{ + asio::error_code ec; + use_certificate_file(filename, format, ec); + asio::detail::throw_error(ec, "use_certificate_file"); +} + +asio::error_code context::use_certificate_file( + const std::string& filename, file_format format, + asio::error_code& ec) +{ + int file_type; + switch (format) + { + case context_base::asn1: + file_type = SSL_FILETYPE_ASN1; + break; + case context_base::pem: + file_type = SSL_FILETYPE_PEM; + break; + default: + { + ec = asio::error::invalid_argument; + return ec; + } + } + + if (::SSL_CTX_use_certificate_file(handle_, filename.c_str(), file_type) != 1) + { + ec = asio::error_code(::ERR_get_error(), + asio::error::get_ssl_category()); + return ec; + } + + ec = asio::error_code(); + return ec; +} + +void context::use_certificate_chain_file(const std::string& filename) +{ + asio::error_code ec; + use_certificate_chain_file(filename, ec); + asio::detail::throw_error(ec, "use_certificate_chain_file"); +} + +asio::error_code context::use_certificate_chain_file( + const std::string& filename, asio::error_code& ec) +{ + if (::SSL_CTX_use_certificate_chain_file(handle_, filename.c_str()) != 1) + { + ec = asio::error_code(::ERR_get_error(), + asio::error::get_ssl_category()); + return ec; + } + + ec = asio::error_code(); + return ec; +} + +void context::use_private_key_file( + const std::string& filename, context::file_format format) +{ + asio::error_code ec; + use_private_key_file(filename, format, ec); + asio::detail::throw_error(ec, "use_private_key_file"); +} + +asio::error_code context::use_private_key_file( + const std::string& filename, context::file_format format, + asio::error_code& ec) +{ + int file_type; + switch (format) + { + case context_base::asn1: + file_type = SSL_FILETYPE_ASN1; + break; + case context_base::pem: + file_type = SSL_FILETYPE_PEM; + break; + default: + { + ec = asio::error::invalid_argument; + return ec; + } + } + + if (::SSL_CTX_use_PrivateKey_file(handle_, filename.c_str(), file_type) != 1) + { + ec = asio::error_code(::ERR_get_error(), + asio::error::get_ssl_category()); + return ec; + } + + ec = asio::error_code(); + return ec; +} + +void context::use_rsa_private_key_file( + const std::string& filename, context::file_format format) +{ + asio::error_code ec; + use_rsa_private_key_file(filename, format, ec); + asio::detail::throw_error(ec, "use_rsa_private_key_file"); +} + +asio::error_code context::use_rsa_private_key_file( + const std::string& filename, context::file_format format, + asio::error_code& ec) +{ + int file_type; + switch (format) + { + case context_base::asn1: + file_type = SSL_FILETYPE_ASN1; + break; + case context_base::pem: + file_type = SSL_FILETYPE_PEM; + break; + default: + { + ec = asio::error::invalid_argument; + return ec; + } + } + + if (::SSL_CTX_use_RSAPrivateKey_file( + handle_, filename.c_str(), file_type) != 1) + { + ec = asio::error_code(::ERR_get_error(), + asio::error::get_ssl_category()); + return ec; + } + + ec = asio::error_code(); + return ec; +} + +void context::use_tmp_dh_file(const std::string& filename) +{ + asio::error_code ec; + use_tmp_dh_file(filename, ec); + asio::detail::throw_error(ec, "use_tmp_dh_file"); +} + +asio::error_code context::use_tmp_dh_file( + const std::string& filename, asio::error_code& ec) +{ + ::BIO* bio = ::BIO_new_file(filename.c_str(), "r"); + if (!bio) + { + ec = asio::error::invalid_argument; + return ec; + } + + ::DH* dh = ::PEM_read_bio_DHparams(bio, 0, 0, 0); + if (!dh) + { + ::BIO_free(bio); + ec = asio::error::invalid_argument; + return ec; + } + + ::BIO_free(bio); + int result = ::SSL_CTX_set_tmp_dh(handle_, dh); + ::DH_free(dh); + if (result != 1) + { + ec = asio::error_code(::ERR_get_error(), + asio::error::get_ssl_category()); + return ec; + } + + ec = asio::error_code(); + return ec; +} + +asio::error_code context::do_set_password_callback( + detail::password_callback_base* callback, asio::error_code& ec) +{ + if (handle_->default_passwd_callback_userdata) + delete static_cast( + handle_->default_passwd_callback_userdata); + + handle_->default_passwd_callback_userdata = callback; + + SSL_CTX_set_default_passwd_cb(handle_, &context::password_callback_function); + + ec = asio::error_code(); + return ec; +} + +int context::password_callback_function( + char* buf, int size, int purpose, void* data) +{ + using namespace std; // For strncat and strlen. + + if (data) + { + detail::password_callback_base* callback = + static_cast(data); + + std::string passwd = callback->call(static_cast(size), + purpose ? context_base::for_writing : context_base::for_reading); + + *buf = '\0'; + strncat(buf, passwd.c_str(), size); + return strlen(buf); + } + + return 0; +} + +#endif // !defined(ASIO_ENABLE_OLD_SSL) + +} // namespace ssl +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_SSL_IMPL_CONTEXT_IPP diff --git a/asio/include/asio/ssl/impl/src.hpp b/asio/include/asio/ssl/impl/src.hpp index f19b9f54..c6239ab2 100644 --- a/asio/include/asio/ssl/impl/src.hpp +++ b/asio/include/asio/ssl/impl/src.hpp @@ -19,6 +19,8 @@ # error Do not compile Asio library source with ASIO_HEADER_ONLY defined #endif +#include "asio/ssl/impl/context.ipp" #include "asio/ssl/impl/error.ipp" +#include "asio/ssl/detail/impl/engine.ipp" #endif // ASIO_IMPL_SRC_HPP diff --git a/asio/include/asio/ssl/stream.hpp b/asio/include/asio/ssl/stream.hpp index 7275e344..b2bc046a 100644 --- a/asio/include/asio/ssl/stream.hpp +++ b/asio/include/asio/ssl/stream.hpp @@ -2,8 +2,7 @@ // ssl/stream.hpp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com -// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -18,15 +17,473 @@ #include "asio/detail/config.hpp" -#include "asio/ssl/old/stream.hpp" +#if defined(ASIO_ENABLE_OLD_SSL) +# include "asio/ssl/old/stream.hpp" +#else // defined(ASIO_ENABLE_OLD_SSL) +# include "asio/detail/buffer_sequence_adapter.hpp" +# include "asio/ssl/context.hpp" +# include "asio/ssl/detail/buffer_space.hpp" +# include "asio/ssl/detail/engine.hpp" +# include "asio/ssl/detail/handshake_op.hpp" +# include "asio/ssl/detail/read_op.hpp" +# include "asio/ssl/detail/shutdown_op.hpp" +# include "asio/ssl/detail/transport.hpp" +# include "asio/ssl/detail/write_op.hpp" +# include "asio/ssl/stream_base.hpp" +# include +#endif // defined(ASIO_ENABLE_OLD_SSL) #include "asio/detail/push_options.hpp" namespace asio { namespace ssl { +#if defined(ASIO_ENABLE_OLD_SSL) + using asio::ssl::old::stream; +#else // defined(ASIO_ENABLE_OLD_SSL) + +/// Provides stream-oriented functionality using SSL. +/** + * The stream class template provides asynchronous and blocking stream-oriented + * functionality using SSL. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. The application must also ensure that all + * asynchronous operations are performed within the same implicit or explicit + * strand. + * + * @par Example + * To use the SSL stream template with an ip::tcp::socket, you would write: + * @code + * asio::io_service io_service; + * asio::ssl::context context(io_service, asio::ssl::context::sslv23); + * asio::ssl::stream sock(io_service, context); + * @endcode + * + * @par Concepts: + * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream. + */ +template +class stream : public stream_base +{ +public: + /// The native handle type of the SSL stream. + typedef SSL* native_handle_type; + + /// The type of the next layer. + typedef typename boost::remove_reference::type next_layer_type; + + /// The type of the lowest layer. + typedef typename next_layer_type::lowest_layer_type lowest_layer_type; + + /// Construct a stream. + /** + * This constructor creates a stream and initialises the underlying stream + * object. + * + * @param arg The argument to be passed to initialise the underlying stream. + * + * @param context The SSL context to be used for the stream. + */ + template + stream(Arg& arg, context& ctx) + : engine_(ctx.native_handle()), + transport_(arg) + { + } + + /// Destructor. + ~stream() + { + } + + /// Get the io_service associated with the object. + /** + * This function may be used to obtain the io_service object that the stream + * uses to dispatch handlers for asynchronous operations. + * + * @return A reference to the io_service object that stream will use to + * dispatch handlers. Ownership is not transferred to the caller. + */ + asio::io_service& get_io_service() + { + return transport_.get_io_service(); + } + + /// Get the underlying implementation in the native type. + /** + * This function may be used to obtain the underlying implementation of the + * context. This is intended to allow access to context functionality that is + * not otherwise provided. + */ + native_handle_type native_handle() + { + return engine_.native_handle(); + } + + /// Get a reference to the next layer. + /** + * This function returns a reference to the next layer in a stack of stream + * layers. + * + * @return A reference to the next layer in the stack of stream layers. + * Ownership is not transferred to the caller. + */ + const next_layer_type& next_layer() const + { + return transport_.next_layer(); + } + + /// Get a reference to the next layer. + /** + * This function returns a reference to the next layer in a stack of stream + * layers. + * + * @return A reference to the next layer in the stack of stream layers. + * Ownership is not transferred to the caller. + */ + next_layer_type& next_layer() + { + return transport_.next_layer(); + } + + /// Get a reference to the lowest layer. + /** + * This function returns a reference to the lowest layer in a stack of + * stream layers. + * + * @return A reference to the lowest layer in the stack of stream layers. + * Ownership is not transferred to the caller. + */ + lowest_layer_type& lowest_layer() + { + return transport_.lowest_layer(); + } + + /// Get a reference to the lowest layer. + /** + * This function returns a reference to the lowest layer in a stack of + * stream layers. + * + * @return A reference to the lowest layer in the stack of stream layers. + * Ownership is not transferred to the caller. + */ + const lowest_layer_type& lowest_layer() const + { + return transport_.lowest_layer(); + } + + /// Perform SSL handshaking. + /** + * This function is used to perform SSL handshaking on the stream. The + * function call will block until handshaking is complete or an error occurs. + * + * @param type The type of handshaking to be performed, i.e. as a client or as + * a server. + * + * @throws asio::system_error Thrown on failure. + */ + void handshake(handshake_type type) + { + asio::error_code ec; + handshake(type, ec); + asio::detail::throw_error(ec, "handshake"); + } + + /// Perform SSL handshaking. + /** + * This function is used to perform SSL handshaking on the stream. The + * function call will block until handshaking is complete or an error occurs. + * + * @param type The type of handshaking to be performed, i.e. as a client or as + * a server. + * + * @param ec Set to indicate what error occurred, if any. + */ + asio::error_code handshake(handshake_type type, + asio::error_code& ec) + { + for (;;) + { + int result = engine_.handshake(type, space_, ec); + result = transport_.sync(result, space_, ec); + if (result >= 0) + return engine_.map_error_code(ec); + } + } + + /// Start an asynchronous SSL handshake. + /** + * This function is used to asynchronously perform an SSL handshake on the + * stream. This function call always returns immediately. + * + * @param type The type of handshaking to be performed, i.e. as a client or as + * a server. + * + * @param handler The handler to be called when the handshake operation + * completes. Copies will be made of the handler as required. The equivalent + * function signature of the handler must be: + * @code void handler( + * const asio::error_code& error // Result of operation. + * ); @endcode + */ + template + void async_handshake(handshake_type type, + HandshakeHandler handler) + { + detail::handshake_op( + engine_, transport_, space_, type, handler)( + asio::error_code(), 0, 1); + } + + /// Shut down SSL on the stream. + /** + * This function is used to shut down SSL on the stream. The function call + * will block until SSL has been shut down or an error occurs. + * + * @throws asio::system_error Thrown on failure. + */ + void shutdown() + { + asio::error_code ec; + shutdown(ec); + asio::detail::throw_error(ec, "shutdown"); + } + + /// Shut down SSL on the stream. + /** + * This function is used to shut down SSL on the stream. The function call + * will block until SSL has been shut down or an error occurs. + * + * @param ec Set to indicate what error occurred, if any. + */ + asio::error_code shutdown(asio::error_code& ec) + { + for (;;) + { + int result = engine_.shutdown(space_, ec); + result = transport_.sync(result, space_, ec); + if (result >= 0) + return engine_.map_error_code(ec); + } + } + + /// Asynchronously shut down SSL on the stream. + /** + * This function is used to asynchronously shut down SSL on the stream. This + * function call always returns immediately. + * + * @param handler The handler to be called when the handshake operation + * completes. Copies will be made of the handler as required. The equivalent + * function signature of the handler must be: + * @code void handler( + * const asio::error_code& error // Result of operation. + * ); @endcode + */ + template + void async_shutdown(ShutdownHandler handler) + { + detail::shutdown_op( + engine_, transport_, space_, handler)( + asio::error_code(), 0, 1); + } + + /// Write some data to the stream. + /** + * This function is used to write data on the stream. The function call will + * block until one or more bytes of data has been written successfully, or + * until an error occurs. + * + * @param buffers The data to be written. + * + * @returns The number of bytes written. + * + * @throws asio::system_error Thrown on failure. + * + * @note The write_some operation may not transmit all of the data to the + * peer. Consider using the @ref write function if you need to ensure that all + * data is written before the blocking operation completes. + */ + template + std::size_t write_some(const ConstBufferSequence& buffers) + { + asio::error_code ec; + std::size_t n = write_some(buffers, ec); + asio::detail::throw_error(ec, "write_some"); + return n; + } + + /// Write some data to the stream. + /** + * This function is used to write data on the stream. The function call will + * block until one or more bytes of data has been written successfully, or + * until an error occurs. + * + * @param buffers The data to be written to the stream. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes written. Returns 0 if an error occurred. + * + * @note The write_some operation may not transmit all of the data to the + * peer. Consider using the @ref write function if you need to ensure that all + * data is written before the blocking operation completes. + */ + template + std::size_t write_some(const ConstBufferSequence& buffers, + asio::error_code& ec) + { + asio::const_buffer buffer = + asio::detail::buffer_sequence_adapter::first(buffers); + + for (;;) + { + int result = engine_.write(buffer, space_, ec); + result = transport_.sync(result, space_, ec); + if (result >= 0) + { + engine_.map_error_code(ec); + return static_cast(result); + } + } + } + + /// Start an asynchronous write. + /** + * This function is used to asynchronously write one or more bytes of data to + * the stream. The function call always returns immediately. + * + * @param buffers The data to be written to the stream. Although the buffers + * object may be copied as necessary, ownership of the underlying buffers is + * retained by the caller, which must guarantee that they remain valid until + * the handler is called. + * + * @param handler The handler to be called when the write operation completes. + * Copies will be made of the handler as required. The equivalent function + * signature of the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes written. + * ); @endcode + * + * @note The async_write_some operation may not transmit all of the data to + * the peer. Consider using the @ref async_write function if you need to + * ensure that all data is written before the blocking operation completes. + */ + template + void async_write_some(const ConstBufferSequence& buffers, + WriteHandler handler) + { + detail::write_op( + engine_, transport_, space_, buffers, handler)( + asio::error_code(), 0, 1); + } + + /// Read some data from the stream. + /** + * This function is used to read data from the stream. The function call will + * block until one or more bytes of data has been read successfully, or until + * an error occurs. + * + * @param buffers The buffers into which the data will be read. + * + * @returns The number of bytes read. + * + * @throws asio::system_error Thrown on failure. + * + * @note The read_some operation may not read all of the requested number of + * bytes. Consider using the @ref read function if you need to ensure that the + * requested amount of data is read before the blocking operation completes. + */ + template + std::size_t read_some(const MutableBufferSequence& buffers) + { + asio::error_code ec; + std::size_t n = read_some(buffers, ec); + asio::detail::throw_error(ec, "read_some"); + return n; + } + + /// Read some data from the stream. + /** + * This function is used to read data from the stream. The function call will + * block until one or more bytes of data has been read successfully, or until + * an error occurs. + * + * @param buffers The buffers into which the data will be read. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes read. Returns 0 if an error occurred. + * + * @note The read_some operation may not read all of the requested number of + * bytes. Consider using the @ref read function if you need to ensure that the + * requested amount of data is read before the blocking operation completes. + */ + template + std::size_t read_some(const MutableBufferSequence& buffers, + asio::error_code& ec) + { + asio::mutable_buffer buffer = + asio::detail::buffer_sequence_adapter::first(buffers); + + for (;;) + { + int result = engine_.read(buffer, space_, ec); + result = transport_.sync(result, space_, ec); + if (result >= 0) + { + engine_.map_error_code(ec); + return static_cast(result); + } + } + } + + /// Start an asynchronous read. + /** + * This function is used to asynchronously read one or more bytes of data from + * the stream. The function call always returns immediately. + * + * @param buffers The buffers into which the data will be read. Although the + * buffers object may be copied as necessary, ownership of the underlying + * buffers is retained by the caller, which must guarantee that they remain + * valid until the handler is called. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The equivalent function + * signature of the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes read. + * ); @endcode + * + * @note The async_read_some operation may not read all of the requested + * number of bytes. Consider using the @ref async_read function if you need to + * ensure that the requested amount of data is read before the asynchronous + * operation completes. + */ + template + void async_read_some(const MutableBufferSequence& buffers, + ReadHandler handler) + { + detail::read_op( + engine_, transport_, space_, buffers, handler)( + asio::error_code(), 0, 1); + } + +private: + detail::engine engine_; + detail::transport transport_; + detail::buffer_space space_; +}; + +#endif // defined(ASIO_ENABLE_OLD_SSL) + } // namespace ssl } // namespace asio diff --git a/asio/include/asio/ssl/stream_base.hpp b/asio/include/asio/ssl/stream_base.hpp index e1cc0d72..4aa22653 100644 --- a/asio/include/asio/ssl/stream_base.hpp +++ b/asio/include/asio/ssl/stream_base.hpp @@ -2,7 +2,7 @@ // ssl/stream_base.hpp // ~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/asio/include/asio/ssl/stream_service.hpp b/asio/include/asio/ssl/stream_service.hpp index 840a61f2..e3cf1174 100644 --- a/asio/include/asio/ssl/stream_service.hpp +++ b/asio/include/asio/ssl/stream_service.hpp @@ -2,8 +2,7 @@ // ssl/stream_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com -// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -18,15 +17,21 @@ #include "asio/detail/config.hpp" -#include "asio/ssl/old/stream_service.hpp" +#if defined(ASIO_ENABLE_OLD_SSL) +# include "asio/ssl/old/stream_service.hpp" +#endif // defined(ASIO_ENABLE_OLD_SSL) #include "asio/detail/push_options.hpp" namespace asio { namespace ssl { +#if defined(ASIO_ENABLE_OLD_SSL) + using asio::ssl::old::stream_service; +#endif // defined(ASIO_ENABLE_OLD_SSL) + } // namespace ssl } // namespace asio diff --git a/asio/src/tests/unit/ssl/stream.cpp b/asio/src/tests/unit/ssl/stream.cpp index 4247c9b4..08b4c4bc 100644 --- a/asio/src/tests/unit/ssl/stream.cpp +++ b/asio/src/tests/unit/ssl/stream.cpp @@ -106,6 +106,7 @@ void test() stream1.async_read_some(buffer(mutable_char_buffer), read_some_handler); +#if defined(ASIO_ENABLE_OLD_SSL) stream1.peek(buffer(mutable_char_buffer)); stream1.peek(buffer(mutable_char_buffer), ec); @@ -113,6 +114,7 @@ void test() (void)in_avail1; std::size_t in_avail2 = stream1.in_avail(ec); (void)in_avail2; +#endif // defined(ASIO_ENABLE_OLD_SSL) } catch (std::exception&) {