$search
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