PageRenderTime 50ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/qwaqvm/platforms/Cross/third-party/resiprocate-src-1.6/contrib/asio/asio/ssl/detail/openssl_operation.hpp

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