1 // 2 // ssl/old/detail/stream_service.hpp 3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4 // 5 // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com 6 // Copyright (c) 2005-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 // 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) 10 // 11 12 #ifndef BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_STREAM_SERVICE_HPP 13 #define BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_STREAM_SERVICE_HPP 14 15 #if defined(_MSC_VER) && (_MSC_VER >= 1200) 16 # pragma once 17 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) 18 19 #include <boost/asio/detail/config.hpp> 20 #include <cstddef> 21 #include <climits> 22 #include <memory> 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> 36 37 #include <boost/asio/detail/push_options.hpp> 38 39 namespace boost { 40 namespace asio { 41 namespace ssl { 42 namespace old { 43 namespace detail { 44 45 class openssl_stream_service 46 : public boost::asio::detail::service_base<openssl_stream_service> 47 { 48 private: 49 enum { max_buffer_size = INT_MAX }; 50 51 //Base handler for asyncrhonous operations 52 template <typename Stream> 53 class base_handler 54 { 55 public: 56 typedef boost::function< 57 void (const boost::system::error_code&, size_t)> func_t; 58 base_handler(boost::asio::io_service & io_service)59 base_handler(boost::asio::io_service& io_service) 60 : op_(NULL) 61 , io_service_(io_service) 62 , work_(io_service) 63 {} 64 do_func(const boost::system::error_code & error,size_t size)65 void do_func(const boost::system::error_code& error, size_t size) 66 { 67 func_(error, size); 68 } 69 set_operation(openssl_operation<Stream> * op)70 void set_operation(openssl_operation<Stream>* op) { op_ = op; } set_func(func_t func)71 void set_func(func_t func) { func_ = func; } 72 ~base_handler()73 ~base_handler() 74 { 75 delete op_; 76 } 77 78 private: 79 func_t func_; 80 openssl_operation<Stream>* op_; 81 boost::asio::io_service& io_service_; 82 boost::asio::io_service::work work_; 83 }; // class base_handler 84 85 // Handler for asynchronous IO (write/read) operations 86 template<typename Stream, typename Handler> 87 class io_handler 88 : public base_handler<Stream> 89 { 90 public: io_handler(Handler handler,boost::asio::io_service & io_service)91 io_handler(Handler handler, boost::asio::io_service& io_service) 92 : base_handler<Stream>(io_service) 93 , handler_(handler) 94 { 95 this->set_func(boost::bind( 96 &io_handler<Stream, Handler>::handler_impl, 97 this, boost::arg<1>(), boost::arg<2>() )); 98 } 99 100 private: 101 Handler handler_; handler_impl(const boost::system::error_code & error,size_t size)102 void handler_impl(const boost::system::error_code& error, size_t size) 103 { 104 std::auto_ptr<io_handler<Stream, Handler> > this_ptr(this); 105 handler_(error, size); 106 } 107 }; // class io_handler 108 109 // Handler for asyncrhonous handshake (connect, accept) functions 110 template <typename Stream, typename Handler> 111 class handshake_handler 112 : public base_handler<Stream> 113 { 114 public: handshake_handler(Handler handler,boost::asio::io_service & io_service)115 handshake_handler(Handler handler, boost::asio::io_service& io_service) 116 : base_handler<Stream>(io_service) 117 , handler_(handler) 118 { 119 this->set_func(boost::bind( 120 &handshake_handler<Stream, Handler>::handler_impl, 121 this, boost::arg<1>(), boost::arg<2>() )); 122 } 123 124 private: 125 Handler handler_; handler_impl(const boost::system::error_code & error,size_t)126 void handler_impl(const boost::system::error_code& error, size_t) 127 { 128 std::auto_ptr<handshake_handler<Stream, Handler> > this_ptr(this); 129 handler_(error); 130 } 131 132 }; // class handshake_handler 133 134 // Handler for asyncrhonous shutdown 135 template <typename Stream, typename Handler> 136 class shutdown_handler 137 : public base_handler<Stream> 138 { 139 public: shutdown_handler(Handler handler,boost::asio::io_service & io_service)140 shutdown_handler(Handler handler, boost::asio::io_service& io_service) 141 : base_handler<Stream>(io_service), 142 handler_(handler) 143 { 144 this->set_func(boost::bind( 145 &shutdown_handler<Stream, Handler>::handler_impl, 146 this, boost::arg<1>(), boost::arg<2>() )); 147 } 148 149 private: 150 Handler handler_; handler_impl(const boost::system::error_code & error,size_t)151 void handler_impl(const boost::system::error_code& error, size_t) 152 { 153 std::auto_ptr<shutdown_handler<Stream, Handler> > this_ptr(this); 154 handler_(error); 155 } 156 }; // class shutdown_handler 157 158 public: 159 // The implementation type. 160 typedef struct impl_struct 161 { 162 ::SSL* ssl; 163 ::BIO* ext_bio; 164 net_buffer recv_buf; 165 } * impl_type; 166 167 // Construct a new stream socket service for the specified io_service. openssl_stream_service(boost::asio::io_service & io_service)168 explicit openssl_stream_service(boost::asio::io_service& io_service) 169 : boost::asio::detail::service_base<openssl_stream_service>(io_service), 170 strand_(io_service) 171 { 172 } 173 174 // Destroy all user-defined handler objects owned by the service. shutdown_service()175 void shutdown_service() 176 { 177 } 178 179 // Return a null stream implementation. null() const180 impl_type null() const 181 { 182 return 0; 183 } 184 185 // Create a new stream implementation. 186 template <typename Stream, typename Context_Service> create(impl_type & impl,Stream &,basic_context<Context_Service> & context)187 void create(impl_type& impl, Stream& /*next_layer*/, 188 basic_context<Context_Service>& context) 189 { 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); 194 ::BIO* int_bio = 0; 195 impl->ext_bio = 0; 196 ::BIO_new_bio_pair(&int_bio, 8192, &impl->ext_bio, 8192); 197 ::SSL_set_bio(impl->ssl, int_bio, int_bio); 198 } 199 200 // Destroy a stream implementation. 201 template <typename Stream> destroy(impl_type & impl,Stream &)202 void destroy(impl_type& impl, Stream& /*next_layer*/) 203 { 204 if (impl != 0) 205 { 206 ::BIO_free(impl->ext_bio); 207 ::SSL_free(impl->ssl); 208 delete impl; 209 impl = 0; 210 } 211 } 212 213 // Perform SSL handshaking. 214 template <typename Stream> handshake(impl_type & impl,Stream & next_layer,stream_base::handshake_type type,boost::system::error_code & ec)215 boost::system::error_code handshake(impl_type& impl, Stream& next_layer, 216 stream_base::handshake_type type, boost::system::error_code& ec) 217 { 218 try 219 { 220 openssl_operation<Stream> op( 221 type == stream_base::client ? 222 &ssl_wrap<mutex_type>::SSL_connect: 223 &ssl_wrap<mutex_type>::SSL_accept, 224 next_layer, 225 impl->recv_buf, 226 impl->ssl, 227 impl->ext_bio); 228 op.start(); 229 } 230 catch (boost::system::system_error& e) 231 { 232 ec = e.code(); 233 return ec; 234 } 235 236 ec = boost::system::error_code(); 237 return ec; 238 } 239 240 // Start an asynchronous SSL handshake. 241 template <typename Stream, typename Handler> async_handshake(impl_type & impl,Stream & next_layer,stream_base::handshake_type type,Handler handler)242 void async_handshake(impl_type& impl, Stream& next_layer, 243 stream_base::handshake_type type, Handler handler) 244 { 245 typedef handshake_handler<Stream, Handler> connect_handler; 246 247 connect_handler* local_handler = 248 new connect_handler(handler, get_io_service()); 249 250 openssl_operation<Stream>* op = new openssl_operation<Stream> 251 ( 252 type == stream_base::client ? 253 &ssl_wrap<mutex_type>::SSL_connect: 254 &ssl_wrap<mutex_type>::SSL_accept, 255 next_layer, 256 impl->recv_buf, 257 impl->ssl, 258 impl->ext_bio, 259 boost::bind 260 ( 261 &base_handler<Stream>::do_func, 262 local_handler, 263 boost::arg<1>(), 264 boost::arg<2>() 265 ), 266 strand_ 267 ); 268 local_handler->set_operation(op); 269 270 strand_.post(boost::bind(&openssl_operation<Stream>::start, op)); 271 } 272 273 // Shut down SSL on the stream. 274 template <typename Stream> shutdown(impl_type & impl,Stream & next_layer,boost::system::error_code & ec)275 boost::system::error_code shutdown(impl_type& impl, Stream& next_layer, 276 boost::system::error_code& ec) 277 { 278 try 279 { 280 openssl_operation<Stream> op( 281 &ssl_wrap<mutex_type>::SSL_shutdown, 282 next_layer, 283 impl->recv_buf, 284 impl->ssl, 285 impl->ext_bio); 286 op.start(); 287 } 288 catch (boost::system::system_error& e) 289 { 290 ec = e.code(); 291 return ec; 292 } 293 294 ec = boost::system::error_code(); 295 return ec; 296 } 297 298 // Asynchronously shut down SSL on the stream. 299 template <typename Stream, typename Handler> async_shutdown(impl_type & impl,Stream & next_layer,Handler handler)300 void async_shutdown(impl_type& impl, Stream& next_layer, Handler handler) 301 { 302 typedef shutdown_handler<Stream, Handler> disconnect_handler; 303 304 disconnect_handler* local_handler = 305 new disconnect_handler(handler, get_io_service()); 306 307 openssl_operation<Stream>* op = new openssl_operation<Stream> 308 ( 309 &ssl_wrap<mutex_type>::SSL_shutdown, 310 next_layer, 311 impl->recv_buf, 312 impl->ssl, 313 impl->ext_bio, 314 boost::bind 315 ( 316 &base_handler<Stream>::do_func, 317 local_handler, 318 boost::arg<1>(), 319 boost::arg<2>() 320 ), 321 strand_ 322 ); 323 local_handler->set_operation(op); 324 325 strand_.post(boost::bind(&openssl_operation<Stream>::start, op)); 326 } 327 328 // Write some data to the stream. 329 template <typename Stream, typename Const_Buffers> write_some(impl_type & impl,Stream & next_layer,const Const_Buffers & buffers,boost::system::error_code & ec)330 std::size_t write_some(impl_type& impl, Stream& next_layer, 331 const Const_Buffers& buffers, boost::system::error_code& ec) 332 { 333 size_t bytes_transferred = 0; 334 try 335 { 336 boost::asio::const_buffer buffer = 337 boost::asio::detail::buffer_sequence_adapter< 338 boost::asio::const_buffer, Const_Buffers>::first(buffers); 339 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) 344 { 345 ec = boost::system::error_code(); 346 return 0; 347 } 348 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( 354 send_func, 355 next_layer, 356 impl->recv_buf, 357 impl->ssl, 358 impl->ext_bio 359 ); 360 bytes_transferred = static_cast<size_t>(op.start()); 361 } 362 catch (boost::system::system_error& e) 363 { 364 ec = e.code(); 365 return 0; 366 } 367 368 ec = boost::system::error_code(); 369 return bytes_transferred; 370 } 371 372 // Start an asynchronous write. 373 template <typename Stream, typename Const_Buffers, typename Handler> async_write_some(impl_type & impl,Stream & next_layer,const Const_Buffers & buffers,Handler handler)374 void async_write_some(impl_type& impl, Stream& next_layer, 375 const Const_Buffers& buffers, Handler handler) 376 { 377 typedef io_handler<Stream, Handler> send_handler; 378 379 boost::asio::const_buffer buffer = 380 boost::asio::detail::buffer_sequence_adapter< 381 boost::asio::const_buffer, Const_Buffers>::first(buffers); 382 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) 387 { 388 get_io_service().post(boost::asio::detail::bind_handler( 389 handler, boost::system::error_code(), 0)); 390 return; 391 } 392 393 send_handler* local_handler = new send_handler(handler, get_io_service()); 394 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)); 399 400 openssl_operation<Stream>* op = new openssl_operation<Stream> 401 ( 402 send_func, 403 next_layer, 404 impl->recv_buf, 405 impl->ssl, 406 impl->ext_bio, 407 boost::bind 408 ( 409 &base_handler<Stream>::do_func, 410 local_handler, 411 boost::arg<1>(), 412 boost::arg<2>() 413 ), 414 strand_ 415 ); 416 local_handler->set_operation(op); 417 418 strand_.post(boost::bind(&openssl_operation<Stream>::start, op)); 419 } 420 421 // Read some data from the stream. 422 template <typename Stream, typename Mutable_Buffers> read_some(impl_type & impl,Stream & next_layer,const Mutable_Buffers & buffers,boost::system::error_code & ec)423 std::size_t read_some(impl_type& impl, Stream& next_layer, 424 const Mutable_Buffers& buffers, boost::system::error_code& ec) 425 { 426 size_t bytes_transferred = 0; 427 try 428 { 429 boost::asio::mutable_buffer buffer = 430 boost::asio::detail::buffer_sequence_adapter< 431 boost::asio::mutable_buffer, Mutable_Buffers>::first(buffers); 432 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) 437 { 438 ec = boost::system::error_code(); 439 return 0; 440 } 441 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, 447 next_layer, 448 impl->recv_buf, 449 impl->ssl, 450 impl->ext_bio 451 ); 452 453 bytes_transferred = static_cast<size_t>(op.start()); 454 } 455 catch (boost::system::system_error& e) 456 { 457 ec = e.code(); 458 return 0; 459 } 460 461 ec = boost::system::error_code(); 462 return bytes_transferred; 463 } 464 465 // Start an asynchronous read. 466 template <typename Stream, typename Mutable_Buffers, typename Handler> async_read_some(impl_type & impl,Stream & next_layer,const Mutable_Buffers & buffers,Handler handler)467 void async_read_some(impl_type& impl, Stream& next_layer, 468 const Mutable_Buffers& buffers, Handler handler) 469 { 470 typedef io_handler<Stream, Handler> recv_handler; 471 472 boost::asio::mutable_buffer buffer = 473 boost::asio::detail::buffer_sequence_adapter< 474 boost::asio::mutable_buffer, Mutable_Buffers>::first(buffers); 475 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) 480 { 481 get_io_service().post(boost::asio::detail::bind_handler( 482 handler, boost::system::error_code(), 0)); 483 return; 484 } 485 486 recv_handler* local_handler = new recv_handler(handler, get_io_service()); 487 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)); 492 493 openssl_operation<Stream>* op = new openssl_operation<Stream> 494 ( 495 recv_func, 496 next_layer, 497 impl->recv_buf, 498 impl->ssl, 499 impl->ext_bio, 500 boost::bind 501 ( 502 &base_handler<Stream>::do_func, 503 local_handler, 504 boost::arg<1>(), 505 boost::arg<2>() 506 ), 507 strand_ 508 ); 509 local_handler->set_operation(op); 510 511 strand_.post(boost::bind(&openssl_operation<Stream>::start, op)); 512 } 513 514 // Peek at the incoming data on the stream. 515 template <typename Stream, typename Mutable_Buffers> peek(impl_type &,Stream &,const Mutable_Buffers &,boost::system::error_code & ec)516 std::size_t peek(impl_type& /*impl*/, Stream& /*next_layer*/, 517 const Mutable_Buffers& /*buffers*/, boost::system::error_code& ec) 518 { 519 ec = boost::system::error_code(); 520 return 0; 521 } 522 523 // Determine the amount of data that may be read without blocking. 524 template <typename Stream> in_avail(impl_type &,Stream &,boost::system::error_code & ec)525 std::size_t in_avail(impl_type& /*impl*/, Stream& /*next_layer*/, 526 boost::system::error_code& ec) 527 { 528 ec = boost::system::error_code(); 529 return 0; 530 } 531 532 private: 533 boost::asio::io_service::strand strand_; 534 535 typedef boost::asio::detail::mutex mutex_type; 536 537 template<typename Mutex> 538 struct ssl_wrap 539 { 540 static Mutex ssl_mutex_; 541 SSL_acceptboost::asio::ssl::old::detail::openssl_stream_service::ssl_wrap542 static int SSL_accept(SSL *ssl) 543 { 544 typename Mutex::scoped_lock lock(ssl_mutex_); 545 return ::SSL_accept(ssl); 546 } 547 SSL_connectboost::asio::ssl::old::detail::openssl_stream_service::ssl_wrap548 static int SSL_connect(SSL *ssl) 549 { 550 typename Mutex::scoped_lock lock(ssl_mutex_); 551 return ::SSL_connect(ssl); 552 } 553 SSL_shutdownboost::asio::ssl::old::detail::openssl_stream_service::ssl_wrap554 static int SSL_shutdown(SSL *ssl) 555 { 556 typename Mutex::scoped_lock lock(ssl_mutex_); 557 return ::SSL_shutdown(ssl); 558 } 559 }; 560 }; 561 562 template<typename Mutex> 563 Mutex openssl_stream_service::ssl_wrap<Mutex>::ssl_mutex_; 564 565 } // namespace detail 566 } // namespace old 567 } // namespace ssl 568 } // namespace asio 569 } // namespace boost 570 571 #include <boost/asio/detail/pop_options.hpp> 572 573 #endif // BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_STREAM_SERVICE_HPP 574