openssl_stream_service.hpp 14 KB

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