2 // ssl/old/detail/stream_service.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
6 // Copyright (c) 2005-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
8 // Distributed under the Boost Software License, Version 1.0. (See accompanying
9 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
12 #ifndef BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_STREAM_SERVICE_HPP
13 #define BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_STREAM_SERVICE_HPP
15 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
17 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
19 #include <boost/asio/detail/config.hpp>
23 #include <boost/config.hpp>
24 #include <boost/noncopyable.hpp>
25 #include <boost/function.hpp>
26 #include <boost/bind.hpp>
27 #include <boost/asio/detail/buffer_sequence_adapter.hpp>
28 #include <boost/asio/error.hpp>
29 #include <boost/asio/io_service.hpp>
30 #include <boost/asio/ssl/basic_context.hpp>
31 #include <boost/asio/ssl/stream_base.hpp>
32 #include <boost/asio/ssl/old/detail/openssl_operation.hpp>
33 #include <boost/asio/ssl/detail/openssl_types.hpp>
34 #include <boost/asio/strand.hpp>
35 #include <boost/system/system_error.hpp>
37 #include <boost/asio/detail/push_options.hpp>
45 class openssl_stream_service
46 : public boost::asio::detail::service_base<openssl_stream_service>
49 enum { max_buffer_size = INT_MAX };
51 //Base handler for asyncrhonous operations
52 template <typename Stream>
56 typedef boost::function<
57 void (const boost::system::error_code&, size_t)> func_t;
59 base_handler(boost::asio::io_service& io_service)
61 , io_service_(io_service)
65 void do_func(const boost::system::error_code& error, size_t size)
70 void set_operation(openssl_operation<Stream>* op) { op_ = op; }
71 void set_func(func_t func) { func_ = func; }
80 openssl_operation<Stream>* op_;
81 boost::asio::io_service& io_service_;
82 boost::asio::io_service::work work_;
83 }; // class base_handler
85 // Handler for asynchronous IO (write/read) operations
86 template<typename Stream, typename Handler>
88 : public base_handler<Stream>
91 io_handler(Handler handler, boost::asio::io_service& io_service)
92 : base_handler<Stream>(io_service)
95 this->set_func(boost::bind(
96 &io_handler<Stream, Handler>::handler_impl,
97 this, boost::arg<1>(), boost::arg<2>() ));
102 void handler_impl(const boost::system::error_code& error, size_t size)
104 std::auto_ptr<io_handler<Stream, Handler> > this_ptr(this);
105 handler_(error, size);
107 }; // class io_handler
109 // Handler for asyncrhonous handshake (connect, accept) functions
110 template <typename Stream, typename Handler>
111 class handshake_handler
112 : public base_handler<Stream>
115 handshake_handler(Handler handler, boost::asio::io_service& io_service)
116 : base_handler<Stream>(io_service)
119 this->set_func(boost::bind(
120 &handshake_handler<Stream, Handler>::handler_impl,
121 this, boost::arg<1>(), boost::arg<2>() ));
126 void handler_impl(const boost::system::error_code& error, size_t)
128 std::auto_ptr<handshake_handler<Stream, Handler> > this_ptr(this);
132 }; // class handshake_handler
134 // Handler for asyncrhonous shutdown
135 template <typename Stream, typename Handler>
136 class shutdown_handler
137 : public base_handler<Stream>
140 shutdown_handler(Handler handler, boost::asio::io_service& io_service)
141 : base_handler<Stream>(io_service),
144 this->set_func(boost::bind(
145 &shutdown_handler<Stream, Handler>::handler_impl,
146 this, boost::arg<1>(), boost::arg<2>() ));
151 void handler_impl(const boost::system::error_code& error, size_t)
153 std::auto_ptr<shutdown_handler<Stream, Handler> > this_ptr(this);
156 }; // class shutdown_handler
159 // The implementation type.
160 typedef struct impl_struct
167 // Construct a new stream socket service for the specified io_service.
168 explicit openssl_stream_service(boost::asio::io_service& io_service)
169 : boost::asio::detail::service_base<openssl_stream_service>(io_service),
174 // Destroy all user-defined handler objects owned by the service.
175 void shutdown_service()
179 // Return a null stream implementation.
180 impl_type null() const
185 // Create a new stream implementation.
186 template <typename Stream, typename Context_Service>
187 void create(impl_type& impl, Stream& /*next_layer*/,
188 basic_context<Context_Service>& context)
190 impl = new impl_struct;
191 impl->ssl = ::SSL_new(context.impl());
192 ::SSL_set_mode(impl->ssl, SSL_MODE_ENABLE_PARTIAL_WRITE);
193 ::SSL_set_mode(impl->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
196 ::BIO_new_bio_pair(&int_bio, 8192, &impl->ext_bio, 8192);
197 ::SSL_set_bio(impl->ssl, int_bio, int_bio);
200 // Destroy a stream implementation.
201 template <typename Stream>
202 void destroy(impl_type& impl, Stream& /*next_layer*/)
206 ::BIO_free(impl->ext_bio);
207 ::SSL_free(impl->ssl);
213 // Perform SSL handshaking.
214 template <typename Stream>
215 boost::system::error_code handshake(impl_type& impl, Stream& next_layer,
216 stream_base::handshake_type type, boost::system::error_code& ec)
220 openssl_operation<Stream> op(
221 type == stream_base::client ?
222 &ssl_wrap<mutex_type>::SSL_connect:
223 &ssl_wrap<mutex_type>::SSL_accept,
230 catch (boost::system::system_error& e)
236 ec = boost::system::error_code();
240 // Start an asynchronous SSL handshake.
241 template <typename Stream, typename Handler>
242 void async_handshake(impl_type& impl, Stream& next_layer,
243 stream_base::handshake_type type, Handler handler)
245 typedef handshake_handler<Stream, Handler> connect_handler;
247 connect_handler* local_handler =
248 new connect_handler(handler, get_io_service());
250 openssl_operation<Stream>* op = new openssl_operation<Stream>
252 type == stream_base::client ?
253 &ssl_wrap<mutex_type>::SSL_connect:
254 &ssl_wrap<mutex_type>::SSL_accept,
261 &base_handler<Stream>::do_func,
268 local_handler->set_operation(op);
270 strand_.post(boost::bind(&openssl_operation<Stream>::start, op));
273 // Shut down SSL on the stream.
274 template <typename Stream>
275 boost::system::error_code shutdown(impl_type& impl, Stream& next_layer,
276 boost::system::error_code& ec)
280 openssl_operation<Stream> op(
281 &ssl_wrap<mutex_type>::SSL_shutdown,
288 catch (boost::system::system_error& e)
294 ec = boost::system::error_code();
298 // Asynchronously shut down SSL on the stream.
299 template <typename Stream, typename Handler>
300 void async_shutdown(impl_type& impl, Stream& next_layer, Handler handler)
302 typedef shutdown_handler<Stream, Handler> disconnect_handler;
304 disconnect_handler* local_handler =
305 new disconnect_handler(handler, get_io_service());
307 openssl_operation<Stream>* op = new openssl_operation<Stream>
309 &ssl_wrap<mutex_type>::SSL_shutdown,
316 &base_handler<Stream>::do_func,
323 local_handler->set_operation(op);
325 strand_.post(boost::bind(&openssl_operation<Stream>::start, op));
328 // Write some data to the stream.
329 template <typename Stream, typename Const_Buffers>
330 std::size_t write_some(impl_type& impl, Stream& next_layer,
331 const Const_Buffers& buffers, boost::system::error_code& ec)
333 size_t bytes_transferred = 0;
336 boost::asio::const_buffer buffer =
337 boost::asio::detail::buffer_sequence_adapter<
338 boost::asio::const_buffer, Const_Buffers>::first(buffers);
340 std::size_t buffer_size = boost::asio::buffer_size(buffer);
341 if (buffer_size > max_buffer_size)
342 buffer_size = max_buffer_size;
343 else if (buffer_size == 0)
345 ec = boost::system::error_code();
349 boost::function<int (SSL*)> send_func =
350 boost::bind(boost::type<int>(), &::SSL_write, boost::arg<1>(),
351 boost::asio::buffer_cast<const void*>(buffer),
352 static_cast<int>(buffer_size));
353 openssl_operation<Stream> op(
360 bytes_transferred = static_cast<size_t>(op.start());
362 catch (boost::system::system_error& e)
368 ec = boost::system::error_code();
369 return bytes_transferred;
372 // Start an asynchronous write.
373 template <typename Stream, typename Const_Buffers, typename Handler>
374 void async_write_some(impl_type& impl, Stream& next_layer,
375 const Const_Buffers& buffers, Handler handler)
377 typedef io_handler<Stream, Handler> send_handler;
379 boost::asio::const_buffer buffer =
380 boost::asio::detail::buffer_sequence_adapter<
381 boost::asio::const_buffer, Const_Buffers>::first(buffers);
383 std::size_t buffer_size = boost::asio::buffer_size(buffer);
384 if (buffer_size > max_buffer_size)
385 buffer_size = max_buffer_size;
386 else if (buffer_size == 0)
388 get_io_service().post(boost::asio::detail::bind_handler(
389 handler, boost::system::error_code(), 0));
393 send_handler* local_handler = new send_handler(handler, get_io_service());
395 boost::function<int (SSL*)> send_func =
396 boost::bind(boost::type<int>(), &::SSL_write, boost::arg<1>(),
397 boost::asio::buffer_cast<const void*>(buffer),
398 static_cast<int>(buffer_size));
400 openssl_operation<Stream>* op = new openssl_operation<Stream>
409 &base_handler<Stream>::do_func,
416 local_handler->set_operation(op);
418 strand_.post(boost::bind(&openssl_operation<Stream>::start, op));
421 // Read some data from the stream.
422 template <typename Stream, typename Mutable_Buffers>
423 std::size_t read_some(impl_type& impl, Stream& next_layer,
424 const Mutable_Buffers& buffers, boost::system::error_code& ec)
426 size_t bytes_transferred = 0;
429 boost::asio::mutable_buffer buffer =
430 boost::asio::detail::buffer_sequence_adapter<
431 boost::asio::mutable_buffer, Mutable_Buffers>::first(buffers);
433 std::size_t buffer_size = boost::asio::buffer_size(buffer);
434 if (buffer_size > max_buffer_size)
435 buffer_size = max_buffer_size;
436 else if (buffer_size == 0)
438 ec = boost::system::error_code();
442 boost::function<int (SSL*)> recv_func =
443 boost::bind(boost::type<int>(), &::SSL_read, boost::arg<1>(),
444 boost::asio::buffer_cast<void*>(buffer),
445 static_cast<int>(buffer_size));
446 openssl_operation<Stream> op(recv_func,
453 bytes_transferred = static_cast<size_t>(op.start());
455 catch (boost::system::system_error& e)
461 ec = boost::system::error_code();
462 return bytes_transferred;
465 // Start an asynchronous read.
466 template <typename Stream, typename Mutable_Buffers, typename Handler>
467 void async_read_some(impl_type& impl, Stream& next_layer,
468 const Mutable_Buffers& buffers, Handler handler)
470 typedef io_handler<Stream, Handler> recv_handler;
472 boost::asio::mutable_buffer buffer =
473 boost::asio::detail::buffer_sequence_adapter<
474 boost::asio::mutable_buffer, Mutable_Buffers>::first(buffers);
476 std::size_t buffer_size = boost::asio::buffer_size(buffer);
477 if (buffer_size > max_buffer_size)
478 buffer_size = max_buffer_size;
479 else if (buffer_size == 0)
481 get_io_service().post(boost::asio::detail::bind_handler(
482 handler, boost::system::error_code(), 0));
486 recv_handler* local_handler = new recv_handler(handler, get_io_service());
488 boost::function<int (SSL*)> recv_func =
489 boost::bind(boost::type<int>(), &::SSL_read, boost::arg<1>(),
490 boost::asio::buffer_cast<void*>(buffer),
491 static_cast<int>(buffer_size));
493 openssl_operation<Stream>* op = new openssl_operation<Stream>
502 &base_handler<Stream>::do_func,
509 local_handler->set_operation(op);
511 strand_.post(boost::bind(&openssl_operation<Stream>::start, op));
514 // Peek at the incoming data on the stream.
515 template <typename Stream, typename Mutable_Buffers>
516 std::size_t peek(impl_type& /*impl*/, Stream& /*next_layer*/,
517 const Mutable_Buffers& /*buffers*/, boost::system::error_code& ec)
519 ec = boost::system::error_code();
523 // Determine the amount of data that may be read without blocking.
524 template <typename Stream>
525 std::size_t in_avail(impl_type& /*impl*/, Stream& /*next_layer*/,
526 boost::system::error_code& ec)
528 ec = boost::system::error_code();
533 boost::asio::io_service::strand strand_;
535 typedef boost::asio::detail::mutex mutex_type;
537 template<typename Mutex>
540 static Mutex ssl_mutex_;
542 static int SSL_accept(SSL *ssl)
544 typename Mutex::scoped_lock lock(ssl_mutex_);
545 return ::SSL_accept(ssl);
548 static int SSL_connect(SSL *ssl)
550 typename Mutex::scoped_lock lock(ssl_mutex_);
551 return ::SSL_connect(ssl);
554 static int SSL_shutdown(SSL *ssl)
556 typename Mutex::scoped_lock lock(ssl_mutex_);
557 return ::SSL_shutdown(ssl);
562 template<typename Mutex>
563 Mutex openssl_stream_service::ssl_wrap<Mutex>::ssl_mutex_;
565 } // namespace detail
571 #include <boost/asio/detail/pop_options.hpp>
573 #endif // BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_STREAM_SERVICE_HPP