openssl_stream_service.hpp 15 KB

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