00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #ifndef ASIO_SSL_DETAIL_OPENSSL_OPERATION_HPP
00012 #define ASIO_SSL_DETAIL_OPENSSL_OPERATION_HPP
00013
00014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
00015 # pragma once
00016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
00017
00018 #include "asio/detail/push_options.hpp"
00019
00020 #include "asio/detail/push_options.hpp"
00021 #include <boost/function.hpp>
00022 #include <boost/assert.hpp>
00023 #include <boost/bind.hpp>
00024 #include "asio/detail/pop_options.hpp"
00025
00026 #include "asio/buffer.hpp"
00027 #include "asio/placeholders.hpp"
00028 #include "asio/write.hpp"
00029 #include "asio/detail/socket_ops.hpp"
00030 #include "asio/ssl/detail/openssl_types.hpp"
00031
00032 namespace asio {
00033 namespace ssl {
00034 namespace detail {
00035
00036 typedef boost::function<int (::SSL*)> ssl_primitive_func;
00037 typedef boost::function<void (const asio::error_code&, int)>
00038 user_handler_func;
00039
00040
00041
00042
00043 class net_buffer
00044 {
00045 static const int NET_BUF_SIZE = 16*1024 + 256;
00046
00047 unsigned char buf_[NET_BUF_SIZE];
00048 unsigned char* data_start_;
00049 unsigned char* data_end_;
00050
00051 public:
00052 net_buffer()
00053 {
00054 data_start_ = data_end_ = buf_;
00055 }
00056 unsigned char* get_unused_start() { return data_end_; }
00057 unsigned char* get_data_start() { return data_start_; }
00058 size_t get_unused_len() { return (NET_BUF_SIZE - (data_end_ - buf_)); }
00059 size_t get_data_len() { return (data_end_ - data_start_); }
00060 void data_added(size_t count)
00061 {
00062 data_end_ += count;
00063 data_end_ = data_end_ > (buf_ + NET_BUF_SIZE)?
00064 (buf_ + NET_BUF_SIZE):
00065 data_end_;
00066 }
00067 void data_removed(size_t count)
00068 {
00069 data_start_ += count;
00070 if (data_start_ >= data_end_) reset();
00071 }
00072 void reset() { data_start_ = buf_; data_end_ = buf_; }
00073 bool has_data() { return (data_start_ < data_end_); }
00074 };
00075
00076
00077
00078
00079
00080 template <typename Stream>
00081 class openssl_operation
00082 {
00083 public:
00084
00085
00086 openssl_operation(ssl_primitive_func primitive,
00087 Stream& socket,
00088 net_buffer& recv_buf,
00089 SSL* session,
00090 BIO* ssl_bio,
00091 user_handler_func handler,
00092 asio::io_service::strand& strand
00093 )
00094 : primitive_(primitive)
00095 , user_handler_(handler)
00096 , strand_(&strand)
00097 , recv_buf_(recv_buf)
00098 , socket_(socket)
00099 , ssl_bio_(ssl_bio)
00100 , session_(session)
00101 {
00102 write_ = boost::bind(
00103 &openssl_operation::do_async_write,
00104 this, boost::arg<1>(), boost::arg<2>()
00105 );
00106 read_ = boost::bind(
00107 &openssl_operation::do_async_read,
00108 this
00109 );
00110 handler_= boost::bind(
00111 &openssl_operation::async_user_handler,
00112 this, boost::arg<1>(), boost::arg<2>()
00113 );
00114 }
00115
00116
00117 openssl_operation(ssl_primitive_func primitive,
00118 Stream& socket,
00119 net_buffer& recv_buf,
00120 SSL* session,
00121 BIO* ssl_bio)
00122 : primitive_(primitive)
00123 , strand_(0)
00124 , recv_buf_(recv_buf)
00125 , socket_(socket)
00126 , ssl_bio_(ssl_bio)
00127 , session_(session)
00128 {
00129 write_ = boost::bind(
00130 &openssl_operation::do_sync_write,
00131 this, boost::arg<1>(), boost::arg<2>()
00132 );
00133 read_ = boost::bind(
00134 &openssl_operation::do_sync_read,
00135 this
00136 );
00137 handler_ = boost::bind(
00138 &openssl_operation::sync_user_handler,
00139 this, boost::arg<1>(), boost::arg<2>()
00140 );
00141 }
00142
00143
00144
00145
00146 int start()
00147 {
00148 int rc = primitive_( session_ );
00149
00150 bool is_operation_done = (rc > 0);
00151
00152
00153
00154
00155
00156 int error_code = !is_operation_done ?
00157 ::SSL_get_error( session_, rc ) :
00158 0;
00159 int sys_error_code = ERR_get_error();
00160
00161 bool is_read_needed = (error_code == SSL_ERROR_WANT_READ);
00162 bool is_write_needed = (error_code == SSL_ERROR_WANT_WRITE ||
00163 ::BIO_ctrl_pending( ssl_bio_ ));
00164 bool is_shut_down_received =
00165 ((::SSL_get_shutdown( session_ ) & SSL_RECEIVED_SHUTDOWN) ==
00166 SSL_RECEIVED_SHUTDOWN);
00167 bool is_shut_down_sent =
00168 ((::SSL_get_shutdown( session_ ) & SSL_SENT_SHUTDOWN) ==
00169 SSL_SENT_SHUTDOWN);
00170
00171 if (is_shut_down_sent && is_shut_down_received && is_operation_done && !is_write_needed)
00172
00173 return handler_(asio::error_code(), 1);
00174
00175 if (is_shut_down_received && !is_operation_done)
00176
00177
00178 return handler_(asio::error::shut_down, 0);
00179
00180 if (!is_operation_done && !is_read_needed && !is_write_needed
00181 && !is_shut_down_sent)
00182 {
00183
00184
00185 if (error_code == SSL_ERROR_SYSCALL)
00186 {
00187 return handler_(asio::error_code(
00188 sys_error_code, asio::error::system_category), rc);
00189 }
00190 else
00191 {
00192 return handler_(asio::error_code(
00193 error_code, asio::error::get_ssl_category()), rc);
00194 }
00195 }
00196
00197 if (!is_operation_done && !is_write_needed)
00198 {
00199
00200 if (recv_buf_.get_data_len() > 0)
00201 {
00202
00203 int written = ::BIO_write
00204 (
00205 ssl_bio_,
00206 recv_buf_.get_data_start(),
00207 recv_buf_.get_data_len()
00208 );
00209
00210 if (written > 0)
00211 {
00212 recv_buf_.data_removed(written);
00213 }
00214 else if (written < 0)
00215 {
00216 if (!BIO_should_retry(ssl_bio_))
00217 {
00218
00219 return handler_(asio::error::no_recovery, 0);
00220 }
00221 }
00222
00223 return start();
00224 }
00225 else if (is_read_needed || (is_shut_down_sent && !is_shut_down_received))
00226 {
00227 return read_();
00228 }
00229 }
00230
00231
00232 return write_(is_operation_done, rc);
00233 }
00234
00235
00236 private:
00237 typedef boost::function<int (const asio::error_code&, int)>
00238 int_handler_func;
00239 typedef boost::function<int (bool, int)> write_func;
00240 typedef boost::function<int ()> read_func;
00241
00242 ssl_primitive_func primitive_;
00243 user_handler_func user_handler_;
00244 asio::io_service::strand* strand_;
00245 write_func write_;
00246 read_func read_;
00247 int_handler_func handler_;
00248
00249 net_buffer send_buf_;
00250
00251
00252
00253
00254
00255 net_buffer& recv_buf_;
00256
00257 Stream& socket_;
00258 BIO* ssl_bio_;
00259 SSL* session_;
00260
00261
00262 int sync_user_handler(const asio::error_code& error, int rc)
00263 {
00264 if (!error)
00265 return rc;
00266
00267 throw asio::system_error(error);
00268 }
00269
00270 int async_user_handler(asio::error_code error, int rc)
00271 {
00272 if (rc < 0)
00273 {
00274 if (!error)
00275 error = asio::error::no_recovery;
00276 rc = 0;
00277 }
00278
00279 user_handler_(error, rc);
00280 return 0;
00281 }
00282
00283
00284 int do_async_write(bool is_operation_done, int rc)
00285 {
00286 int len = ::BIO_ctrl_pending( ssl_bio_ );
00287 if ( len )
00288 {
00289
00290 len = (int)send_buf_.get_unused_len() > len?
00291 len:
00292 send_buf_.get_unused_len();
00293
00294 if (len == 0)
00295 {
00296
00297
00298 return 0;
00299 }
00300
00301
00302 len = ::BIO_read( ssl_bio_, send_buf_.get_unused_start(), len);
00303
00304 if (len > 0)
00305 {
00306 unsigned char *data_start = send_buf_.get_unused_start();
00307 send_buf_.data_added(len);
00308
00309 BOOST_ASSERT(strand_);
00310 asio::async_write
00311 (
00312 socket_,
00313 asio::buffer(data_start, len),
00314 strand_->wrap
00315 (
00316 boost::bind
00317 (
00318 &openssl_operation::async_write_handler,
00319 this,
00320 is_operation_done,
00321 rc,
00322 asio::placeholders::error,
00323 asio::placeholders::bytes_transferred
00324 )
00325 )
00326 );
00327
00328 return 0;
00329 }
00330 else if (!BIO_should_retry(ssl_bio_))
00331 {
00332
00333
00334 handler_(asio::error::no_recovery, 0);
00335 return 0;
00336 }
00337 }
00338
00339 if (is_operation_done)
00340 {
00341
00342 handler_(asio::error_code(), rc);
00343 return 0;
00344 }
00345
00346
00347
00348 start();
00349
00350 return 0;
00351 }
00352
00353 void async_write_handler(bool is_operation_done, int rc,
00354 const asio::error_code& error, size_t bytes_sent)
00355 {
00356 if (!error)
00357 {
00358
00359 send_buf_.data_removed(bytes_sent);
00360
00361 if (is_operation_done)
00362 handler_(asio::error_code(), rc);
00363 else
00364
00365 start();
00366 }
00367 else
00368 handler_(error, rc);
00369 }
00370
00371 int do_async_read()
00372 {
00373
00374 BOOST_ASSERT(strand_);
00375 socket_.async_read_some
00376 (
00377 asio::buffer(recv_buf_.get_unused_start(),
00378 recv_buf_.get_unused_len()),
00379 strand_->wrap
00380 (
00381 boost::bind
00382 (
00383 &openssl_operation::async_read_handler,
00384 this,
00385 asio::placeholders::error,
00386 asio::placeholders::bytes_transferred
00387 )
00388 )
00389 );
00390 return 0;
00391 }
00392
00393 void async_read_handler(const asio::error_code& error,
00394 size_t bytes_recvd)
00395 {
00396 if (!error)
00397 {
00398 recv_buf_.data_added(bytes_recvd);
00399
00400
00401 int written = ::BIO_write
00402 (
00403 ssl_bio_,
00404 recv_buf_.get_data_start(),
00405 recv_buf_.get_data_len()
00406 );
00407
00408 if (written > 0)
00409 {
00410 recv_buf_.data_removed(written);
00411 }
00412 else if (written < 0)
00413 {
00414 if (!BIO_should_retry(ssl_bio_))
00415 {
00416
00417 handler_(asio::error::no_recovery, 0);
00418 return;
00419 }
00420 }
00421
00422
00423 start();
00424 }
00425 else
00426 {
00427
00428
00429 handler_(error, 0);
00430 }
00431 }
00432
00433
00434 int do_sync_write(bool is_operation_done, int rc)
00435 {
00436 int len = ::BIO_ctrl_pending( ssl_bio_ );
00437 if ( len )
00438 {
00439
00440 len = (int)send_buf_.get_unused_len() > len?
00441 len:
00442 send_buf_.get_unused_len();
00443
00444
00445 len = ::BIO_read( ssl_bio_, send_buf_.get_unused_start(), len);
00446
00447 if (len > 0)
00448 {
00449 size_t sent_len = asio::write(
00450 socket_,
00451 asio::buffer(send_buf_.get_unused_start(), len)
00452 );
00453
00454 send_buf_.data_added(len);
00455 send_buf_.data_removed(sent_len);
00456 }
00457 else if (!BIO_should_retry(ssl_bio_))
00458 {
00459
00460
00461 throw asio::system_error(asio::error::no_recovery);
00462 }
00463 }
00464
00465 if (is_operation_done)
00466
00467 return rc;
00468
00469
00470 return start();
00471 }
00472
00473 int do_sync_read()
00474 {
00475 size_t len = socket_.read_some
00476 (
00477 asio::buffer(recv_buf_.get_unused_start(),
00478 recv_buf_.get_unused_len())
00479 );
00480
00481
00482 recv_buf_.data_added(len);
00483
00484
00485 int written = ::BIO_write
00486 (
00487 ssl_bio_,
00488 recv_buf_.get_data_start(),
00489 recv_buf_.get_data_len()
00490 );
00491
00492 if (written > 0)
00493 {
00494 recv_buf_.data_removed(written);
00495 }
00496 else if (written < 0)
00497 {
00498 if (!BIO_should_retry(ssl_bio_))
00499 {
00500
00501 throw asio::system_error(asio::error::no_recovery);
00502 }
00503 }
00504
00505
00506 return start();
00507 }
00508 };
00509
00510 }
00511 }
00512 }
00513
00514 #include "asio/detail/pop_options.hpp"
00515
00516 #endif // ASIO_SSL_DETAIL_OPENSSL_OPERATION_HPP