$search
00001 // 00002 // openssl_operation.hpp 00003 // ~~~~~~~~~~~~~~~~~~~~~ 00004 // 00005 // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com 00006 // 00007 // Distributed under the Boost Software License, Version 1.0. (See accompanying 00008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 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 // Network send_/recv buffer implementation 00041 // 00042 // 00043 class net_buffer 00044 { 00045 static const int NET_BUF_SIZE = 16*1024 + 256; // SSL record size + spare 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 }; // class net_buffer 00075 00076 // 00077 // Operation class 00078 // 00079 // 00080 template <typename Stream> 00081 class openssl_operation 00082 { 00083 public: 00084 00085 // Constructor for asynchronous operations 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 // Constructor for synchronous operations 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 // Start operation 00144 // In case of asynchronous it returns 0, in sync mode returns success code 00145 // or throws an error... 00146 int start() 00147 { 00148 int rc = primitive_( session_ ); 00149 00150 bool is_operation_done = (rc > 0); 00151 // For connect/accept/shutdown, the operation 00152 // is done, when return code is 1 00153 // for write, it is done, when is retcode > 0 00154 // for read, is is done when retcode > 0 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 // SSL connection is shut down cleanly 00173 return handler_(asio::error_code(), 1); 00174 00175 if (is_shut_down_received && !is_operation_done) 00176 // Shutdown has been requested, while we were reading or writing... 00177 // abort our action... 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 // The operation has failed... It is not completed and does 00184 // not want network communication nor does want to send shutdown out... 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 // We may have left over data that we can pass to SSL immediately 00200 if (recv_buf_.get_data_len() > 0) 00201 { 00202 // Pass the buffered data to SSL 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 // Some serios error with BIO.... 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 // Continue with operation, flush any SSL data out to network... 00232 return write_(is_operation_done, rc); 00233 } 00234 00235 // Private implementation 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_; // buffers for network IO 00250 00251 // The recv buffer is owned by the stream, not the operation, since there can 00252 // be left over bytes after passing the data up to the application, and these 00253 // bytes need to be kept around for the next read operation issued by the 00254 // application. 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 // Writes bytes asynchronously from SSL to NET 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 // There is something to write into net, do it... 00290 len = (int)send_buf_.get_unused_len() > len? 00291 len: 00292 send_buf_.get_unused_len(); 00293 00294 if (len == 0) 00295 { 00296 // In case our send buffer is full, we have just to wait until 00297 // previous send to complete... 00298 return 0; 00299 } 00300 00301 // Read outgoing data from bio 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 // Seems like fatal error 00333 // reading from SSL BIO has failed... 00334 handler_(asio::error::no_recovery, 0); 00335 return 0; 00336 } 00337 } 00338 00339 if (is_operation_done) 00340 { 00341 // Finish the operation, with success 00342 handler_(asio::error_code(), rc); 00343 return 0; 00344 } 00345 00346 // OPeration is not done and writing to net has been made... 00347 // start operation again 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 // Remove data from send buffer 00359 send_buf_.data_removed(bytes_sent); 00360 00361 if (is_operation_done) 00362 handler_(asio::error_code(), rc); 00363 else 00364 // Since the operation was not completed, try it again... 00365 start(); 00366 } 00367 else 00368 handler_(error, rc); 00369 } 00370 00371 int do_async_read() 00372 { 00373 // Wait for new data 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 // Pass the received data to SSL 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 // Some serios error with BIO.... 00417 handler_(asio::error::no_recovery, 0); 00418 return; 00419 } 00420 } 00421 00422 // and try the SSL primitive again 00423 start(); 00424 } 00425 else 00426 { 00427 // Error in network level... 00428 // SSL can't continue either... 00429 handler_(error, 0); 00430 } 00431 } 00432 00433 // Syncronous functions... 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 // There is something to write into net, do it... 00440 len = (int)send_buf_.get_unused_len() > len? 00441 len: 00442 send_buf_.get_unused_len(); 00443 00444 // Read outgoing data from bio 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 // Seems like fatal error 00460 // reading from SSL BIO has failed... 00461 throw asio::system_error(asio::error::no_recovery); 00462 } 00463 } 00464 00465 if (is_operation_done) 00466 // Finish the operation, with success 00467 return rc; 00468 00469 // Operation is not finished, start again. 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 // Write data to ssl 00482 recv_buf_.data_added(len); 00483 00484 // Pass the received data to SSL 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 // Some serios error with BIO.... 00501 throw asio::system_error(asio::error::no_recovery); 00502 } 00503 } 00504 00505 // Try the operation again 00506 return start(); 00507 } 00508 }; // class openssl_operation 00509 00510 } // namespace detail 00511 } // namespace ssl 00512 } // namespace asio 00513 00514 #include "asio/detail/pop_options.hpp" 00515 00516 #endif // ASIO_SSL_DETAIL_OPENSSL_OPERATION_HPP