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