openssl_stream_service.hpp
Go to the documentation of this file.
00001 //
00002 // stream_service.hpp
00003 // ~~~~~~~~~~~~~~~~~~
00004 //
00005 // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
00006 // Copyright (c) 2005-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
00007 //
00008 // Distributed under the Boost Software License, Version 1.0. (See accompanying
00009 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
00010 //
00011 
00012 #ifndef ASIO_SSL_DETAIL_OPENSSL_STREAM_SERVICE_HPP
00013 #define ASIO_SSL_DETAIL_OPENSSL_STREAM_SERVICE_HPP
00014 
00015 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
00016 # pragma once
00017 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
00018 
00019 #include "asio/detail/push_options.hpp"
00020 
00021 #include "asio/detail/push_options.hpp"
00022 #include <cstddef>
00023 #include <climits>
00024 #include <boost/config.hpp>
00025 #include <boost/noncopyable.hpp>
00026 #include <boost/function.hpp>
00027 #include <boost/bind.hpp>
00028 #include "asio/detail/pop_options.hpp"
00029 
00030 #include "asio/error.hpp"
00031 #include "asio/io_service.hpp"
00032 #include "asio/strand.hpp"
00033 #include "asio/detail/service_base.hpp"
00034 #include "asio/ssl/basic_context.hpp"
00035 #include "asio/ssl/stream_base.hpp"
00036 #include "asio/ssl/detail/openssl_operation.hpp"
00037 #include "asio/ssl/detail/openssl_types.hpp"
00038 
00039 namespace asio {
00040 namespace ssl {
00041 namespace detail {
00042 
00043 class openssl_stream_service
00044   : public asio::detail::service_base<openssl_stream_service>
00045 {
00046 private:
00047   enum { max_buffer_size = INT_MAX };
00048 
00049   //Base handler for asyncrhonous operations
00050   template <typename Stream>
00051   class base_handler
00052   {
00053   public:
00054     typedef boost::function<
00055       void (const asio::error_code&, size_t)> func_t;
00056 
00057     base_handler(asio::io_service& io_service)
00058       : op_(NULL)
00059       , io_service_(io_service)
00060       , work_(io_service)
00061     {}
00062     
00063     void do_func(const asio::error_code& error, size_t size)
00064     {
00065       func_(error, size);
00066     }
00067         
00068     void set_operation(openssl_operation<Stream>* op) { op_ = op; }
00069     void set_func(func_t func) { func_ = func; }
00070 
00071     ~base_handler()
00072     {
00073       delete op_;
00074     }
00075 
00076   private:
00077     func_t func_;
00078     openssl_operation<Stream>* op_;
00079     asio::io_service& io_service_;
00080     asio::io_service::work work_;
00081   };  // class base_handler
00082 
00083   // Handler for asynchronous IO (write/read) operations
00084   template<typename Stream, typename Handler>
00085   class io_handler 
00086     : public base_handler<Stream>
00087   {
00088   public:
00089     io_handler(Handler handler, asio::io_service& io_service)
00090       : base_handler<Stream>(io_service)
00091       , handler_(handler)
00092     {
00093       set_func(boost::bind(
00094         &io_handler<Stream, Handler>::handler_impl, 
00095         this, boost::arg<1>(), boost::arg<2>() ));
00096     }
00097 
00098   private:
00099     Handler handler_;
00100     void handler_impl(const asio::error_code& error, size_t size)
00101     {
00102       handler_(error, size);
00103       delete this;
00104     }
00105   };  // class io_handler 
00106 
00107   // Handler for asyncrhonous handshake (connect, accept) functions
00108   template <typename Stream, typename Handler>
00109   class handshake_handler
00110     : public base_handler<Stream>
00111   {
00112   public:
00113     handshake_handler(Handler handler, asio::io_service& io_service)
00114       : base_handler<Stream>(io_service)
00115       , handler_(handler)
00116     {
00117       set_func(boost::bind(
00118         &handshake_handler<Stream, Handler>::handler_impl, 
00119         this, boost::arg<1>(), boost::arg<2>() ));
00120     }
00121 
00122   private:
00123     Handler handler_;
00124     void handler_impl(const asio::error_code& error, size_t)
00125     {
00126       handler_(error);
00127       delete this;
00128     }
00129 
00130   };  // class handshake_handler
00131 
00132   // Handler for asyncrhonous shutdown
00133   template <typename Stream, typename Handler>
00134   class shutdown_handler
00135     : public base_handler<Stream>
00136   {
00137   public:
00138     shutdown_handler(Handler handler, asio::io_service& io_service)
00139       : base_handler<Stream>(io_service),
00140         handler_(handler)
00141     { 
00142       set_func(boost::bind(
00143         &shutdown_handler<Stream, Handler>::handler_impl, 
00144         this, boost::arg<1>(), boost::arg<2>() ));
00145     }
00146 
00147   private:
00148     Handler handler_;
00149     void handler_impl(const asio::error_code& error, size_t)
00150     {
00151       handler_(error);
00152       delete this;
00153     }
00154   };  // class shutdown_handler
00155 
00156 public:
00157   // The implementation type.
00158   typedef struct impl_struct
00159   {
00160     ::SSL* ssl;
00161     ::BIO* ext_bio;
00162     net_buffer recv_buf;
00163   } * impl_type;
00164 
00165   // Construct a new stream socket service for the specified io_service.
00166   explicit openssl_stream_service(asio::io_service& io_service)
00167     : asio::detail::service_base<openssl_stream_service>(io_service),
00168       strand_(io_service)
00169   {
00170   }
00171 
00172   // Destroy all user-defined handler objects owned by the service.
00173   void shutdown_service()
00174   {
00175   }
00176 
00177   // Return a null stream implementation.
00178   impl_type null() const
00179   {
00180     return 0;
00181   }
00182 
00183   // Create a new stream implementation.
00184   template <typename Stream, typename Context_Service>
00185   void create(impl_type& impl, Stream& next_layer,
00186       basic_context<Context_Service>& context)
00187   {
00188     impl = new impl_struct;
00189     impl->ssl = ::SSL_new(context.impl());
00190     ::SSL_set_mode(impl->ssl, SSL_MODE_ENABLE_PARTIAL_WRITE);
00191     ::SSL_set_mode(impl->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
00192     ::BIO* int_bio = 0;
00193     impl->ext_bio = 0;
00194     ::BIO_new_bio_pair(&int_bio, 8192, &impl->ext_bio, 8192);
00195     ::SSL_set_bio(impl->ssl, int_bio, int_bio);
00196   }
00197 
00198   // Destroy a stream implementation.
00199   template <typename Stream>
00200   void destroy(impl_type& impl, Stream& next_layer)
00201   {
00202     if (impl != 0)
00203     {
00204       ::BIO_free(impl->ext_bio);
00205       ::SSL_free(impl->ssl);
00206       delete impl;
00207       impl = 0;
00208     }
00209   }
00210 
00211   // Perform SSL handshaking.
00212   template <typename Stream>
00213   asio::error_code handshake(impl_type& impl, Stream& next_layer,
00214       stream_base::handshake_type type, asio::error_code& ec)
00215   {
00216     try
00217     {
00218       openssl_operation<Stream> op(
00219         type == stream_base::client ?
00220           &ssl_wrap<mutex_type>::SSL_connect:
00221           &ssl_wrap<mutex_type>::SSL_accept,
00222         next_layer,
00223         impl->recv_buf,
00224         impl->ssl,
00225         impl->ext_bio);
00226       op.start();
00227     }
00228     catch (asio::system_error& e)
00229     {
00230       ec = e.code();
00231       return ec;
00232     }
00233 
00234     ec = asio::error_code();
00235     return ec;
00236   }
00237 
00238   // Start an asynchronous SSL handshake.
00239   template <typename Stream, typename Handler>
00240   void async_handshake(impl_type& impl, Stream& next_layer,
00241       stream_base::handshake_type type, Handler handler)
00242   {
00243     typedef handshake_handler<Stream, Handler> connect_handler;
00244 
00245     connect_handler* local_handler = 
00246       new connect_handler(handler, get_io_service());
00247 
00248     openssl_operation<Stream>* op = new openssl_operation<Stream>
00249     (
00250       type == stream_base::client ?
00251         &ssl_wrap<mutex_type>::SSL_connect:
00252         &ssl_wrap<mutex_type>::SSL_accept,
00253       next_layer,
00254       impl->recv_buf,
00255       impl->ssl,
00256       impl->ext_bio,
00257       boost::bind
00258       (
00259         &base_handler<Stream>::do_func, 
00260         local_handler,
00261         boost::arg<1>(),
00262         boost::arg<2>()
00263       ),
00264       strand_
00265     );
00266     local_handler->set_operation(op);
00267 
00268     strand_.post(boost::bind(&openssl_operation<Stream>::start, op));
00269   }
00270 
00271   // Shut down SSL on the stream.
00272   template <typename Stream>
00273   asio::error_code shutdown(impl_type& impl, Stream& next_layer,
00274       asio::error_code& ec)
00275   {
00276     try
00277     {
00278       openssl_operation<Stream> op(
00279         &ssl_wrap<mutex_type>::SSL_shutdown,
00280         next_layer,
00281         impl->recv_buf,
00282         impl->ssl,
00283         impl->ext_bio);
00284       op.start();
00285     }
00286     catch (asio::system_error& e)
00287     {
00288       ec = e.code();
00289       return ec;
00290     }
00291 
00292     ec = asio::error_code();
00293     return ec;
00294   }
00295 
00296   // Asynchronously shut down SSL on the stream.
00297   template <typename Stream, typename Handler>
00298   void async_shutdown(impl_type& impl, Stream& next_layer, Handler handler)
00299   {
00300     typedef shutdown_handler<Stream, Handler> disconnect_handler;
00301 
00302     disconnect_handler* local_handler = 
00303       new disconnect_handler(handler, get_io_service());
00304 
00305     openssl_operation<Stream>* op = new openssl_operation<Stream>
00306     (
00307       &ssl_wrap<mutex_type>::SSL_shutdown,
00308       next_layer,
00309       impl->recv_buf,
00310       impl->ssl,
00311       impl->ext_bio,
00312       boost::bind
00313       (
00314         &base_handler<Stream>::do_func, 
00315         local_handler, 
00316         boost::arg<1>(),
00317         boost::arg<2>()
00318       ),
00319       strand_
00320     );
00321     local_handler->set_operation(op);
00322 
00323     strand_.post(boost::bind(&openssl_operation<Stream>::start, op));        
00324   }
00325 
00326   // Write some data to the stream.
00327   template <typename Stream, typename Const_Buffers>
00328   std::size_t write_some(impl_type& impl, Stream& next_layer,
00329       const Const_Buffers& buffers, asio::error_code& ec)
00330   {
00331     size_t bytes_transferred = 0;
00332     try
00333     {
00334       std::size_t buffer_size = asio::buffer_size(*buffers.begin());
00335       if (buffer_size > max_buffer_size)
00336         buffer_size = max_buffer_size;
00337 
00338       boost::function<int (SSL*)> send_func =
00339         boost::bind(&::SSL_write, boost::arg<1>(),  
00340             asio::buffer_cast<const void*>(*buffers.begin()),
00341             static_cast<int>(buffer_size));
00342       openssl_operation<Stream> op(
00343         send_func,
00344         next_layer,
00345         impl->recv_buf,
00346         impl->ssl,
00347         impl->ext_bio
00348       );
00349       bytes_transferred = static_cast<size_t>(op.start());
00350     }
00351     catch (asio::system_error& e)
00352     {
00353       ec = e.code();
00354       return 0;
00355     }
00356 
00357     ec = asio::error_code();
00358     return bytes_transferred;
00359   }
00360 
00361   // Start an asynchronous write.
00362   template <typename Stream, typename Const_Buffers, typename Handler>
00363   void async_write_some(impl_type& impl, Stream& next_layer,
00364       const Const_Buffers& buffers, Handler handler)
00365   {
00366     typedef io_handler<Stream, Handler> send_handler;
00367 
00368     send_handler* local_handler = new send_handler(handler, get_io_service());
00369 
00370     std::size_t buffer_size = asio::buffer_size(*buffers.begin());
00371     if (buffer_size > max_buffer_size)
00372       buffer_size = max_buffer_size;
00373 
00374     boost::function<int (SSL*)> send_func =
00375       boost::bind(&::SSL_write, boost::arg<1>(),
00376           asio::buffer_cast<const void*>(*buffers.begin()),
00377           static_cast<int>(buffer_size));
00378 
00379     openssl_operation<Stream>* op = new openssl_operation<Stream>
00380     (
00381       send_func,
00382       next_layer,
00383       impl->recv_buf,
00384       impl->ssl,
00385       impl->ext_bio,
00386       boost::bind
00387       (
00388         &base_handler<Stream>::do_func, 
00389         local_handler, 
00390         boost::arg<1>(),
00391         boost::arg<2>()
00392       ),
00393       strand_
00394     );
00395     local_handler->set_operation(op);
00396 
00397     strand_.post(boost::bind(&openssl_operation<Stream>::start, op));        
00398   }
00399 
00400   // Read some data from the stream.
00401   template <typename Stream, typename Mutable_Buffers>
00402   std::size_t read_some(impl_type& impl, Stream& next_layer,
00403       const Mutable_Buffers& buffers, asio::error_code& ec)
00404   {
00405     size_t bytes_transferred = 0;
00406     try
00407     {
00408       std::size_t buffer_size = asio::buffer_size(*buffers.begin());
00409       if (buffer_size > max_buffer_size)
00410         buffer_size = max_buffer_size;
00411 
00412       boost::function<int (SSL*)> recv_func =
00413         boost::bind(&::SSL_read, boost::arg<1>(),
00414             asio::buffer_cast<void*>(*buffers.begin()),
00415             static_cast<int>(buffer_size));
00416       openssl_operation<Stream> op(recv_func,
00417         next_layer,
00418         impl->recv_buf,
00419         impl->ssl,
00420         impl->ext_bio
00421       );
00422 
00423       bytes_transferred = static_cast<size_t>(op.start());
00424     }
00425     catch (asio::system_error& e)
00426     {
00427       ec = e.code();
00428       return 0;
00429     }
00430 
00431     ec = asio::error_code();
00432     return bytes_transferred;
00433   }
00434 
00435   // Start an asynchronous read.
00436   template <typename Stream, typename Mutable_Buffers, typename Handler>
00437   void async_read_some(impl_type& impl, Stream& next_layer,
00438       const Mutable_Buffers& buffers, Handler handler)
00439   {
00440     typedef io_handler<Stream, Handler> recv_handler;
00441 
00442     recv_handler* local_handler = new recv_handler(handler, get_io_service());
00443 
00444     std::size_t buffer_size = asio::buffer_size(*buffers.begin());
00445     if (buffer_size > max_buffer_size)
00446       buffer_size = max_buffer_size;
00447 
00448     boost::function<int (SSL*)> recv_func =
00449       boost::bind(&::SSL_read, boost::arg<1>(),
00450           asio::buffer_cast<void*>(*buffers.begin()),
00451           static_cast<int>(buffer_size));
00452 
00453     openssl_operation<Stream>* op = new openssl_operation<Stream>
00454     (
00455       recv_func,
00456       next_layer,
00457       impl->recv_buf,
00458       impl->ssl,
00459       impl->ext_bio,
00460       boost::bind
00461       (
00462         &base_handler<Stream>::do_func, 
00463         local_handler, 
00464         boost::arg<1>(),
00465         boost::arg<2>()
00466       ),
00467       strand_
00468     );
00469     local_handler->set_operation(op);
00470 
00471     strand_.post(boost::bind(&openssl_operation<Stream>::start, op));        
00472   }
00473 
00474   // Peek at the incoming data on the stream.
00475   template <typename Stream, typename Mutable_Buffers>
00476   std::size_t peek(impl_type& impl, Stream& next_layer,
00477       const Mutable_Buffers& buffers, asio::error_code& ec)
00478   {
00479     ec = asio::error_code();
00480     return 0;
00481   }
00482 
00483   // Determine the amount of data that may be read without blocking.
00484   template <typename Stream>
00485   std::size_t in_avail(impl_type& impl, Stream& next_layer,
00486       asio::error_code& ec)
00487   {
00488     ec = asio::error_code();
00489     return 0;
00490   }
00491 
00492 private:  
00493   asio::io_service::strand strand_;
00494 
00495   typedef asio::detail::mutex mutex_type;
00496   
00497   template<typename Mutex>
00498   struct ssl_wrap
00499   {
00500     static Mutex ssl_mutex_;
00501 
00502     static int SSL_accept(SSL *ssl)
00503     {
00504       typename Mutex::scoped_lock lock(ssl_mutex_);
00505       return ::SSL_accept(ssl);
00506     }
00507   
00508     static int SSL_connect(SSL *ssl)
00509     {
00510       typename Mutex::scoped_lock lock(ssl_mutex_);
00511       return ::SSL_connect(ssl);
00512     }
00513   
00514     static int SSL_shutdown(SSL *ssl)
00515     {
00516       typename Mutex::scoped_lock lock(ssl_mutex_);
00517       return ::SSL_shutdown(ssl);  
00518     }    
00519   };  
00520 };
00521 
00522 template<typename Mutex>
00523 Mutex openssl_stream_service::ssl_wrap<Mutex>::ssl_mutex_;
00524 
00525 } // namespace detail
00526 } // namespace ssl
00527 } // namespace asio
00528 
00529 #include "asio/detail/pop_options.hpp"
00530 
00531 #endif // ASIO_SSL_DETAIL_OPENSSL_STREAM_SERVICE_HPP
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines


Castor
Author(s): Carpe Noctem
autogenerated on Fri Nov 8 2013 11:05:39