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 <boost/config.hpp>
00024 #include <boost/noncopyable.hpp>
00025 #include <boost/function.hpp>
00026 #include <boost/bind.hpp>
00027 #include "asio/detail/pop_options.hpp"
00028
00029 #include "asio/error.hpp"
00030 #include "asio/io_service.hpp"
00031 #include "asio/detail/service_base.hpp"
00032 #include "asio/ssl/basic_context.hpp"
00033 #include "asio/ssl/stream_base.hpp"
00034 #include "asio/ssl/detail/openssl_operation.hpp"
00035 #include "asio/ssl/detail/openssl_types.hpp"
00036
00037 namespace asio {
00038 namespace ssl {
00039 namespace detail {
00040
00041 class openssl_stream_service
00042 : public asio::detail::service_base<openssl_stream_service>
00043 {
00044 private:
00045
00046 template <typename Stream>
00047 class base_handler
00048 {
00049 public:
00050 typedef boost::function<
00051 void (const asio::error_code&, size_t)> func_t;
00052
00053 base_handler(asio::io_service& io_service)
00054 : op_(NULL)
00055 , io_service_(io_service)
00056 , work_(io_service)
00057 {}
00058
00059 void do_func(const asio::error_code& error, size_t size)
00060 {
00061 func_(error, size);
00062 }
00063
00064 void set_operation(openssl_operation<Stream>* op) { op_ = op; }
00065 void set_func(func_t func) { func_ = func; }
00066
00067 ~base_handler()
00068 {
00069 delete op_;
00070 }
00071
00072 private:
00073 func_t func_;
00074 openssl_operation<Stream>* op_;
00075 asio::io_service& io_service_;
00076 asio::io_service::work work_;
00077 };
00078
00079
00080 template<typename Stream, typename Handler>
00081 class io_handler
00082 : public base_handler<Stream>
00083 {
00084 public:
00085 io_handler(Handler handler, asio::io_service& io_service)
00086 : base_handler<Stream>(io_service)
00087 , handler_(handler)
00088 {
00089 set_func(boost::bind(
00090 &io_handler<Stream, Handler>::handler_impl,
00091 this, boost::arg<1>(), boost::arg<2>() ));
00092 }
00093
00094 private:
00095 Handler handler_;
00096 void handler_impl(const asio::error_code& error, size_t size)
00097 {
00098 handler_(error, size);
00099 delete this;
00100 }
00101 };
00102
00103
00104 template <typename Stream, typename Handler>
00105 class handshake_handler
00106 : public base_handler<Stream>
00107 {
00108 public:
00109 handshake_handler(Handler handler, asio::io_service& io_service)
00110 : base_handler<Stream>(io_service)
00111 , handler_(handler)
00112 {
00113 set_func(boost::bind(
00114 &handshake_handler<Stream, Handler>::handler_impl,
00115 this, boost::arg<1>(), boost::arg<2>() ));
00116 }
00117
00118 private:
00119 Handler handler_;
00120 void handler_impl(const asio::error_code& error, size_t)
00121 {
00122 handler_(error);
00123 delete this;
00124 }
00125
00126 };
00127
00128
00129 template <typename Stream, typename Handler>
00130 class shutdown_handler
00131 : public base_handler<Stream>
00132 {
00133 public:
00134 shutdown_handler(Handler handler, asio::io_service& io_service)
00135 : base_handler<Stream>(io_service),
00136 handler_(handler)
00137 {
00138 set_func(boost::bind(
00139 &shutdown_handler<Stream, Handler>::handler_impl,
00140 this, boost::arg<1>(), boost::arg<2>() ));
00141 }
00142
00143 private:
00144 Handler handler_;
00145 void handler_impl(const asio::error_code& error, size_t)
00146 {
00147 handler_(error);
00148 delete this;
00149 }
00150 };
00151
00152 public:
00153
00154 typedef struct impl_struct
00155 {
00156 ::SSL* ssl;
00157 ::BIO* ext_bio;
00158 net_buffer recv_buf;
00159 } * impl_type;
00160
00161
00162 explicit openssl_stream_service(asio::io_service& io_service)
00163 : asio::detail::service_base<openssl_stream_service>(io_service)
00164 {
00165 }
00166
00167
00168 void shutdown_service()
00169 {
00170 }
00171
00172
00173 impl_type null() const
00174 {
00175 return 0;
00176 }
00177
00178
00179 template <typename Stream, typename Context_Service>
00180 void create(impl_type& impl, Stream& next_layer,
00181 basic_context<Context_Service>& context)
00182 {
00183 impl = new impl_struct;
00184 impl->ssl = ::SSL_new(context.impl());
00185 ::SSL_set_mode(impl->ssl, SSL_MODE_ENABLE_PARTIAL_WRITE);
00186 ::SSL_set_mode(impl->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
00187 ::BIO* int_bio = 0;
00188 impl->ext_bio = 0;
00189 ::BIO_new_bio_pair(&int_bio, 8192, &impl->ext_bio, 8192);
00190 ::SSL_set_bio(impl->ssl, int_bio, int_bio);
00191 }
00192
00193
00194 template <typename Stream>
00195 void destroy(impl_type& impl, Stream& next_layer)
00196 {
00197 if (impl != 0)
00198 {
00199 ::BIO_free(impl->ext_bio);
00200 ::SSL_free(impl->ssl);
00201 delete impl;
00202 impl = 0;
00203 }
00204 }
00205
00206
00207 template <typename Stream>
00208 asio::error_code handshake(impl_type& impl, Stream& next_layer,
00209 stream_base::handshake_type type, asio::error_code& ec)
00210 {
00211 try
00212 {
00213 openssl_operation<Stream> op(
00214 type == stream_base::client ?
00215 &ssl_wrap<mutex_type>::SSL_connect:
00216 &ssl_wrap<mutex_type>::SSL_accept,
00217 next_layer,
00218 impl->recv_buf,
00219 impl->ssl,
00220 impl->ext_bio);
00221 op.start();
00222 }
00223 catch (asio::system_error& e)
00224 {
00225 ec = e.code();
00226 return ec;
00227 }
00228
00229 ec = asio::error_code();
00230 return ec;
00231 }
00232
00233
00234 template <typename Stream, typename Handler>
00235 void async_handshake(impl_type& impl, Stream& next_layer,
00236 stream_base::handshake_type type, Handler handler)
00237 {
00238 typedef handshake_handler<Stream, Handler> connect_handler;
00239
00240 connect_handler* local_handler =
00241 new connect_handler(handler, io_service());
00242
00243 openssl_operation<Stream>* op = new openssl_operation<Stream>
00244 (
00245 type == stream_base::client ?
00246 &ssl_wrap<mutex_type>::SSL_connect:
00247 &ssl_wrap<mutex_type>::SSL_accept,
00248 next_layer,
00249 impl->recv_buf,
00250 impl->ssl,
00251 impl->ext_bio,
00252 boost::bind
00253 (
00254 &base_handler<Stream>::do_func,
00255 local_handler,
00256 boost::arg<1>(),
00257 boost::arg<2>()
00258 )
00259 );
00260 local_handler->set_operation(op);
00261
00262 io_service().post(boost::bind(&openssl_operation<Stream>::start, op));
00263 }
00264
00265
00266 template <typename Stream>
00267 asio::error_code shutdown(impl_type& impl, Stream& next_layer,
00268 asio::error_code& ec)
00269 {
00270 try
00271 {
00272 openssl_operation<Stream> op(
00273 &ssl_wrap<mutex_type>::SSL_shutdown,
00274 next_layer,
00275 impl->recv_buf,
00276 impl->ssl,
00277 impl->ext_bio);
00278 op.start();
00279 }
00280 catch (asio::system_error& e)
00281 {
00282 ec = e.code();
00283 return ec;
00284 }
00285
00286 ec = asio::error_code();
00287 return ec;
00288 }
00289
00290
00291 template <typename Stream, typename Handler>
00292 void async_shutdown(impl_type& impl, Stream& next_layer, Handler handler)
00293 {
00294 typedef shutdown_handler<Stream, Handler> disconnect_handler;
00295
00296 disconnect_handler* local_handler =
00297 new disconnect_handler(handler, io_service());
00298
00299 openssl_operation<Stream>* op = new openssl_operation<Stream>
00300 (
00301 &ssl_wrap<mutex_type>::SSL_shutdown,
00302 next_layer,
00303 impl->recv_buf,
00304 impl->ssl,
00305 impl->ext_bio,
00306 boost::bind
00307 (
00308 &base_handler<Stream>::do_func,
00309 local_handler,
00310 boost::arg<1>(),
00311 boost::arg<2>()
00312 )
00313 );
00314 local_handler->set_operation(op);
00315
00316 io_service().post(boost::bind(&openssl_operation<Stream>::start, op));
00317 }
00318
00319
00320 template <typename Stream, typename Const_Buffers>
00321 std::size_t write_some(impl_type& impl, Stream& next_layer,
00322 const Const_Buffers& buffers, asio::error_code& ec)
00323 {
00324 size_t bytes_transferred = 0;
00325 try
00326 {
00327 boost::function<int (SSL*)> send_func =
00328 boost::bind(&::SSL_write, boost::arg<1>(),
00329 asio::buffer_cast<const void*>(*buffers.begin()),
00330 static_cast<int>(asio::buffer_size(*buffers.begin())));
00331 openssl_operation<Stream> op(
00332 send_func,
00333 next_layer,
00334 impl->recv_buf,
00335 impl->ssl,
00336 impl->ext_bio
00337 );
00338 bytes_transferred = static_cast<size_t>(op.start());
00339 }
00340 catch (asio::system_error& e)
00341 {
00342 ec = e.code();
00343 return 0;
00344 }
00345
00346 ec = asio::error_code();
00347 return bytes_transferred;
00348 }
00349
00350
00351 template <typename Stream, typename Const_Buffers, typename Handler>
00352 void async_write_some(impl_type& impl, Stream& next_layer,
00353 const Const_Buffers& buffers, Handler handler)
00354 {
00355 typedef io_handler<Stream, Handler> send_handler;
00356
00357 send_handler* local_handler = new send_handler(handler, io_service());
00358
00359 boost::function<int (SSL*)> send_func =
00360 boost::bind(&::SSL_write, boost::arg<1>(),
00361 asio::buffer_cast<const void*>(*buffers.begin()),
00362 static_cast<int>(asio::buffer_size(*buffers.begin())));
00363
00364 openssl_operation<Stream>* op = new openssl_operation<Stream>
00365 (
00366 send_func,
00367 next_layer,
00368 impl->recv_buf,
00369 impl->ssl,
00370 impl->ext_bio,
00371 boost::bind
00372 (
00373 &base_handler<Stream>::do_func,
00374 local_handler,
00375 boost::arg<1>(),
00376 boost::arg<2>()
00377 )
00378 );
00379 local_handler->set_operation(op);
00380
00381 io_service().post(boost::bind(&openssl_operation<Stream>::start, op));
00382 }
00383
00384
00385 template <typename Stream, typename Mutable_Buffers>
00386 std::size_t read_some(impl_type& impl, Stream& next_layer,
00387 const Mutable_Buffers& buffers, asio::error_code& ec)
00388 {
00389 size_t bytes_transferred = 0;
00390 try
00391 {
00392 boost::function<int (SSL*)> recv_func =
00393 boost::bind(&::SSL_read, boost::arg<1>(),
00394 asio::buffer_cast<void*>(*buffers.begin()),
00395 asio::buffer_size(*buffers.begin()));
00396 openssl_operation<Stream> op(recv_func,
00397 next_layer,
00398 impl->recv_buf,
00399 impl->ssl,
00400 impl->ext_bio
00401 );
00402
00403 bytes_transferred = static_cast<size_t>(op.start());
00404 }
00405 catch (asio::system_error& e)
00406 {
00407 ec = e.code();
00408 return 0;
00409 }
00410
00411 ec = asio::error_code();
00412 return bytes_transferred;
00413 }
00414
00415
00416 template <typename Stream, typename Mutable_Buffers, typename Handler>
00417 void async_read_some(impl_type& impl, Stream& next_layer,
00418 const Mutable_Buffers& buffers, Handler handler)
00419 {
00420 typedef io_handler<Stream, Handler> recv_handler;
00421
00422 recv_handler* local_handler = new recv_handler(handler, io_service());
00423
00424 boost::function<int (SSL*)> recv_func =
00425 boost::bind(&::SSL_read, boost::arg<1>(),
00426 asio::buffer_cast<void*>(*buffers.begin()),
00427 asio::buffer_size(*buffers.begin()));
00428
00429 openssl_operation<Stream>* op = new openssl_operation<Stream>
00430 (
00431 recv_func,
00432 next_layer,
00433 impl->recv_buf,
00434 impl->ssl,
00435 impl->ext_bio,
00436 boost::bind
00437 (
00438 &base_handler<Stream>::do_func,
00439 local_handler,
00440 boost::arg<1>(),
00441 boost::arg<2>()
00442 )
00443 );
00444 local_handler->set_operation(op);
00445
00446 io_service().post(boost::bind(&openssl_operation<Stream>::start, op));
00447 }
00448
00449
00450 template <typename Stream, typename Mutable_Buffers>
00451 std::size_t peek(impl_type& impl, Stream& next_layer,
00452 const Mutable_Buffers& buffers, asio::error_code& ec)
00453 {
00454 ec = asio::error_code();
00455 return 0;
00456 }
00457
00458
00459 template <typename Stream>
00460 std::size_t in_avail(impl_type& impl, Stream& next_layer,
00461 asio::error_code& ec)
00462 {
00463 ec = asio::error_code();
00464 return 0;
00465 }
00466
00467 private:
00468 typedef asio::detail::mutex mutex_type;
00469
00470 template<typename Mutex>
00471 struct ssl_wrap
00472 {
00473 static Mutex ssl_mutex_;
00474
00475 static int SSL_accept(SSL *ssl)
00476 {
00477 typename Mutex::scoped_lock lock(ssl_mutex_);
00478 return ::SSL_accept(ssl);
00479 }
00480
00481 static int SSL_connect(SSL *ssl)
00482 {
00483 typename Mutex::scoped_lock lock(ssl_mutex_);
00484 return ::SSL_connect(ssl);
00485 }
00486
00487 static int SSL_shutdown(SSL *ssl)
00488 {
00489 typename Mutex::scoped_lock lock(ssl_mutex_);
00490 return ::SSL_shutdown(ssl);
00491 }
00492 };
00493 };
00494
00495 template<typename Mutex>
00496 Mutex openssl_stream_service::ssl_wrap<Mutex>::ssl_mutex_;
00497
00498 }
00499 }
00500 }
00501
00502 #include "asio/detail/pop_options.hpp"
00503
00504 #endif // ASIO_SSL_DETAIL_OPENSSL_STREAM_SERVICE_HPP