diff options
Diffstat (limited to 'boost/asio/ssl/old/detail/openssl_stream_service.hpp')
-rw-r--r-- | boost/asio/ssl/old/detail/openssl_stream_service.hpp | 573 |
1 files changed, 573 insertions, 0 deletions
diff --git a/boost/asio/ssl/old/detail/openssl_stream_service.hpp b/boost/asio/ssl/old/detail/openssl_stream_service.hpp new file mode 100644 index 0000000000..0efed751bb --- /dev/null +++ b/boost/asio/ssl/old/detail/openssl_stream_service.hpp @@ -0,0 +1,573 @@ +// +// ssl/old/detail/stream_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com +// Copyright (c) 2005-2012 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 BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_STREAM_SERVICE_HPP +#define BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_STREAM_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <cstddef> +#include <climits> +#include <memory> +#include <boost/config.hpp> +#include <boost/noncopyable.hpp> +#include <boost/function.hpp> +#include <boost/bind.hpp> +#include <boost/asio/detail/buffer_sequence_adapter.hpp> +#include <boost/asio/error.hpp> +#include <boost/asio/io_service.hpp> +#include <boost/asio/ssl/basic_context.hpp> +#include <boost/asio/ssl/stream_base.hpp> +#include <boost/asio/ssl/old/detail/openssl_operation.hpp> +#include <boost/asio/ssl/detail/openssl_types.hpp> +#include <boost/asio/strand.hpp> +#include <boost/system/system_error.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace ssl { +namespace old { +namespace detail { + +class openssl_stream_service + : public boost::asio::detail::service_base<openssl_stream_service> +{ +private: + enum { max_buffer_size = INT_MAX }; + + //Base handler for asyncrhonous operations + template <typename Stream> + class base_handler + { + public: + typedef boost::function< + void (const boost::system::error_code&, size_t)> func_t; + + base_handler(boost::asio::io_service& io_service) + : op_(NULL) + , io_service_(io_service) + , work_(io_service) + {} + + void do_func(const boost::system::error_code& error, size_t size) + { + func_(error, size); + } + + void set_operation(openssl_operation<Stream>* op) { op_ = op; } + void set_func(func_t func) { func_ = func; } + + ~base_handler() + { + delete op_; + } + + private: + func_t func_; + openssl_operation<Stream>* op_; + boost::asio::io_service& io_service_; + boost::asio::io_service::work work_; + }; // class base_handler + + // Handler for asynchronous IO (write/read) operations + template<typename Stream, typename Handler> + class io_handler + : public base_handler<Stream> + { + public: + io_handler(Handler handler, boost::asio::io_service& io_service) + : base_handler<Stream>(io_service) + , handler_(handler) + { + this->set_func(boost::bind( + &io_handler<Stream, Handler>::handler_impl, + this, boost::arg<1>(), boost::arg<2>() )); + } + + private: + Handler handler_; + void handler_impl(const boost::system::error_code& error, size_t size) + { + std::auto_ptr<io_handler<Stream, Handler> > this_ptr(this); + handler_(error, size); + } + }; // class io_handler + + // Handler for asyncrhonous handshake (connect, accept) functions + template <typename Stream, typename Handler> + class handshake_handler + : public base_handler<Stream> + { + public: + handshake_handler(Handler handler, boost::asio::io_service& io_service) + : base_handler<Stream>(io_service) + , handler_(handler) + { + this->set_func(boost::bind( + &handshake_handler<Stream, Handler>::handler_impl, + this, boost::arg<1>(), boost::arg<2>() )); + } + + private: + Handler handler_; + void handler_impl(const boost::system::error_code& error, size_t) + { + std::auto_ptr<handshake_handler<Stream, Handler> > this_ptr(this); + handler_(error); + } + + }; // class handshake_handler + + // Handler for asyncrhonous shutdown + template <typename Stream, typename Handler> + class shutdown_handler + : public base_handler<Stream> + { + public: + shutdown_handler(Handler handler, boost::asio::io_service& io_service) + : base_handler<Stream>(io_service), + handler_(handler) + { + this->set_func(boost::bind( + &shutdown_handler<Stream, Handler>::handler_impl, + this, boost::arg<1>(), boost::arg<2>() )); + } + + private: + Handler handler_; + void handler_impl(const boost::system::error_code& error, size_t) + { + std::auto_ptr<shutdown_handler<Stream, Handler> > this_ptr(this); + handler_(error); + } + }; // class shutdown_handler + +public: + // The implementation type. + typedef struct impl_struct + { + ::SSL* ssl; + ::BIO* ext_bio; + net_buffer recv_buf; + } * impl_type; + + // Construct a new stream socket service for the specified io_service. + explicit openssl_stream_service(boost::asio::io_service& io_service) + : boost::asio::detail::service_base<openssl_stream_service>(io_service), + strand_(io_service) + { + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown_service() + { + } + + // Return a null stream implementation. + impl_type null() const + { + return 0; + } + + // Create a new stream implementation. + template <typename Stream, typename Context_Service> + void create(impl_type& impl, Stream& /*next_layer*/, + basic_context<Context_Service>& context) + { + impl = new impl_struct; + impl->ssl = ::SSL_new(context.impl()); + ::SSL_set_mode(impl->ssl, SSL_MODE_ENABLE_PARTIAL_WRITE); + ::SSL_set_mode(impl->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); + ::BIO* int_bio = 0; + impl->ext_bio = 0; + ::BIO_new_bio_pair(&int_bio, 8192, &impl->ext_bio, 8192); + ::SSL_set_bio(impl->ssl, int_bio, int_bio); + } + + // Destroy a stream implementation. + template <typename Stream> + void destroy(impl_type& impl, Stream& /*next_layer*/) + { + if (impl != 0) + { + ::BIO_free(impl->ext_bio); + ::SSL_free(impl->ssl); + delete impl; + impl = 0; + } + } + + // Perform SSL handshaking. + template <typename Stream> + boost::system::error_code handshake(impl_type& impl, Stream& next_layer, + stream_base::handshake_type type, boost::system::error_code& ec) + { + try + { + openssl_operation<Stream> op( + type == stream_base::client ? + &ssl_wrap<mutex_type>::SSL_connect: + &ssl_wrap<mutex_type>::SSL_accept, + next_layer, + impl->recv_buf, + impl->ssl, + impl->ext_bio); + op.start(); + } + catch (boost::system::system_error& e) + { + ec = e.code(); + return ec; + } + + ec = boost::system::error_code(); + return ec; + } + + // Start an asynchronous SSL handshake. + template <typename Stream, typename Handler> + void async_handshake(impl_type& impl, Stream& next_layer, + stream_base::handshake_type type, Handler handler) + { + typedef handshake_handler<Stream, Handler> connect_handler; + + connect_handler* local_handler = + new connect_handler(handler, get_io_service()); + + openssl_operation<Stream>* op = new openssl_operation<Stream> + ( + type == stream_base::client ? + &ssl_wrap<mutex_type>::SSL_connect: + &ssl_wrap<mutex_type>::SSL_accept, + next_layer, + impl->recv_buf, + impl->ssl, + impl->ext_bio, + boost::bind + ( + &base_handler<Stream>::do_func, + local_handler, + boost::arg<1>(), + boost::arg<2>() + ), + strand_ + ); + local_handler->set_operation(op); + + strand_.post(boost::bind(&openssl_operation<Stream>::start, op)); + } + + // Shut down SSL on the stream. + template <typename Stream> + boost::system::error_code shutdown(impl_type& impl, Stream& next_layer, + boost::system::error_code& ec) + { + try + { + openssl_operation<Stream> op( + &ssl_wrap<mutex_type>::SSL_shutdown, + next_layer, + impl->recv_buf, + impl->ssl, + impl->ext_bio); + op.start(); + } + catch (boost::system::system_error& e) + { + ec = e.code(); + return ec; + } + + ec = boost::system::error_code(); + return ec; + } + + // Asynchronously shut down SSL on the stream. + template <typename Stream, typename Handler> + void async_shutdown(impl_type& impl, Stream& next_layer, Handler handler) + { + typedef shutdown_handler<Stream, Handler> disconnect_handler; + + disconnect_handler* local_handler = + new disconnect_handler(handler, get_io_service()); + + openssl_operation<Stream>* op = new openssl_operation<Stream> + ( + &ssl_wrap<mutex_type>::SSL_shutdown, + next_layer, + impl->recv_buf, + impl->ssl, + impl->ext_bio, + boost::bind + ( + &base_handler<Stream>::do_func, + local_handler, + boost::arg<1>(), + boost::arg<2>() + ), + strand_ + ); + local_handler->set_operation(op); + + strand_.post(boost::bind(&openssl_operation<Stream>::start, op)); + } + + // Write some data to the stream. + template <typename Stream, typename Const_Buffers> + std::size_t write_some(impl_type& impl, Stream& next_layer, + const Const_Buffers& buffers, boost::system::error_code& ec) + { + size_t bytes_transferred = 0; + try + { + boost::asio::const_buffer buffer = + boost::asio::detail::buffer_sequence_adapter< + boost::asio::const_buffer, Const_Buffers>::first(buffers); + + std::size_t buffer_size = boost::asio::buffer_size(buffer); + if (buffer_size > max_buffer_size) + buffer_size = max_buffer_size; + else if (buffer_size == 0) + { + ec = boost::system::error_code(); + return 0; + } + + boost::function<int (SSL*)> send_func = + boost::bind(boost::type<int>(), &::SSL_write, boost::arg<1>(), + boost::asio::buffer_cast<const void*>(buffer), + static_cast<int>(buffer_size)); + openssl_operation<Stream> op( + send_func, + next_layer, + impl->recv_buf, + impl->ssl, + impl->ext_bio + ); + bytes_transferred = static_cast<size_t>(op.start()); + } + catch (boost::system::system_error& e) + { + ec = e.code(); + return 0; + } + + ec = boost::system::error_code(); + return bytes_transferred; + } + + // Start an asynchronous write. + template <typename Stream, typename Const_Buffers, typename Handler> + void async_write_some(impl_type& impl, Stream& next_layer, + const Const_Buffers& buffers, Handler handler) + { + typedef io_handler<Stream, Handler> send_handler; + + boost::asio::const_buffer buffer = + boost::asio::detail::buffer_sequence_adapter< + boost::asio::const_buffer, Const_Buffers>::first(buffers); + + std::size_t buffer_size = boost::asio::buffer_size(buffer); + if (buffer_size > max_buffer_size) + buffer_size = max_buffer_size; + else if (buffer_size == 0) + { + get_io_service().post(boost::asio::detail::bind_handler( + handler, boost::system::error_code(), 0)); + return; + } + + send_handler* local_handler = new send_handler(handler, get_io_service()); + + boost::function<int (SSL*)> send_func = + boost::bind(boost::type<int>(), &::SSL_write, boost::arg<1>(), + boost::asio::buffer_cast<const void*>(buffer), + static_cast<int>(buffer_size)); + + openssl_operation<Stream>* op = new openssl_operation<Stream> + ( + send_func, + next_layer, + impl->recv_buf, + impl->ssl, + impl->ext_bio, + boost::bind + ( + &base_handler<Stream>::do_func, + local_handler, + boost::arg<1>(), + boost::arg<2>() + ), + strand_ + ); + local_handler->set_operation(op); + + strand_.post(boost::bind(&openssl_operation<Stream>::start, op)); + } + + // Read some data from the stream. + template <typename Stream, typename Mutable_Buffers> + std::size_t read_some(impl_type& impl, Stream& next_layer, + const Mutable_Buffers& buffers, boost::system::error_code& ec) + { + size_t bytes_transferred = 0; + try + { + boost::asio::mutable_buffer buffer = + boost::asio::detail::buffer_sequence_adapter< + boost::asio::mutable_buffer, Mutable_Buffers>::first(buffers); + + std::size_t buffer_size = boost::asio::buffer_size(buffer); + if (buffer_size > max_buffer_size) + buffer_size = max_buffer_size; + else if (buffer_size == 0) + { + ec = boost::system::error_code(); + return 0; + } + + boost::function<int (SSL*)> recv_func = + boost::bind(boost::type<int>(), &::SSL_read, boost::arg<1>(), + boost::asio::buffer_cast<void*>(buffer), + static_cast<int>(buffer_size)); + openssl_operation<Stream> op(recv_func, + next_layer, + impl->recv_buf, + impl->ssl, + impl->ext_bio + ); + + bytes_transferred = static_cast<size_t>(op.start()); + } + catch (boost::system::system_error& e) + { + ec = e.code(); + return 0; + } + + ec = boost::system::error_code(); + return bytes_transferred; + } + + // Start an asynchronous read. + template <typename Stream, typename Mutable_Buffers, typename Handler> + void async_read_some(impl_type& impl, Stream& next_layer, + const Mutable_Buffers& buffers, Handler handler) + { + typedef io_handler<Stream, Handler> recv_handler; + + boost::asio::mutable_buffer buffer = + boost::asio::detail::buffer_sequence_adapter< + boost::asio::mutable_buffer, Mutable_Buffers>::first(buffers); + + std::size_t buffer_size = boost::asio::buffer_size(buffer); + if (buffer_size > max_buffer_size) + buffer_size = max_buffer_size; + else if (buffer_size == 0) + { + get_io_service().post(boost::asio::detail::bind_handler( + handler, boost::system::error_code(), 0)); + return; + } + + recv_handler* local_handler = new recv_handler(handler, get_io_service()); + + boost::function<int (SSL*)> recv_func = + boost::bind(boost::type<int>(), &::SSL_read, boost::arg<1>(), + boost::asio::buffer_cast<void*>(buffer), + static_cast<int>(buffer_size)); + + openssl_operation<Stream>* op = new openssl_operation<Stream> + ( + recv_func, + next_layer, + impl->recv_buf, + impl->ssl, + impl->ext_bio, + boost::bind + ( + &base_handler<Stream>::do_func, + local_handler, + boost::arg<1>(), + boost::arg<2>() + ), + strand_ + ); + local_handler->set_operation(op); + + strand_.post(boost::bind(&openssl_operation<Stream>::start, op)); + } + + // Peek at the incoming data on the stream. + template <typename Stream, typename Mutable_Buffers> + std::size_t peek(impl_type& /*impl*/, Stream& /*next_layer*/, + const Mutable_Buffers& /*buffers*/, boost::system::error_code& ec) + { + ec = boost::system::error_code(); + return 0; + } + + // Determine the amount of data that may be read without blocking. + template <typename Stream> + std::size_t in_avail(impl_type& /*impl*/, Stream& /*next_layer*/, + boost::system::error_code& ec) + { + ec = boost::system::error_code(); + return 0; + } + +private: + boost::asio::io_service::strand strand_; + + typedef boost::asio::detail::mutex mutex_type; + + template<typename Mutex> + struct ssl_wrap + { + static Mutex ssl_mutex_; + + static int SSL_accept(SSL *ssl) + { + typename Mutex::scoped_lock lock(ssl_mutex_); + return ::SSL_accept(ssl); + } + + static int SSL_connect(SSL *ssl) + { + typename Mutex::scoped_lock lock(ssl_mutex_); + return ::SSL_connect(ssl); + } + + static int SSL_shutdown(SSL *ssl) + { + typename Mutex::scoped_lock lock(ssl_mutex_); + return ::SSL_shutdown(ssl); + } + }; +}; + +template<typename Mutex> +Mutex openssl_stream_service::ssl_wrap<Mutex>::ssl_mutex_; + +} // namespace detail +} // namespace old +} // namespace ssl +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_STREAM_SERVICE_HPP |