openssl_operation.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. //
  2. // ssl/old/detail/openssl_operation.hpp
  3. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
  6. //
  7. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. //
  10. #ifndef ASIO_SSL_OLD_DETAIL_OPENSSL_OPERATION_HPP
  11. #define ASIO_SSL_OLD_DETAIL_OPENSSL_OPERATION_HPP
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. # pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include "asio/detail/config.hpp"
  16. #include <boost/function.hpp>
  17. #include <boost/bind.hpp>
  18. #include "asio/buffer.hpp"
  19. #include "asio/detail/assert.hpp"
  20. #include "asio/detail/socket_ops.hpp"
  21. #include "asio/placeholders.hpp"
  22. #include "asio/ssl/detail/openssl_types.hpp"
  23. #include "asio/ssl/error.hpp"
  24. #include "asio/strand.hpp"
  25. #include "asio/system_error.hpp"
  26. #include "asio/write.hpp"
  27. #include "asio/detail/push_options.hpp"
  28. namespace asio {
  29. namespace ssl {
  30. namespace old {
  31. namespace detail {
  32. typedef boost::function<int (::SSL*)> ssl_primitive_func;
  33. typedef boost::function<void (const asio::error_code&, int)>
  34. user_handler_func;
  35. // Network send_/recv buffer implementation
  36. //
  37. //
  38. class net_buffer
  39. {
  40. static const int NET_BUF_SIZE = 16*1024 + 256; // SSL record size + spare
  41. unsigned char buf_[NET_BUF_SIZE];
  42. unsigned char* data_start_;
  43. unsigned char* data_end_;
  44. public:
  45. net_buffer()
  46. {
  47. data_start_ = data_end_ = buf_;
  48. }
  49. unsigned char* get_unused_start() { return data_end_; }
  50. unsigned char* get_data_start() { return data_start_; }
  51. size_t get_unused_len() { return (NET_BUF_SIZE - (data_end_ - buf_)); }
  52. size_t get_data_len() { return (data_end_ - data_start_); }
  53. void data_added(size_t count)
  54. {
  55. data_end_ += count;
  56. data_end_ = data_end_ > (buf_ + NET_BUF_SIZE)?
  57. (buf_ + NET_BUF_SIZE):
  58. data_end_;
  59. }
  60. void data_removed(size_t count)
  61. {
  62. data_start_ += count;
  63. if (data_start_ >= data_end_) reset();
  64. }
  65. void reset() { data_start_ = buf_; data_end_ = buf_; }
  66. bool has_data() { return (data_start_ < data_end_); }
  67. }; // class net_buffer
  68. //
  69. // Operation class
  70. //
  71. //
  72. template <typename Stream>
  73. class openssl_operation
  74. {
  75. public:
  76. // Constructor for asynchronous operations
  77. openssl_operation(ssl_primitive_func primitive,
  78. Stream& socket,
  79. net_buffer& recv_buf,
  80. SSL* session,
  81. BIO* ssl_bio,
  82. user_handler_func handler,
  83. asio::io_service::strand& strand
  84. )
  85. : primitive_(primitive)
  86. , user_handler_(handler)
  87. , strand_(&strand)
  88. , recv_buf_(recv_buf)
  89. , socket_(socket)
  90. , ssl_bio_(ssl_bio)
  91. , session_(session)
  92. {
  93. write_ = boost::bind(
  94. &openssl_operation::do_async_write,
  95. this, boost::arg<1>(), boost::arg<2>()
  96. );
  97. read_ = boost::bind(
  98. &openssl_operation::do_async_read,
  99. this
  100. );
  101. handler_= boost::bind(
  102. &openssl_operation::async_user_handler,
  103. this, boost::arg<1>(), boost::arg<2>()
  104. );
  105. }
  106. // Constructor for synchronous operations
  107. openssl_operation(ssl_primitive_func primitive,
  108. Stream& socket,
  109. net_buffer& recv_buf,
  110. SSL* session,
  111. BIO* ssl_bio)
  112. : primitive_(primitive)
  113. , strand_(0)
  114. , recv_buf_(recv_buf)
  115. , socket_(socket)
  116. , ssl_bio_(ssl_bio)
  117. , session_(session)
  118. {
  119. write_ = boost::bind(
  120. &openssl_operation::do_sync_write,
  121. this, boost::arg<1>(), boost::arg<2>()
  122. );
  123. read_ = boost::bind(
  124. &openssl_operation::do_sync_read,
  125. this
  126. );
  127. handler_ = boost::bind(
  128. &openssl_operation::sync_user_handler,
  129. this, boost::arg<1>(), boost::arg<2>()
  130. );
  131. }
  132. // Start operation
  133. // In case of asynchronous it returns 0, in sync mode returns success code
  134. // or throws an error...
  135. int start()
  136. {
  137. int rc = primitive_( session_ );
  138. bool is_operation_done = (rc > 0);
  139. // For connect/accept/shutdown, the operation
  140. // is done, when return code is 1
  141. // for write, it is done, when is retcode > 0
  142. // for read, it is done when retcode > 0
  143. int error_code = !is_operation_done ?
  144. ::SSL_get_error( session_, rc ) :
  145. 0;
  146. int sys_error_code = ERR_get_error();
  147. if (error_code == SSL_ERROR_SSL)
  148. return handler_(asio::error_code(
  149. sys_error_code, asio::error::get_ssl_category()), rc);
  150. bool is_read_needed = (error_code == SSL_ERROR_WANT_READ);
  151. bool is_write_needed = (error_code == SSL_ERROR_WANT_WRITE ||
  152. ::BIO_ctrl_pending( ssl_bio_ ));
  153. bool is_shut_down_received =
  154. ((::SSL_get_shutdown( session_ ) & SSL_RECEIVED_SHUTDOWN) ==
  155. SSL_RECEIVED_SHUTDOWN);
  156. bool is_shut_down_sent =
  157. ((::SSL_get_shutdown( session_ ) & SSL_SENT_SHUTDOWN) ==
  158. SSL_SENT_SHUTDOWN);
  159. if (is_shut_down_sent && is_shut_down_received
  160. && is_operation_done && !is_write_needed)
  161. // SSL connection is shut down cleanly
  162. return handler_(asio::error_code(), 1);
  163. if (is_shut_down_received && !is_operation_done)
  164. // Shutdown has been requested, while we were reading or writing...
  165. // abort our action...
  166. return handler_(asio::error::shut_down, 0);
  167. if (!is_operation_done && !is_read_needed && !is_write_needed
  168. && !is_shut_down_sent)
  169. {
  170. // The operation has failed... It is not completed and does
  171. // not want network communication nor does want to send shutdown out...
  172. if (error_code == SSL_ERROR_SYSCALL)
  173. {
  174. return handler_(asio::error_code(
  175. sys_error_code, asio::error::system_category), rc);
  176. }
  177. else
  178. {
  179. return handler_(asio::error_code(
  180. sys_error_code, asio::error::get_ssl_category()), rc);
  181. }
  182. }
  183. if (!is_operation_done && !is_write_needed)
  184. {
  185. // We may have left over data that we can pass to SSL immediately
  186. if (recv_buf_.get_data_len() > 0)
  187. {
  188. // Pass the buffered data to SSL
  189. int written = ::BIO_write
  190. (
  191. ssl_bio_,
  192. recv_buf_.get_data_start(),
  193. recv_buf_.get_data_len()
  194. );
  195. if (written > 0)
  196. {
  197. recv_buf_.data_removed(written);
  198. }
  199. else if (written < 0)
  200. {
  201. if (!BIO_should_retry(ssl_bio_))
  202. {
  203. // Some serios error with BIO....
  204. return handler_(asio::error::no_recovery, 0);
  205. }
  206. }
  207. return start();
  208. }
  209. else if (is_read_needed || (is_shut_down_sent && !is_shut_down_received))
  210. {
  211. return read_();
  212. }
  213. }
  214. // Continue with operation, flush any SSL data out to network...
  215. return write_(is_operation_done, rc);
  216. }
  217. // Private implementation
  218. private:
  219. typedef boost::function<int (const asio::error_code&, int)>
  220. int_handler_func;
  221. typedef boost::function<int (bool, int)> write_func;
  222. typedef boost::function<int ()> read_func;
  223. ssl_primitive_func primitive_;
  224. user_handler_func user_handler_;
  225. asio::io_service::strand* strand_;
  226. write_func write_;
  227. read_func read_;
  228. int_handler_func handler_;
  229. net_buffer send_buf_; // buffers for network IO
  230. // The recv buffer is owned by the stream, not the operation, since there can
  231. // be left over bytes after passing the data up to the application, and these
  232. // bytes need to be kept around for the next read operation issued by the
  233. // application.
  234. net_buffer& recv_buf_;
  235. Stream& socket_;
  236. BIO* ssl_bio_;
  237. SSL* session_;
  238. //
  239. int sync_user_handler(const asio::error_code& error, int rc)
  240. {
  241. if (!error)
  242. return rc;
  243. throw asio::system_error(error);
  244. }
  245. int async_user_handler(asio::error_code error, int rc)
  246. {
  247. if (rc < 0)
  248. {
  249. if (!error)
  250. error = asio::error::no_recovery;
  251. rc = 0;
  252. }
  253. user_handler_(error, rc);
  254. return 0;
  255. }
  256. // Writes bytes asynchronously from SSL to NET
  257. int do_async_write(bool is_operation_done, int rc)
  258. {
  259. int len = ::BIO_ctrl_pending( ssl_bio_ );
  260. if ( len )
  261. {
  262. // There is something to write into net, do it...
  263. len = (int)send_buf_.get_unused_len() > len?
  264. len:
  265. send_buf_.get_unused_len();
  266. if (len == 0)
  267. {
  268. // In case our send buffer is full, we have just to wait until
  269. // previous send to complete...
  270. return 0;
  271. }
  272. // Read outgoing data from bio
  273. len = ::BIO_read( ssl_bio_, send_buf_.get_unused_start(), len);
  274. if (len > 0)
  275. {
  276. unsigned char *data_start = send_buf_.get_unused_start();
  277. send_buf_.data_added(len);
  278. ASIO_ASSERT(strand_);
  279. asio::async_write
  280. (
  281. socket_,
  282. asio::buffer(data_start, len),
  283. strand_->wrap
  284. (
  285. boost::bind
  286. (
  287. &openssl_operation::async_write_handler,
  288. this,
  289. is_operation_done,
  290. rc,
  291. asio::placeholders::error,
  292. asio::placeholders::bytes_transferred
  293. )
  294. )
  295. );
  296. return 0;
  297. }
  298. else if (!BIO_should_retry(ssl_bio_))
  299. {
  300. // Seems like fatal error
  301. // reading from SSL BIO has failed...
  302. handler_(asio::error::no_recovery, 0);
  303. return 0;
  304. }
  305. }
  306. if (is_operation_done)
  307. {
  308. // Finish the operation, with success
  309. handler_(asio::error_code(), rc);
  310. return 0;
  311. }
  312. // OPeration is not done and writing to net has been made...
  313. // start operation again
  314. start();
  315. return 0;
  316. }
  317. void async_write_handler(bool is_operation_done, int rc,
  318. const asio::error_code& error, size_t bytes_sent)
  319. {
  320. if (!error)
  321. {
  322. // Remove data from send buffer
  323. send_buf_.data_removed(bytes_sent);
  324. if (is_operation_done)
  325. handler_(asio::error_code(), rc);
  326. else
  327. // Since the operation was not completed, try it again...
  328. start();
  329. }
  330. else
  331. handler_(error, rc);
  332. }
  333. int do_async_read()
  334. {
  335. // Wait for new data
  336. ASIO_ASSERT(strand_);
  337. socket_.async_read_some
  338. (
  339. asio::buffer(recv_buf_.get_unused_start(),
  340. recv_buf_.get_unused_len()),
  341. strand_->wrap
  342. (
  343. boost::bind
  344. (
  345. &openssl_operation::async_read_handler,
  346. this,
  347. asio::placeholders::error,
  348. asio::placeholders::bytes_transferred
  349. )
  350. )
  351. );
  352. return 0;
  353. }
  354. void async_read_handler(const asio::error_code& error,
  355. size_t bytes_recvd)
  356. {
  357. if (!error)
  358. {
  359. recv_buf_.data_added(bytes_recvd);
  360. // Pass the received data to SSL
  361. int written = ::BIO_write
  362. (
  363. ssl_bio_,
  364. recv_buf_.get_data_start(),
  365. recv_buf_.get_data_len()
  366. );
  367. if (written > 0)
  368. {
  369. recv_buf_.data_removed(written);
  370. }
  371. else if (written < 0)
  372. {
  373. if (!BIO_should_retry(ssl_bio_))
  374. {
  375. // Some serios error with BIO....
  376. handler_(asio::error::no_recovery, 0);
  377. return;
  378. }
  379. }
  380. // and try the SSL primitive again
  381. start();
  382. }
  383. else
  384. {
  385. // Error in network level...
  386. // SSL can't continue either...
  387. handler_(error, 0);
  388. }
  389. }
  390. // Syncronous functions...
  391. int do_sync_write(bool is_operation_done, int rc)
  392. {
  393. int len = ::BIO_ctrl_pending( ssl_bio_ );
  394. if ( len )
  395. {
  396. // There is something to write into net, do it...
  397. len = (int)send_buf_.get_unused_len() > len?
  398. len:
  399. send_buf_.get_unused_len();
  400. // Read outgoing data from bio
  401. len = ::BIO_read( ssl_bio_, send_buf_.get_unused_start(), len);
  402. if (len > 0)
  403. {
  404. size_t sent_len = asio::write(
  405. socket_,
  406. asio::buffer(send_buf_.get_unused_start(), len)
  407. );
  408. send_buf_.data_added(len);
  409. send_buf_.data_removed(sent_len);
  410. }
  411. else if (!BIO_should_retry(ssl_bio_))
  412. {
  413. // Seems like fatal error
  414. // reading from SSL BIO has failed...
  415. throw asio::system_error(asio::error::no_recovery);
  416. }
  417. }
  418. if (is_operation_done)
  419. // Finish the operation, with success
  420. return rc;
  421. // Operation is not finished, start again.
  422. return start();
  423. }
  424. int do_sync_read()
  425. {
  426. size_t len = socket_.read_some
  427. (
  428. asio::buffer(recv_buf_.get_unused_start(),
  429. recv_buf_.get_unused_len())
  430. );
  431. // Write data to ssl
  432. recv_buf_.data_added(len);
  433. // Pass the received data to SSL
  434. int written = ::BIO_write
  435. (
  436. ssl_bio_,
  437. recv_buf_.get_data_start(),
  438. recv_buf_.get_data_len()
  439. );
  440. if (written > 0)
  441. {
  442. recv_buf_.data_removed(written);
  443. }
  444. else if (written < 0)
  445. {
  446. if (!BIO_should_retry(ssl_bio_))
  447. {
  448. // Some serios error with BIO....
  449. throw asio::system_error(asio::error::no_recovery);
  450. }
  451. }
  452. // Try the operation again
  453. return start();
  454. }
  455. }; // class openssl_operation
  456. } // namespace detail
  457. } // namespace old
  458. } // namespace ssl
  459. } // namespace asio
  460. #include "asio/detail/pop_options.hpp"
  461. #endif // ASIO_SSL_OLD_DETAIL_OPENSSL_OPERATION_HPP