PageRenderTime 45ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

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

http://openqwaq.googlecode.com/
C++ Header | 531 lines | 432 code | 69 blank | 30 comment | 9 complexity | 55693acd9bece0e3c60e86a47cdbc9de MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, LGPL-2.0, BSD-3-Clause
  1. //
  2. // stream_service.hpp
  3. // ~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
  6. // Copyright (c) 2005-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
  7. //
  8. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  9. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  10. //
  11. #ifndef ASIO_SSL_DETAIL_OPENSSL_STREAM_SERVICE_HPP
  12. #define ASIO_SSL_DETAIL_OPENSSL_STREAM_SERVICE_HPP
  13. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  14. # pragma once
  15. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  16. #include "asio/detail/push_options.hpp"
  17. #include "asio/detail/push_options.hpp"
  18. #include <cstddef>
  19. #include <climits>
  20. #include <boost/config.hpp>
  21. #include <boost/noncopyable.hpp>
  22. #include <boost/function.hpp>
  23. #include <boost/bind.hpp>
  24. #include "asio/detail/pop_options.hpp"
  25. #include "asio/error.hpp"
  26. #include "asio/io_service.hpp"
  27. #include "asio/strand.hpp"
  28. #include "asio/detail/service_base.hpp"
  29. #include "asio/ssl/basic_context.hpp"
  30. #include "asio/ssl/stream_base.hpp"
  31. #include "asio/ssl/detail/openssl_operation.hpp"
  32. #include "asio/ssl/detail/openssl_types.hpp"
  33. namespace asio {
  34. namespace ssl {
  35. namespace detail {
  36. class openssl_stream_service
  37. : public asio::detail::service_base<openssl_stream_service>
  38. {
  39. private:
  40. enum { max_buffer_size = INT_MAX };
  41. //Base handler for asyncrhonous operations
  42. template <typename Stream>
  43. class base_handler
  44. {
  45. public:
  46. typedef boost::function<
  47. void (const asio::error_code&, size_t)> func_t;
  48. base_handler(asio::io_service& io_service)
  49. : op_(NULL)
  50. , io_service_(io_service)
  51. , work_(io_service)
  52. {}
  53. void do_func(const asio::error_code& error, size_t size)
  54. {
  55. func_(error, size);
  56. }
  57. void set_operation(openssl_operation<Stream>* op) { op_ = op; }
  58. void set_func(func_t func) { func_ = func; }
  59. ~base_handler()
  60. {
  61. delete op_;
  62. }
  63. private:
  64. func_t func_;
  65. openssl_operation<Stream>* op_;
  66. asio::io_service& io_service_;
  67. asio::io_service::work work_;
  68. }; // class base_handler
  69. // Handler for asynchronous IO (write/read) operations
  70. template<typename Stream, typename Handler>
  71. class io_handler
  72. : public base_handler<Stream>
  73. {
  74. public:
  75. io_handler(Handler handler, asio::io_service& io_service)
  76. : base_handler<Stream>(io_service)
  77. , handler_(handler)
  78. {
  79. set_func(boost::bind(
  80. &io_handler<Stream, Handler>::handler_impl,
  81. this, boost::arg<1>(), boost::arg<2>() ));
  82. }
  83. private:
  84. Handler handler_;
  85. void handler_impl(const asio::error_code& error, size_t size)
  86. {
  87. handler_(error, size);
  88. delete this;
  89. }
  90. }; // class io_handler
  91. // Handler for asyncrhonous handshake (connect, accept) functions
  92. template <typename Stream, typename Handler>
  93. class handshake_handler
  94. : public base_handler<Stream>
  95. {
  96. public:
  97. handshake_handler(Handler handler, asio::io_service& io_service)
  98. : base_handler<Stream>(io_service)
  99. , handler_(handler)
  100. {
  101. set_func(boost::bind(
  102. &handshake_handler<Stream, Handler>::handler_impl,
  103. this, boost::arg<1>(), boost::arg<2>() ));
  104. }
  105. private:
  106. Handler handler_;
  107. void handler_impl(const asio::error_code& error, size_t)
  108. {
  109. handler_(error);
  110. delete this;
  111. }
  112. }; // class handshake_handler
  113. // Handler for asyncrhonous shutdown
  114. template <typename Stream, typename Handler>
  115. class shutdown_handler
  116. : public base_handler<Stream>
  117. {
  118. public:
  119. shutdown_handler(Handler handler, asio::io_service& io_service)
  120. : base_handler<Stream>(io_service),
  121. handler_(handler)
  122. {
  123. set_func(boost::bind(
  124. &shutdown_handler<Stream, Handler>::handler_impl,
  125. this, boost::arg<1>(), boost::arg<2>() ));
  126. }
  127. private:
  128. Handler handler_;
  129. void handler_impl(const asio::error_code& error, size_t)
  130. {
  131. handler_(error);
  132. delete this;
  133. }
  134. }; // class shutdown_handler
  135. public:
  136. // The implementation type.
  137. typedef struct impl_struct
  138. {
  139. ::SSL* ssl;
  140. ::BIO* ext_bio;
  141. net_buffer recv_buf;
  142. } * impl_type;
  143. // Construct a new stream socket service for the specified io_service.
  144. explicit openssl_stream_service(asio::io_service& io_service)
  145. : asio::detail::service_base<openssl_stream_service>(io_service),
  146. strand_(io_service)
  147. {
  148. }
  149. // Destroy all user-defined handler objects owned by the service.
  150. void shutdown_service()
  151. {
  152. }
  153. // Return a null stream implementation.
  154. impl_type null() const
  155. {
  156. return 0;
  157. }
  158. // Create a new stream implementation.
  159. template <typename Stream, typename Context_Service>
  160. void create(impl_type& impl, Stream& next_layer,
  161. basic_context<Context_Service>& context)
  162. {
  163. impl = new impl_struct;
  164. impl->ssl = ::SSL_new(context.impl());
  165. ::SSL_set_mode(impl->ssl, SSL_MODE_ENABLE_PARTIAL_WRITE);
  166. ::SSL_set_mode(impl->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
  167. ::BIO* int_bio = 0;
  168. impl->ext_bio = 0;
  169. ::BIO_new_bio_pair(&int_bio, 8192, &impl->ext_bio, 8192);
  170. ::SSL_set_bio(impl->ssl, int_bio, int_bio);
  171. }
  172. // Destroy a stream implementation.
  173. template <typename Stream>
  174. void destroy(impl_type& impl, Stream& next_layer)
  175. {
  176. if (impl != 0)
  177. {
  178. ::BIO_free(impl->ext_bio);
  179. ::SSL_free(impl->ssl);
  180. delete impl;
  181. impl = 0;
  182. }
  183. }
  184. // Perform SSL handshaking.
  185. template <typename Stream>
  186. asio::error_code handshake(impl_type& impl, Stream& next_layer,
  187. stream_base::handshake_type type, asio::error_code& ec)
  188. {
  189. try
  190. {
  191. openssl_operation<Stream> op(
  192. type == stream_base::client ?
  193. &ssl_wrap<mutex_type>::SSL_connect:
  194. &ssl_wrap<mutex_type>::SSL_accept,
  195. next_layer,
  196. impl->recv_buf,
  197. impl->ssl,
  198. impl->ext_bio);
  199. op.start();
  200. }
  201. catch (asio::system_error& e)
  202. {
  203. ec = e.code();
  204. return ec;
  205. }
  206. ec = asio::error_code();
  207. return ec;
  208. }
  209. // Start an asynchronous SSL handshake.
  210. template <typename Stream, typename Handler>
  211. void async_handshake(impl_type& impl, Stream& next_layer,
  212. stream_base::handshake_type type, Handler handler)
  213. {
  214. typedef handshake_handler<Stream, Handler> connect_handler;
  215. connect_handler* local_handler =
  216. new connect_handler(handler, get_io_service());
  217. openssl_operation<Stream>* op = new openssl_operation<Stream>
  218. (
  219. type == stream_base::client ?
  220. &ssl_wrap<mutex_type>::SSL_connect:
  221. &ssl_wrap<mutex_type>::SSL_accept,
  222. next_layer,
  223. impl->recv_buf,
  224. impl->ssl,
  225. impl->ext_bio,
  226. boost::bind
  227. (
  228. &base_handler<Stream>::do_func,
  229. local_handler,
  230. boost::arg<1>(),
  231. boost::arg<2>()
  232. ),
  233. strand_
  234. );
  235. local_handler->set_operation(op);
  236. strand_.post(boost::bind(&openssl_operation<Stream>::start, op));
  237. }
  238. // Shut down SSL on the stream.
  239. template <typename Stream>
  240. asio::error_code shutdown(impl_type& impl, Stream& next_layer,
  241. asio::error_code& ec)
  242. {
  243. try
  244. {
  245. openssl_operation<Stream> op(
  246. &ssl_wrap<mutex_type>::SSL_shutdown,
  247. next_layer,
  248. impl->recv_buf,
  249. impl->ssl,
  250. impl->ext_bio);
  251. op.start();
  252. }
  253. catch (asio::system_error& e)
  254. {
  255. ec = e.code();
  256. return ec;
  257. }
  258. ec = asio::error_code();
  259. return ec;
  260. }
  261. // Asynchronously shut down SSL on the stream.
  262. template <typename Stream, typename Handler>
  263. void async_shutdown(impl_type& impl, Stream& next_layer, Handler handler)
  264. {
  265. typedef shutdown_handler<Stream, Handler> disconnect_handler;
  266. disconnect_handler* local_handler =
  267. new disconnect_handler(handler, get_io_service());
  268. openssl_operation<Stream>* op = new openssl_operation<Stream>
  269. (
  270. &ssl_wrap<mutex_type>::SSL_shutdown,
  271. next_layer,
  272. impl->recv_buf,
  273. impl->ssl,
  274. impl->ext_bio,
  275. boost::bind
  276. (
  277. &base_handler<Stream>::do_func,
  278. local_handler,
  279. boost::arg<1>(),
  280. boost::arg<2>()
  281. ),
  282. strand_
  283. );
  284. local_handler->set_operation(op);
  285. strand_.post(boost::bind(&openssl_operation<Stream>::start, op));
  286. }
  287. // Write some data to the stream.
  288. template <typename Stream, typename Const_Buffers>
  289. std::size_t write_some(impl_type& impl, Stream& next_layer,
  290. const Const_Buffers& buffers, asio::error_code& ec)
  291. {
  292. size_t bytes_transferred = 0;
  293. try
  294. {
  295. std::size_t buffer_size = asio::buffer_size(*buffers.begin());
  296. if (buffer_size > max_buffer_size)
  297. buffer_size = max_buffer_size;
  298. boost::function<int (SSL*)> send_func =
  299. boost::bind(&::SSL_write, boost::arg<1>(),
  300. asio::buffer_cast<const void*>(*buffers.begin()),
  301. static_cast<int>(buffer_size));
  302. openssl_operation<Stream> op(
  303. send_func,
  304. next_layer,
  305. impl->recv_buf,
  306. impl->ssl,
  307. impl->ext_bio
  308. );
  309. bytes_transferred = static_cast<size_t>(op.start());
  310. }
  311. catch (asio::system_error& e)
  312. {
  313. ec = e.code();
  314. return 0;
  315. }
  316. ec = asio::error_code();
  317. return bytes_transferred;
  318. }
  319. // Start an asynchronous write.
  320. template <typename Stream, typename Const_Buffers, typename Handler>
  321. void async_write_some(impl_type& impl, Stream& next_layer,
  322. const Const_Buffers& buffers, Handler handler)
  323. {
  324. typedef io_handler<Stream, Handler> send_handler;
  325. send_handler* local_handler = new send_handler(handler, get_io_service());
  326. std::size_t buffer_size = asio::buffer_size(*buffers.begin());
  327. if (buffer_size > max_buffer_size)
  328. buffer_size = max_buffer_size;
  329. boost::function<int (SSL*)> send_func =
  330. boost::bind(&::SSL_write, boost::arg<1>(),
  331. asio::buffer_cast<const void*>(*buffers.begin()),
  332. static_cast<int>(buffer_size));
  333. openssl_operation<Stream>* op = new openssl_operation<Stream>
  334. (
  335. send_func,
  336. next_layer,
  337. impl->recv_buf,
  338. impl->ssl,
  339. impl->ext_bio,
  340. boost::bind
  341. (
  342. &base_handler<Stream>::do_func,
  343. local_handler,
  344. boost::arg<1>(),
  345. boost::arg<2>()
  346. ),
  347. strand_
  348. );
  349. local_handler->set_operation(op);
  350. strand_.post(boost::bind(&openssl_operation<Stream>::start, op));
  351. }
  352. // Read some data from the stream.
  353. template <typename Stream, typename Mutable_Buffers>
  354. std::size_t read_some(impl_type& impl, Stream& next_layer,
  355. const Mutable_Buffers& buffers, asio::error_code& ec)
  356. {
  357. size_t bytes_transferred = 0;
  358. try
  359. {
  360. std::size_t buffer_size = asio::buffer_size(*buffers.begin());
  361. if (buffer_size > max_buffer_size)
  362. buffer_size = max_buffer_size;
  363. boost::function<int (SSL*)> recv_func =
  364. boost::bind(&::SSL_read, boost::arg<1>(),
  365. asio::buffer_cast<void*>(*buffers.begin()),
  366. static_cast<int>(buffer_size));
  367. openssl_operation<Stream> op(recv_func,
  368. next_layer,
  369. impl->recv_buf,
  370. impl->ssl,
  371. impl->ext_bio
  372. );
  373. bytes_transferred = static_cast<size_t>(op.start());
  374. }
  375. catch (asio::system_error& e)
  376. {
  377. ec = e.code();
  378. return 0;
  379. }
  380. ec = asio::error_code();
  381. return bytes_transferred;
  382. }
  383. // Start an asynchronous read.
  384. template <typename Stream, typename Mutable_Buffers, typename Handler>
  385. void async_read_some(impl_type& impl, Stream& next_layer,
  386. const Mutable_Buffers& buffers, Handler handler)
  387. {
  388. typedef io_handler<Stream, Handler> recv_handler;
  389. recv_handler* local_handler = new recv_handler(handler, get_io_service());
  390. std::size_t buffer_size = asio::buffer_size(*buffers.begin());
  391. if (buffer_size > max_buffer_size)
  392. buffer_size = max_buffer_size;
  393. boost::function<int (SSL*)> recv_func =
  394. boost::bind(&::SSL_read, boost::arg<1>(),
  395. asio::buffer_cast<void*>(*buffers.begin()),
  396. static_cast<int>(buffer_size));
  397. openssl_operation<Stream>* op = new openssl_operation<Stream>
  398. (
  399. recv_func,
  400. next_layer,
  401. impl->recv_buf,
  402. impl->ssl,
  403. impl->ext_bio,
  404. boost::bind
  405. (
  406. &base_handler<Stream>::do_func,
  407. local_handler,
  408. boost::arg<1>(),
  409. boost::arg<2>()
  410. ),
  411. strand_
  412. );
  413. local_handler->set_operation(op);
  414. strand_.post(boost::bind(&openssl_operation<Stream>::start, op));
  415. }
  416. // Peek at the incoming data on the stream.
  417. template <typename Stream, typename Mutable_Buffers>
  418. std::size_t peek(impl_type& impl, Stream& next_layer,
  419. const Mutable_Buffers& buffers, asio::error_code& ec)
  420. {
  421. ec = asio::error_code();
  422. return 0;
  423. }
  424. // Determine the amount of data that may be read without blocking.
  425. template <typename Stream>
  426. std::size_t in_avail(impl_type& impl, Stream& next_layer,
  427. asio::error_code& ec)
  428. {
  429. ec = asio::error_code();
  430. return 0;
  431. }
  432. private:
  433. asio::io_service::strand strand_;
  434. typedef asio::detail::mutex mutex_type;
  435. template<typename Mutex>
  436. struct ssl_wrap
  437. {
  438. static Mutex ssl_mutex_;
  439. static int SSL_accept(SSL *ssl)
  440. {
  441. typename Mutex::scoped_lock lock(ssl_mutex_);
  442. return ::SSL_accept(ssl);
  443. }
  444. static int SSL_connect(SSL *ssl)
  445. {
  446. typename Mutex::scoped_lock lock(ssl_mutex_);
  447. return ::SSL_connect(ssl);
  448. }
  449. static int SSL_shutdown(SSL *ssl)
  450. {
  451. typename Mutex::scoped_lock lock(ssl_mutex_);
  452. return ::SSL_shutdown(ssl);
  453. }
  454. };
  455. };
  456. template<typename Mutex>
  457. Mutex openssl_stream_service::ssl_wrap<Mutex>::ssl_mutex_;
  458. } // namespace detail
  459. } // namespace ssl
  460. } // namespace asio
  461. #include "asio/detail/pop_options.hpp"
  462. #endif // ASIO_SSL_DETAIL_OPENSSL_STREAM_SERVICE_HPP