00001
00002
00003
00004
00005
00006
00007
00008
00009
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
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 };
00082
00083
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 };
00106
00107
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 };
00131
00132
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 };
00155
00156 public:
00157
00158 typedef struct impl_struct
00159 {
00160 ::SSL* ssl;
00161 ::BIO* ext_bio;
00162 net_buffer recv_buf;
00163 } * impl_type;
00164
00165
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
00173 void shutdown_service()
00174 {
00175 }
00176
00177
00178 impl_type null() const
00179 {
00180 return 0;
00181 }
00182
00183
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
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
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
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
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
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
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
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
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
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
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
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 }
00526 }
00527 }
00528
00529 #include "asio/detail/pop_options.hpp"
00530
00531 #endif // ASIO_SSL_DETAIL_OPENSSL_STREAM_SERVICE_HPP