openssl_init.hpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. //
  2. // openssl_init.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_INIT_HPP
  12. #define BOOST_ASIO_SSL_DETAIL_OPENSSL_INIT_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 <cstring>
  19. #include <vector>
  20. #include <boost/assert.hpp>
  21. #include <boost/config.hpp>
  22. #include <boost/shared_ptr.hpp>
  23. #include <boost/asio/detail/pop_options.hpp>
  24. #include <boost/asio/detail/mutex.hpp>
  25. #include <boost/asio/detail/tss_ptr.hpp>
  26. #include <boost/asio/ssl/detail/openssl_types.hpp>
  27. namespace boost {
  28. namespace asio {
  29. namespace ssl {
  30. namespace detail {
  31. template <bool Do_Init = true>
  32. class openssl_init
  33. : private boost::noncopyable
  34. {
  35. private:
  36. // Structure to perform the actual initialisation.
  37. class do_init
  38. {
  39. public:
  40. do_init()
  41. {
  42. if (Do_Init)
  43. {
  44. ::SSL_library_init();
  45. ::SSL_load_error_strings();
  46. ::OpenSSL_add_ssl_algorithms();
  47. mutexes_.resize(::CRYPTO_num_locks());
  48. for (size_t i = 0; i < mutexes_.size(); ++i)
  49. mutexes_[i].reset(new boost::asio::detail::mutex);
  50. ::CRYPTO_set_locking_callback(&do_init::openssl_locking_func);
  51. ::CRYPTO_set_id_callback(&do_init::openssl_id_func);
  52. }
  53. }
  54. ~do_init()
  55. {
  56. if (Do_Init)
  57. {
  58. ::CRYPTO_set_id_callback(0);
  59. ::CRYPTO_set_locking_callback(0);
  60. ::ERR_free_strings();
  61. ::ERR_remove_state(0);
  62. ::EVP_cleanup();
  63. ::CRYPTO_cleanup_all_ex_data();
  64. ::CONF_modules_unload(1);
  65. ::ENGINE_cleanup();
  66. }
  67. }
  68. // Helper function to manage a do_init singleton. The static instance of the
  69. // openssl_init object ensures that this function is always called before
  70. // main, and therefore before any other threads can get started. The do_init
  71. // instance must be static in this function to ensure that it gets
  72. // initialised before any other global objects try to use it.
  73. static boost::shared_ptr<do_init> instance()
  74. {
  75. static boost::shared_ptr<do_init> init(new do_init);
  76. return init;
  77. }
  78. private:
  79. static unsigned long openssl_id_func()
  80. {
  81. #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
  82. return ::GetCurrentThreadId();
  83. #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
  84. void* id = instance()->thread_id_;
  85. if (id == 0)
  86. instance()->thread_id_ = id = &id; // Ugh.
  87. BOOST_ASSERT(sizeof(unsigned long) >= sizeof(void*));
  88. return reinterpret_cast<unsigned long>(id);
  89. #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
  90. }
  91. static void openssl_locking_func(int mode, int n,
  92. const char* /*file*/, int /*line*/)
  93. {
  94. if (mode & CRYPTO_LOCK)
  95. instance()->mutexes_[n]->lock();
  96. else
  97. instance()->mutexes_[n]->unlock();
  98. }
  99. // Mutexes to be used in locking callbacks.
  100. std::vector<boost::shared_ptr<boost::asio::detail::mutex> > mutexes_;
  101. #if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
  102. // The thread identifiers to be used by openssl.
  103. boost::asio::detail::tss_ptr<void> thread_id_;
  104. #endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
  105. };
  106. public:
  107. // Constructor.
  108. openssl_init()
  109. : ref_(do_init::instance())
  110. {
  111. using namespace std; // For memmove.
  112. // Ensure openssl_init::instance_ is linked in.
  113. openssl_init* tmp = &instance_;
  114. memmove(&tmp, &tmp, sizeof(openssl_init*));
  115. }
  116. // Destructor.
  117. ~openssl_init()
  118. {
  119. }
  120. private:
  121. // Instance to force initialisation of openssl at global scope.
  122. static openssl_init instance_;
  123. // Reference to singleton do_init object to ensure that openssl does not get
  124. // cleaned up until the last user has finished with it.
  125. boost::shared_ptr<do_init> ref_;
  126. };
  127. template <bool Do_Init>
  128. openssl_init<Do_Init> openssl_init<Do_Init>::instance_;
  129. } // namespace detail
  130. } // namespace ssl
  131. } // namespace asio
  132. } // namespace boost
  133. #include <boost/asio/detail/pop_options.hpp>
  134. #endif // BOOST_ASIO_SSL_DETAIL_OPENSSL_INIT_HPP