summaryrefslogtreecommitdiff
path: root/boost/asio/ssl/old/detail/openssl_stream_service.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/asio/ssl/old/detail/openssl_stream_service.hpp')
-rw-r--r--boost/asio/ssl/old/detail/openssl_stream_service.hpp573
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